On Sat, 25 Oct 2025, Pali Rohár wrote:
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. --- mingw-w64-crt/Makefile.am | 2 + mingw-w64-crt/lib-common/msvcrt.def.in | 2 +- mingw-w64-crt/misc/_mktime64.c | 60 ++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 mingw-w64-crt/misc/_mktime64.cdiff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index 3de7e15da12b..df505ee80584 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am @@ -585,6 +585,7 @@ src_msvcrt32=\ misc/_localtime64.c \ misc/_mkgmtime32.c \ misc/_mkgmtime64.c \ + misc/_mktime64.c \ misc/_set_doserrno.c \ misc/_set_fmode.c \ misc/_time64.c \ @@ -897,6 +898,7 @@ src_pre_msvcr70=\ misc/_ftime64.c \ misc/_gmtime64.c \ misc/_localtime64.c \ + misc/_mktime64.c \ misc/_time64.c \ misc/_wctime64.c \ misc/strtoimax.c \ diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in index 77f18305b27b..9e357f0b6bd2 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(_ftime64) ; i386 _ftime64 replaced by emu _futime64 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 000000000000..924e6635446d --- /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; +}
I think this function is right. There are tricky corner cases here as well, but I think the logic above does it correctly.
// Martin _______________________________________________ Mingw-w64-public mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
