3

我想知道是否有人知道/有一个 C 宏来从硬编码的日期和时间计算静态 Unix 时间,如下所示:

time_t t = UNIX_TIMESTAMP(2012, 5, 10, 9, 26, 13);

我正在研究这个,因为我想要一个数字静态时间戳。这将在整个软件中完成数百次,每次都有不同的日期,我想确保它很快,因为它每秒会运行数百次。多次转换日期肯定会减慢速度(即调用 mktime() 比在适当位置编译静态数字要慢,对吧?)

[进行了更新以尝试使本段更清晰,2012 年 11 月 23 日]

更新

我想通过有关正在使用的流程的更多信息来澄清这个问题。当我的服务器收到请求时,对于每个请求,它都会启动一个新进程。该过程会不断使用新插件进行更新,并且此类更新通常需要数据库更新。这些必须只运行一次。要知道是否需要更新,我想使用 Unix 日期(这比使用计数器更好,因为计数器更有可能偶尔中断。)

因此,插件将接收更新信号并调用其 on_update() 函数。在那里我想做这样的事情:

void some_plugin::on_update(time_t last_update)
{
  if(last_update < UNIX_TIMESTAMP(2010, 3, 22, 20, 9, 26)) {
    ...run update...
  }
  if(last_update < UNIX_TIMESTAMP(2012, 5, 10, 9, 26, 13)) {
    ...run update...
  }
  // as many test as required...
}

如您所见,如果我每次都必须计算 unix 时间戳,这可能代表每个进程有数千次调用,如果您每秒收到 100 次点击 x 1000 次调用,那么当您可以让编译器计算这些数字时,您浪费了 100,000 次调用在编译时一次。

将值放在静态变量中没有意义,因为此代码将在每个进程运行时运行一次。

请注意,last_update 变量会根据被点击的网站而变化(它来自数据库。)

代码

好的,我现在得到了代码:

// helper (Days in February)
#define _SNAP_UNIX_TIMESTAMP_FDAY(year) \
    (((year) % 400) == 0 ? 29LL : \
        (((year) % 100) == 0 ? 28LL : \
            (((year) % 4) == 0 ? 29LL : \
                28LL)))

// helper (Days in the year)
#define _SNAP_UNIX_TIMESTAMP_YDAY(year, month, day) \
    ( \
        /* January */    static_cast<qint64>(day) \
        /* February */ + ((month) >=  2 ? 31LL : 0LL) \
        /* March */    + ((month) >=  3 ? _SNAP_UNIX_TIMESTAMP_FDAY(year) : 0LL) \
        /* April */    + ((month) >=  4 ? 31LL : 0LL) \
        /* May */      + ((month) >=  5 ? 30LL : 0LL) \
        /* June */     + ((month) >=  6 ? 31LL : 0LL) \
        /* July */     + ((month) >=  7 ? 30LL : 0LL) \
        /* August */   + ((month) >=  8 ? 31LL : 0LL) \
        /* September */+ ((month) >=  9 ? 31LL : 0LL) \
        /* October */  + ((month) >= 10 ? 30LL : 0LL) \
        /* November */ + ((month) >= 11 ? 31LL : 0LL) \
        /* December */ + ((month) >= 12 ? 30LL : 0LL) \
    )

#define SNAP_UNIX_TIMESTAMP(year, month, day, hour, minute, second) \
    ( /* time */ static_cast<qint64>(second) \
                + static_cast<qint64>(minute) * 60LL \
                + static_cast<qint64>(hour) * 3600LL \
    + /* year day (month + day) */ (_SNAP_UNIX_TIMESTAMP_YDAY(year, month, day) - 1) * 86400LL \
    + /* year */ (static_cast<qint64>(year) - 1970LL) * 31536000LL \
                + ((static_cast<qint64>(year) - 1969LL) / 4LL) * 86400LL \
                - ((static_cast<qint64>(year) - 1901LL) / 100LL) * 86400LL \
                + ((static_cast<qint64>(year) - 1601LL) / 400LL) * 86400LL )

警告:不要使用这些宏来动态计算日期。它比 mktime() 慢。话虽如此,如果您有一个硬编码的日期,那么编译器将在编译时计算 time_t 值。编译速度较慢,但​​一遍又一遍地执行速度更快。

4

3 回答 3

4

公式在 POSIX 中:

tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
    (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
    ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400

来源:XBD 纪元以来的 4.15 秒 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_15

于 2012-05-10T16:56:30.943 回答
2

如果您测量它实际上太慢了,那么这是一个实用的简单解决方案:

void myfun() {
  static time_t t = 0;
  if (t == 0)
    t = slow_unix_timestamp(2012, 5, 10, 9, 26, 13);
}

现在只计算一次。

于 2012-05-10T16:41:19.267 回答
1

不是宏,但时间戳只会初始化一次,后续调用get_timestamp()将简单地成为内存访问。您在运行时支付初始化费用,但只get_timestamp()调用第一次,因为您知道您可以在程序的早期初始化它并允许后续调用有效地“免费”。

time_t initialize_timestamp(int y, int m, int d, int h, int min, s)
{
   tm t;
   t.tm_year = y - 1900;
   t.tm_mon = m;
   t.tm.mday = d;
   t.tm_hour = h;
   t.tm_min = min;
   t.tm_sec = s;

   return mktime(&t);
}

time_t get_static_timestamp()
{
   static time_t ts = initialize_timestamp(2012, 5, 10, 9, 26, 13);
   return ts;
}
于 2012-05-10T16:44:48.267 回答