| /** | |
| * 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> | |
| static struct tm *__cdecl emu__localtime64(const __time64_t *timeptr) | |
| { | |
| struct tm *tmptr; | |
| struct tm tm32; | |
| int local_daylight; | |
| long local_dstbias; | |
| long local_timezone; | |
| __time64_t t64; | |
| __time32_t t32; | |
| /* _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 long tzset_called = 0; | |
| if (!tzset_called) { | |
| _tzset(); | |
| (void)InterlockedExchange(&tzset_called, 1); | |
| } | |
| } | |
| local_daylight = *__daylight(); | |
| local_dstbias = *__dstbias(); | |
| local_timezone = *__timezone(); | |
| /* __localtime64() for the case when the timezone does not use DST */ | |
| t64 = *timeptr - local_timezone; | |
| tmptr = _gmtime64(&t64); | |
| if (!tmptr) | |
| return NULL; | |
| /* If the timezone use DST then it is needed to check if the DST is active | |
| * for passed timestamp. To do that use the existing _localtime32() function | |
| * and its tm_isdst member of return value. As the _localtime32() function | |
| * works only for time structure which can be represented by signed 32-bit | |
| * time_t type, change year of the passed timestamp, so the timestamp can | |
| * be represented by 32-bit type. This expects that the DST start and end | |
| * days of the last addressable year matches also for all other future years. | |
| */ | |
| if (local_daylight) { | |
| /* Prepare struct tm to be representable by 32-bit time_t value, just by changing year */ | |
| tm32 = *tmptr; | |
| if (tm32.tm_year > 2037-1900) | |
| tm32.tm_year = 2037-1900; | |
| else if (tm32.tm_year < 1971-1900) | |
| tm32.tm_year = 1971-1900; | |
| /* Use _localtime32()'s tm_isdst to determinate if the DST is active for passed timestamp */ | |
| t32 = _mkgmtime32(&tm32); | |
| if (t32 == -1) | |
| return NULL; | |
| t32 += local_timezone; /* Remove the fake timezone offset */ | |
| tmptr = _localtime32(&t32); | |
| if (!tmptr) | |
| return NULL; | |
| /* If the DST is active for passed timestamp then recalculate the struct tm according to DST bias */ | |
| if (tmptr->tm_isdst) { | |
| t64 -= local_dstbias; | |
| tmptr = _gmtime64(&t64); | |
| if (!tmptr) | |
| return NULL; | |
| tmptr->tm_isdst = 1; | |
| } else { | |
| tmptr = _gmtime64(&t64); | |
| } | |
| } | |
| return tmptr; | |
| } | |
| #define RETT struct tm * | |
| #define FUNC _localtime64 | |
| #define ARGS const __time64_t *timeptr | |
| #define CALL timeptr | |
| #include "msvcrt_or_emu_glue.h" |