Do you know of a C macro to compute Unix time and date?

若如初见. 提交于 2019-12-07 11:54:06

问题


I'm wondering if someone knows/has a C macro to compute a static Unix time from a hard coded date and time as in:

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

I'm looking into that because I want to have a numeric static timestamp. This will be done hundred of times throughout the software, each time with a different date, and I want to make sure it is fast because it will run hundreds of times every second. Converting dates that many times would definitively slow down things (i.e. calling mktime() is slower than having a static number compiled in place, right?)

[made an update to try to render this paragraph clearer, Nov 23, 2012]

Update

I want to clarify the question with more information about the process being used. As my server receives requests, for each request, it starts a new process. That process is constantly updated with new plugins and quite often such updates require a database update. Those must be run only once. To know whether an update is necessary, I want to use a Unix date (which is better than using a counter because a counter is much more likely to break once in a while.)

The plugins will thus receive an update signal and have their on_update() function called. There I want to do something like this:

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...
}

As you can see, if I have to compute the unix timestamp each time, this could represent thousands of calls per process and if you receive 100 hits a second x 1000 calls, you wasted 100,000 calls when you could have had the compiler compute those numbers once at compile time.

Putting the value in a static variable is of no interest because this code will run once per process run.

Note that the last_update variable changes depending on the website being hit (it comes from the database.)

Code

Okay, I got the code now:

// 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 )

WARNING: Do not use these macros to dynamically compute a date. It is SLOWER than mktime(). This being said, if you have a hard coded date, then the compiler will compute the time_t value at compile time. Slower to compile, but faster to execute over and over again.


回答1:


The formula is in 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

Source: XBD 4.15 Seconds Since the Epoch http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_15




回答2:


If you measured that it's actually too slow, then here is a practical simple workaround solution:

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

Now it's calculated only once.




回答3:


Not a macro, but the timestamp will only be initialized once, subsequent calls to get_timestamp() will simple be a memory access. You pay the initialization penalty at runtime, but only the first time get_timestamp() is called, knowing that you can initialize it early in your program and allow subsequent calls to be effectively "free".

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;
}


来源:https://stackoverflow.com/questions/10538444/do-you-know-of-a-c-macro-to-compute-unix-time-and-date

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!