I have the following file test.c:
#define _POSIX_THREAD_SAFE_FUNCTIONS
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
int main(int argc,char**argv) {
struct tm t1, t2, t3;
time_t w1, w2, w3;
memset(&t1,0,sizeof(struct tm));
memset(&t2,0,sizeof(struct tm));
memset(&t3,0,sizeof(struct tm));
w1 = 0;
errno = 0;
localtime_r(&w1,&t1);
printf("localtime_r: errno=%d\n",errno);
errno = 0;
w2 = mktime(&t1);
printf("mktime: errno=%d result=%" PRId64 "\n",errno,((int64_t)w2));
errno = 0;
localtime_r(&w2,&t2);
printf("localtime_r: errno=%d\n",errno);
errno = 0;
w3 = mktime(&t2);
printf("mktime: errno=%d result=%" PRId64 "\n",errno,((int64_t)w3));
errno = 0;
localtime_r(&w3,&t3);
printf("localtime_r: errno=%d\n",errno);
printf("sizeof(time_t)=%" PRId64 "\n", ((int64_t)sizeof(time_t)));
printf("W1=%" PRId64 " W2=%" PRId64 " W3=%" PRId64 "\n",((int64_t)w1),((int64_t)w2),((int64_t)w3));
printf("Y1=%d Y2=%d Y3=%d\n",t1.tm_year,t2.tm_year,t3.tm_year);
return 0;
}
I compile it like this:
i686-w64-mingw32-gcc -D__MINGW_USE_VC2005_COMPAT=1 -o test.exe test.c
Note, i686-w64-mingw32-gcc --version
reports 8.3-win32 20190406
This is running in a Docker image of Ubuntu 19.04, using the MinGW version
that comes with Ubuntu 19.04 (it says version 6.0.0-3).
I have a Windows 10 VM (Version 1809 OS Build 17763.379). By default, time zone is set to US Pacific Time (UTC-8). I copy test.exe to this VM and run it there.
It prints:
localtime_r: errno=0
mktime: errno=0 result=0
localtime_r: errno=0
mktime: errno=0 result=0
localtime_r: errno=0
sizeof(time_t)=8
W1=0 W2=0 W3=0
Y1=69 Y2=69 Y3=69
That's the expected result. (At UTC midnight on 1 Jan 1970, it was still 1969 in UTC-8.)
I change the Windows time zone to UTC+10 (Canberra, Melbourne, Sydney). Run it again. It prints:
localtime_r: errno=0
mktime: errno=0 result=47244640256
localtime_r: errno=22
mktime: errno=22 result=4294967295
localtime_r: errno=0
sizeof(time_t)=8
W1=0 W2=47244640256 W3=4294967295
Y1=70 Y2=-1 Y3=206
It seems the mktime() call is returning an invalid value in UTC+10 time zone, but returns the correct value of 0 in UTC-8 time zone.
Why does this code work in one timezone break in another?
Note, this is only a problem with -D__MINGW_USE_VC2005_COMPAT=1
to enable
64-bit time_t. If I leave that out, which means 32-bit time_t, then the code
works in both timezones. (But, 32-bit time_t is not a good idea, because it breaks in the year 2038, and that's less than twenty years away now.)