blob: b49ce209563eef22f18b75b3357436c348f29ada [file] [log] [blame]
/**
* 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 volatile 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"