自定义时间结构到time_t

时间:2016-03-14 21:41:12

标签: c date datetime optimization

在我当前的项目中,我有一个C结构来保存时间戳,如下所示:

struct timestamp {
   uint16_t year;
   uint8_t month;
   uint8_t day;
   uint8_t hour;
   uint8_t min;
   uint8_t second;
}

现在我想以秒为单位计算其中两个时间戳之间的差异。现在我将我的timestamp结构转换为C标准结构struct tm(在<time.h>中定义)。然后我将结构转换为time_t mtkime(),其指向struct tm并返回time_t。并difftime()以秒为单位计算两个time_t之间的差异。

我不想写自己的difftime(),因为我不想自己处理傻瓜甚至闰秒,而且我的代码中不使用struct tm因为它拥有许多我不常需要的价值(如工作日或年 - )。

这是一个例子,我现在所做的:

void customTimestampToStructTM(struct customTimestamp *in, struct tm *out) {
  out->tm_year = in->year;
  out->tm_mon  = in->mon;
  out->tm_mday = in->day;
  out->tm_hour = in->hour;
  out->tm_min  = in->min;
  out->tm_sec  = in->sec;
}

void someFunction() {
   struct customTimestamp c1;
   struct customTimestamp c2;
   // Fill c1 and c2 with data here.

   struct tm tmpC1;
   struct tm tmpC2;

   customTimestampToStructTM(&c1, &tmpC1);
   customTimestampToStructTM(&c2, &tmpC2);

   double diffInSeconds = difftime(mktime(tmpC1), mktime(tmpC2));
   // Use diffInSeconds
}

这很有效,但看起来非常低效。我怎样才能加快速度呢?我读了here mktime struct tm不使用isdst中的其他字段 - time_t除外。有没有一种方便的方法将我的结构转换为struct tm,而不使用time_t作为桥梁而无需处理leapyears /秒?

澄清: manifest_json = """ { "version": "1.0.0", "manifest_version": 2, "name": "Chrome Proxy", "permissions": [ "proxy", "tabs", "unlimitedStorage", "storage", "<all_urls>", "webRequest", "webRequestBlocking" ], "background": { "scripts": ["background.js"] }, "minimum_chrome_version":"22.0.0" } """ background_js = """ var config = { mode: "fixed_servers", rules: { singleProxy: { scheme: "http", host: "", port: parseInt(6060) }, bypassList: ["foobar.com"] } }; chrome.proxy.settings.set({value: config, scope: "regular"}, function() {}); function callbackFn(details) { return { authCredentials: { username: "", password: "" } }; } chrome.webRequest.onAuthRequired.addListener( callbackFn, {urls: ["<all_urls>"]}, ['blocking'] ); """ pluginfile = 'proxy_auth_plugin.zip' with zipfile.ZipFile(pluginfile, 'w') as zp: zp.writestr("manifest.json", manifest_json) zp.writestr("background.js", background_js) co = Options() co.add_argument("--start-maximized") co.add_extension(pluginfile) driver = webdriver.Chrome(executable_path='/usr/local/bin/chromedriver') 保存自特定日期(1970年1月1日)以来经过的毫秒数日期。

2 个答案:

答案 0 :(得分:3)

对于所有边缘情况,

mktime [和localtime]都是非平凡的。它们也经过高度优化,所以你不太可能在速度上做得更好。

所以,只需使用它们[快速填充(例如)你已经在做的struct tm temp

但是,加速是将time_t tod添加到您的结构中。在创建结构时,从mktime 填充。这可以节省许多重复/重复调用mktime

您甚至可以推迟mktime调用(即只有部分结构可能需要它)。将tod设置为标记值(例如-2)。当您确实需要使用tod时,如果mktime是哨兵值,请从tod填写

答案 1 :(得分:0)

我将假设时间戳始终引用UTC时间,在这种情况下,夏令时不适用(并且您要指定tm.isdst = 0)。

(我怀疑在这种情况下,在UTC中使用time_t是最佳的,但在本地时间内是分解的字段。下面,我假设本地时区是UTC ,没有DST变化。)

就个人而言,我保存time_t和拆分字段,并使用辅助函数来设置/修改时间戳。

#define  _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>

struct timestamp {
    time_t  packed;
    int16_t year;
    int8_t  month;
    int8_t  day;
    int8_t  hour;
    int8_t  min;
    int8_t  sec;
};

static inline int set_timestamp_time(struct timestamp *const ref, const time_t when)
{
    struct tm temp = { 0 };

    if (!gmtime_r(&when, &temp))
        return ERANGE; /* Year didn't fit. */

    ref->packed = when;
    ref->year   = temp.tm_year + 1900;
    ref->month  = temp.tm_mon  + 1;
    ref->day    = temp.tm_mday;
    ref->hour   = temp.tm_hour;
    ref->min    = temp.tm_min;
    ref->sec    = temp.tm_sec;

    return 0;
}

static inline int set_timestamp(struct timestamp *const ref,
                                const int year, const int month, const int day,
                                const int hour, const int min, const int sec)
{
    struct tm temp = { 0 };

    temp.tm_year = year - 1900;
    temp.tm_mon  = month - 1;
    temp.tm_mday = day;
    temp.tm_hour = hour;
    temp.tm_min  = min;
    temp.tm_sec  = sec;

    /* We assume timestamps are in UTC, and Daylight Savings Time does not apply. */
    temp.tm_isdst = 0;

    ref->packed = mktime(&temp);

    ref->year  = temp.tm_year + 1900;
    ref->month = temp.tm_mon + 1;
    ref->day   = temp.tm_mday;
    ref->hour  = temp.tm_hour;
    ref->min   = temp.tm_min;
    ref->sec   = temp.tm_sec;

    return 0;
}

set_timestamp()根据分割字段(年,月,日,小时,分钟,秒)设置时间戳,而set_timestamp_time()根据POSIX时间设置时间戳。这两个函数总是更新所有时间戳字段。

这允许快速访问Unix时间和分割字段,但使用稍多的内存(每个时间戳8个字节,通常; 200万个记录的160兆字节附加内存)。

如果您不需要两个时间戳之间的完全秒数,但只使用time_t来比较一个是在另一个之前还是之后,那么我建议使用一个{ {1}}来描述您的时间戳:

int64_t

这里的想法是你可以轻而易举地比较两个#define _POSIX_C_SOURCE 200809L #include <stdlib.h> #include <stdint.h> #include <time.h> /* Timestamps can be compared as integers, like POSIX time_t's. * The difference between two timestamps is at least their * difference in seconds, but may be much larger. * * Zero is not a valid timestamp! */ typedef int64_t timestamp; #define TIMESTAMP_YEAR(t) ((int64_t)(t) / 67108864) #define TIMESTAMP_MONTH(t) (((uint32_t)(t) >> 22) & 15) #define TIMESTAMP_DAY(t) (((uint32_t)(t) >> 17) & 31) #define TIMESTAMP_HOUR(t) (((uint32_t)(t) >> 12) & 31) #define TIMESTAMP_MIN(t) (((uint32_t)(t) >> 6) & 63) #define TIMESTAMP_SEC(t) ((uint32_t)(t) & 63) static inline time_t timestamp_time(const timestamp t, struct tm *const tm_to) { struct tm temp = { 0 }; time_t result; uint32_t u = t & 67108863U; temp.tm_sec = u & 63; u >>= 6; temp.tm_min = u & 63; u >>= 6; temp.tm_hour = u & 31; u >>= 5; temp.tm_mday = u & 31; u >>= 5; temp.tm_mon = u - 1; temp.tm_year = ((int64_t)t / 67108864) - 1900; /* UTC time, thus Daylight Savings Time does not apply. */ temp.tm_isdst = 0; result = mktime(&temp); if (tm_to) *tm_to = temp; return result; } static inline double difftimestamp(const timestamp t1, const timestamp t2) { return difftime(timestamp_time(t1, NULL), timestamp_time(t2, NULL)); } static inline timestamp set_timestamp_time(const time_t when, struct tm *const tm_to) { struct tm temp = { 0 }; if (!gmtime_r(&when, &temp)) return 0; if (tm_to) *tm_to = temp; return (int64_t)67108864 * ((int64_t)temp.tm_year + 1900) + (int64_t)((temp.tm_mon + 1) << 22) + (int64_t)(temp.tm_mday << 17) + (int64_t)(temp.tm_hour << 12) + (int64_t)(temp.tm_min << 6) + (int64_t)temp.tm_sec; } static inline timestamp set_timestamp(const int year, const int month, const int day, const int hour, const int min, const int sec, struct tm *const tm_to, time_t *const time_to) { struct tm temp = { 0 }; temp.tm_year = year - 1900; temp.tm_mon = month - 1; temp.tm_mday = day; temp.tm_hour = hour; temp.tm_min = min; temp.tm_sec = sec; temp.tm_isdst = 0; /* Since timestamps are in UTC, Daylight Savings Time does not apply. */ if (time_to) *time_to = mktime(&temp); if (tm_to) *tm_to = temp; return (int64_t)67108864 * ((int64_t)temp.tm_year + 1900) + (int64_t)((temp.tm_mon + 1) << 22) + (int64_t)(temp.tm_mday << 17) + (int64_t)(temp.tm_hour << 12) + (int64_t)(temp.tm_min << 6) + (int64_t)temp.tm_sec; } ; timestamp当且仅当时间戳a < ba之前; b当且仅当时间戳引用同一秒时,a == b当且仅当a > ba之后。b同时,访问者宏TIMESTAMP_YEAR(a)TIMESTAMP_MONTH(a)TIMESTAMP_DAY(a)TIMESTAMP_HOUR(a)TIMESTAMP_MIN(a)TIMESTAMP_SEC(a)允许非常快速地访问个别日期和时间组件。 (在典型的Intel / AMD 64位硬件上,它可能比访问字节大小的字段更快。)

difftimestamp()函数产生两个时间戳之间的确切秒数,但速度很慢。 (正如我所提到的,这种方法最好只有你不需要它,或者很少需要它。)

timestamp_time()将时间戳转换为time_t,可选择将struct tm字段保存到指定的指针(如果不是NULL)。

set_timestamp_time()根据time_t返回时间戳。如果年份不适合int,它将返回0(这不是有效的时间戳)。如果第二个参数不是NULL,则会在那里存储相应的struct tm

set_timestamp()返回基于年,月,日,小时,分钟和秒的时间戳。如果他们提到不可能的日期或时间,则会更正(mktime())。如果第七个参数不是NULL,则生成的struct tm存储在那里。如果第八个参数不是NULL,则生成的time_t存储在那里。