avoid TzSpecificLocalTimeToSystemTime

svn: r840
This commit is contained in:
Matthew Flatt 2005-09-12 20:06:56 +00:00
parent 6e6e54d411
commit 7c147ecaec

View File

@ -2035,24 +2035,72 @@ char *scheme_expand_string_filename(Scheme_Object *o, const char *errorin, int *
# define GET_FF_NAME(fd) fd.cFileName # define GET_FF_NAME(fd) fd.cFileName
static time_t convert_date(const FILETIME *ft) static time_t convert_date(const FILETIME *ft)
{ {
LONGLONG l; LONGLONG l, delta;
FILETIME ft2; FILETIME ft2;
SYSTEMTIME st, st2; SYSTEMTIME st;
TIME_ZONE_INFORMATION tz;
/* FindFirstFile incorrectly shifts for daylight saving. Counteract /* FindFirstFile incorrectly shifts for daylight saving. It
the difference by using FileTimeToLocalFileTime, which also subtracts an hour to get to UTC when daylight saving is in effect
shifts incorrectly. There's a race condition here, because we now, even when daylight saving was not in effect when the file
might cross the daylight-saving boundary between the time that was saved. Counteract the difference. There's a race condition
FindFirstFile runs and FileTimeToLocalFileTime runs. Cross your here, because we might cross the daylight-saving boundary between
fingers... */ the time that FindFirstFile runs and GetTimeZoneInformation
runs. Cross your fingers... */
FileTimeToLocalFileTime(ft, &ft2); FileTimeToLocalFileTime(ft, &ft2);
FileTimeToSystemTime(&ft2, &st); FileTimeToSystemTime(&ft2, &st);
TzSpecificLocalTimeToSystemTime(NULL, &st, &st2);
SystemTimeToFileTime(&st2, &ft2); delta = 0;
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;
l = ((((LONGLONG)ft2.dwHighDateTime << 32) | ft2.dwLowDateTime) /* 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);
} 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)
- (((LONGLONG)0x019DB1DE << 32) | 0xD53E8000)); - (((LONGLONG)0x019DB1DE << 32) | 0xD53E8000));
l /= 10000000; l /= 10000000;
l += delta;
return (time_t)l; return (time_t)l;
} }