Do you know of a C macro to compute Unix time and date?
- by Alexis Wilke
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.