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;
|
SYSTEMTIME st;
|
||||||
TIME_ZONE_INFORMATION tz;
|
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
|
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
|
now, even when daylight saving was not in effect when the file
|
||||||
was saved. Counteract the difference. There's a race condition
|
was saved. Counteract the difference. There's a race condition
|
||||||
here, because we might cross the daylight-saving boundary between
|
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... */
|
runs. Cross your fingers... */
|
||||||
FileTimeToLocalFileTime(ft, &ft2);
|
FileTimeToLocalFileTime(ft, &ft2);
|
||||||
FileTimeToSystemTime(&ft2, &st);
|
FileTimeToSystemTime(&ft2, &st);
|
||||||
|
@ -143,47 +143,8 @@ static time_t convert_date(const FILETIME *ft)
|
||||||
if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_DAYLIGHT) {
|
if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_DAYLIGHT) {
|
||||||
/* Daylight saving is in effect now, so there may be a bad
|
/* Daylight saving is in effect now, so there may be a bad
|
||||||
shift. Check the file's date. */
|
shift. Check the file's date. */
|
||||||
int start_day_of_month, end_day_of_month, first_day_of_week, diff, end_shift;
|
if (!rktio_system_time_is_dst(&st, NULL))
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
delta = ((tz.StandardBias - tz.DaylightBias) * 60);
|
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)
|
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));
|
void rktio_set_signal_handler(int sig_id, void (*proc)(int));
|
||||||
#endif
|
#endif
|
||||||
void rktio_forget_os_signal_handler(rktio_t *rktio);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
# undef dtxCOMP
|
# 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
|
#endif
|
||||||
|
|
||||||
#if defined(OS_X) && defined(__x86_64__)
|
#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");
|
tzn = MSC_IZE(strdup)("UTC");
|
||||||
} else {
|
} else {
|
||||||
TIME_ZONE_INFORMATION tz;
|
TIME_ZONE_INFORMATION tz;
|
||||||
if (GetTimeZoneInformationForYearProc)
|
if (rktio_system_time_is_dst(&localTime, &tz)) {
|
||||||
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) {
|
|
||||||
tzoffset = (tz.Bias + tz.DaylightBias) * -60;
|
tzoffset = (tz.Bias + tz.DaylightBias) * -60;
|
||||||
tzn = NARROW_PATH_copy(tz.DaylightName);
|
tzn = NARROW_PATH_copy(tz.DaylightName);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user