crt: Provide emulation of _mktime64 function Function _mktime64 is available since msvcr70.dll. For older msvcrt versions provide mingw-w64 emulation via musl libc __tm_to_secs() function with adjustment of _timezone and _dstbias variable variables, and normalization via _localtime64() function which is now available in all CRT import libraries (either as native symbols or as mingw-w64 emulation). Adjustment of _dstbias needs to be done only when passed timestamp is during the DST period which is detected by the _localtime64() function too. Signed-off-by: Martin Storsjö <martin@martin.st>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index e8e5e73..2497a45 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am
@@ -587,6 +587,7 @@ misc/_localtime64.c \ misc/_mkgmtime32.c \ misc/_mkgmtime64.c \ + misc/_mktime64.c \ misc/_set_doserrno.c \ misc/_set_fmode.c \ misc/_time64.c \ @@ -902,6 +903,7 @@ misc/_futime64.c \ misc/_gmtime64.c \ misc/_localtime64.c \ + misc/_mktime64.c \ misc/_time64.c \ misc/_utime64.c \ misc/_wctime64.c \
diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in index a1439b2..71054e1 100644 --- a/mingw-w64-crt/lib-common/msvcrt.def.in +++ b/mingw-w64-crt/lib-common/msvcrt.def.in
@@ -1158,7 +1158,7 @@ F_NON_I386(_futime64) ; i386 _futime64 replaced by emu F_NON_I386(_gmtime64) ; i386 _gmtime64 replaced by emu F_NON_I386(_localtime64) ; i386 _localtime64 replaced by emu -_mktime64 +F_NON_I386(_mktime64) ; i386 _mktime64 replaced by emu F_X86_ANY(_osplatform DATA) F_NON_I386(_stat64) ; i386 _stat64 replaced by emu F_NON_I386(_time64) ; i386 _time64 replaced by emu
diff --git a/mingw-w64-crt/misc/_mktime64.c b/mingw-w64-crt/misc/_mktime64.c new file mode 100644 index 0000000..924e663 --- /dev/null +++ b/mingw-w64-crt/misc/_mktime64.c
@@ -0,0 +1,60 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include <windows.h> +#include <time.h> + +#include "__tm_to_secs.h" + +static __time64_t __cdecl emu__mktime64(struct tm *tmptr) +{ + __time64_t time64; + struct tm *tmptr2; + int tm_isdst; + long local_dstbias; + long local_timezone; + + /* _tzset() initialize _daylight, _dstbias and _timezone variables, + * so it needs to be called before accessing those variables. + * If those variables are already initialized then _tzset() does + * not need to be called again. As _tzset() is an expensive call, + * guard repeated calls by static variable. As the _tzset() is a + * thread-safe call, the race condition is not a problem. + */ + { + static volatile long tzset_called = 0; + if (!tzset_called) { + _tzset(); + (void)InterlockedExchange(&tzset_called, 1); + } + } + local_dstbias = *__dstbias(); + local_timezone = *__timezone(); + + tm_isdst = tmptr->tm_isdst; + time64 = __tm_to_secs(tmptr); + time64 += local_timezone; + + tmptr2 = _localtime64(&time64); + if (!tmptr2) + return -1; + + if (tm_isdst > 0 || (tm_isdst < 0 && tmptr2->tm_isdst > 0)) { + time64 += local_dstbias; + tmptr2 = _localtime64(&time64); + if (!tmptr2) + return -1; + } + + *tmptr = *tmptr2; + return time64; +} + +#define RETT __time64_t +#define FUNC _mktime64 +#define ARGS struct tm *tmptr +#define CALL tmptr +#include "msvcrt_or_emu_glue.h"