The %s specifier in strftime doesn't respect timezones. Example: #include <time.h> #include <stdio.h> int main() { time_t t = 1234567890; struct tm *tmp = gmtime(&t); char output[200]; strftime(output, 200, "%s", tmp); printf("%s\n",output); return 0; } Run with a non UTC timezone. e.g. TZ=GMT+9 Output will be 1234600290 instead of expected 1234567890 Location in glibc: http://fossies.org/dox/glibc-2.19/strftime__l_8c_source.html#l01133 This bug also exists in BSD's libc: https://svnweb.freebsd.org/base/release/10.0.0/lib/libc/stdtime/strftime.c?view=markup#l312 It does not occur in musl: http://git.musl-libc.org/cgit/musl/tree/src/time/strftime.c?id=ac0acd569e01735fc6052d43fdf57f3a07c93f3d#n127
This is the documented behavior in the manual: Calling 'strftime' also sets the current time zone as if 'tzset' were called; 'strftime' uses this information instead of BROKENTIME's 'tm_gmtoff' and 'tm_zone' members. The %s format isn't specified by POSIX and appears to originate in the strftime implementation accompanying the tzdata database. The glibc behavior is compatible -- the original implementation converts the supplied struct tm back to a time_t using mktime(), and mktime() is defined by POSIX to use the timezone as set by tzset(). (POSIX's definition of struct tm doesn't even have the tm_zone or tm_gmtoff members.)
> This is the documented behavior in the manual: > Calling 'strftime' also sets the current time zone as if 'tzset' > were called; 'strftime' uses this information instead of > BROKENTIME's 'tm_gmtoff' and 'tm_zone' members. The %s specifier is defined as printing the **UTC timestamp**. From the man page: %s The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). (TZ) In reality, it prints the UTC timestamp, but adjusted for the local time offset. This is wrong (and not as documented) At the very least this means we have a documentation bug.
Again, from the manual: Calling 'strftime' also sets the current time zone as if 'tzset' were called; 'strftime' uses this information instead of BROKENTIME's 'tm_gmtoff' and 'tm_zone' members. This means that strftime() always treats the supplied struct tm as if it were in the local time zone; this includes the conversion to UTC. If you supply a struct tm to strftime() that isn't in the local time zone, naturally the conversion from the local time zone to UTC will be wrong.