Step 1: select any time_t (the current time will work fine) as a control point; name it t0 .
Step 2: Call gmtime on t0 and calculate the difference between the result and the era in the broken form struct tm .
Step 3: Call localtime on t0 and apply the broken difference from step 2 to the result of struct tm . Then call mktime on it to return a time_t .
The result should be time_t representing the era.
My first attempt to realize this had problems when local time shifts were not constant over time, for example, in places where daylight saving time was added or left, or which switched from observing one zone to another. This seems to be due to the fact that the data in struct tm , which the time zone information is based on, is changing. Here is the original implementation with its problems:
time_t get_epoch(time_t t0) { struct tm gmt = *gmtime(&t0); struct tm tmp = *localtime(&t0); tmp.tm_sec -= gmt.tm_sec; tmp.tm_min -= gmt.tm_min; tmp.tm_hour -= gmt.tm_hour; tmp.tm_mday -= gmt.tm_mday-1; tmp.tm_mon -= gmt.tm_mon; tmp.tm_year -= gmt.tm_year-70; return mktime(&tmp); }
and an improved version, where posix_time is a function to calculate seconds from an era for a given struct tm using POSIX formulas (http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html # tag_04_15), with extra work for processing years to 1970, etc., if necessary:
time_t get_epoch(time_t t0) { struct tm gmt = *gmtime(&t0); struct tm tmp = *localtime(&t0); long long offset = posix_time(&gmt); while (offset > INT_MAX) { offset -= INT_MAX; tmp.tm_sec -= INT_MAX; mktime(&tmp); } while (offset < -INT_MAX+61) { offset -= -INT_MAX+61; tmp.tm_sec -= -INT_MAX+61; mktime(&tmp); } tmp.tm_sec -= offset; return mktime(&tmp); }
For compatibility with C89, long long need to be dropped, and the number of required calls mktime increases dramatically; offset cannot be calculated as a single value, but a loop will be needed to call mktime several times a year.
R ..
source share