rktio: fix Windows file timestamp dst correction
The old correction was broken in at least a couple of ways; use the more tested DST calculation in the implementation of `seconds->date`.
This commit is contained in:
parent
e95c3fe6d5
commit
d3aa7e90e7
|
@ -129,12 +129,12 @@ static time_t convert_date(const FILETIME *ft)
|
|||
SYSTEMTIME st;
|
||||
TIME_ZONE_INFORMATION tz;
|
||||
|
||||
/* FindFirstFile incorrectly shifts for daylight saving. It
|
||||
/* GetFileAttributes incorrectly shifts for daylight saving. It
|
||||
subtracts an hour to get to UTC when daylight saving is in effect
|
||||
now, even when daylight saving was not in effect when the file
|
||||
was saved. Counteract the difference. There's a race condition
|
||||
here, because we might cross the daylight-saving boundary between
|
||||
the time that FindFirstFile runs and GetTimeZoneInformation
|
||||
the time that GetFileAttributes runs and GetTimeZoneInformation
|
||||
runs. Cross your fingers... */
|
||||
FileTimeToLocalFileTime(ft, &ft2);
|
||||
FileTimeToSystemTime(&ft2, &st);
|
||||
|
@ -143,47 +143,8 @@ static time_t convert_date(const FILETIME *ft)
|
|||
if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_DAYLIGHT) {
|
||||
/* Daylight saving is in effect now, so there may be a bad
|
||||
shift. Check the file's date. */
|
||||
int start_day_of_month, end_day_of_month, first_day_of_week, diff, end_shift;
|
||||
|
||||
/* Valid only when the months match: */
|
||||
first_day_of_week = (st.wDayOfWeek - (st.wDay - 1 - (((st.wDay - 1) / 7) * 7)));
|
||||
if (first_day_of_week < 0)
|
||||
first_day_of_week += 7;
|
||||
|
||||
diff = (tz.DaylightDate.wDayOfWeek - first_day_of_week);
|
||||
if (diff < 0)
|
||||
diff += 7;
|
||||
start_day_of_month = 1 + (((tz.DaylightDate.wDay - 1) * 7)
|
||||
+ diff);
|
||||
|
||||
diff = (tz.StandardDate.wDayOfWeek - first_day_of_week);
|
||||
if (diff < 0)
|
||||
diff += 7;
|
||||
end_day_of_month = 1 + (((tz.StandardDate.wDay - 1) * 7)
|
||||
+ diff);
|
||||
|
||||
/* Count ambigious range (when the clock goes back) as
|
||||
in standard time. We assume that subtracting the
|
||||
ambiguous range does not go back into the previous day,
|
||||
and that the shift is a multiple of an hour. */
|
||||
end_shift = ((tz.StandardBias - tz.DaylightBias) / 60);
|
||||
|
||||
if ((st.wMonth < tz.DaylightDate.wMonth)
|
||||
|| ((st.wMonth == tz.DaylightDate.wMonth)
|
||||
&& ((st.wDay < start_day_of_month)
|
||||
|| ((st.wDay == start_day_of_month)
|
||||
&& (st.wHour < tz.DaylightDate.wHour))))) {
|
||||
/* Daylight saving had not yet started. */
|
||||
if (!rktio_system_time_is_dst(&st, NULL))
|
||||
delta = ((tz.StandardBias - tz.DaylightBias) * 60);
|
||||
} else if ((st.wMonth > tz.StandardDate.wMonth)
|
||||
|| ((st.wMonth == tz.StandardDate.wMonth)
|
||||
&& ((st.wDay > end_day_of_month)
|
||||
|| ((st.wDay == end_day_of_month)
|
||||
&& (st.wHour >= (tz.StandardDate.wHour
|
||||
- end_shift)))))) {
|
||||
/* Daylight saving was already over. */
|
||||
delta = ((tz.StandardBias - tz.DaylightBias) * 60);
|
||||
}
|
||||
}
|
||||
|
||||
l = ((((LONGLONG)ft->dwHighDateTime << 32) | ft->dwLowDateTime)
|
||||
|
|
|
@ -360,3 +360,8 @@ char *rktio_strndup(char *s, intptr_t len);
|
|||
void rktio_set_signal_handler(int sig_id, void (*proc)(int));
|
||||
#endif
|
||||
void rktio_forget_os_signal_handler(rktio_t *rktio);
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
int rktio_system_time_is_dst(SYSTEMTIME *st, TIME_ZONE_INFORMATION *_tz);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -258,6 +258,28 @@ static int is_day_before(SYSTEMTIME *a, SYSTEMTIME *b)
|
|||
return 0;
|
||||
}
|
||||
# undef dtxCOMP
|
||||
|
||||
int rktio_system_time_is_dst(SYSTEMTIME *st, TIME_ZONE_INFORMATION *_tz)
|
||||
{
|
||||
TIME_ZONE_INFORMATION tz;
|
||||
if (GetTimeZoneInformationForYearProc)
|
||||
GetTimeZoneInformationForYearProc(st->wYear, NULL, &tz);
|
||||
else
|
||||
(void)GetTimeZoneInformation(&tz);
|
||||
if (_tz) *_tz = tz;
|
||||
if (tz.StandardDate.wMonth) {
|
||||
if (is_start_day_before(&tz.DaylightDate, &tz.StandardDate)) {
|
||||
/* northern hemisphere */
|
||||
return (!is_day_before(st, &tz.DaylightDate)
|
||||
&& is_day_before(st, &tz.StandardDate));
|
||||
} else {
|
||||
/* southern hemisphere */
|
||||
return (is_day_before(st, &tz.StandardDate)
|
||||
|| !is_day_before(st, &tz.DaylightDate));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OS_X) && defined(__x86_64__)
|
||||
|
@ -379,22 +401,7 @@ rktio_date_t *rktio_seconds_to_date(rktio_t *rktio, rktio_timestamp_t seconds, i
|
|||
tzn = MSC_IZE(strdup)("UTC");
|
||||
} else {
|
||||
TIME_ZONE_INFORMATION tz;
|
||||
if (GetTimeZoneInformationForYearProc)
|
||||
GetTimeZoneInformationForYearProc(localTime.wYear, NULL, &tz);
|
||||
else
|
||||
(void)GetTimeZoneInformation(&tz);
|
||||
if (tz.StandardDate.wMonth) {
|
||||
if (is_start_day_before(&tz.DaylightDate, &tz.StandardDate)) {
|
||||
/* northern hemisphere */
|
||||
dst = (!is_day_before(&localTime, &tz.DaylightDate)
|
||||
&& is_day_before(&localTime, &tz.StandardDate));
|
||||
} else {
|
||||
/* southern hemisphere */
|
||||
dst = (is_day_before(&localTime, &tz.StandardDate)
|
||||
|| !is_day_before(&localTime, &tz.DaylightDate));
|
||||
}
|
||||
}
|
||||
if (dst) {
|
||||
if (rktio_system_time_is_dst(&localTime, &tz)) {
|
||||
tzoffset = (tz.Bias + tz.DaylightBias) * -60;
|
||||
tzn = NARROW_PATH_copy(tz.DaylightName);
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue
Block a user