diff options
author | Tony Cook <tony@develop-help.com> | 2020-10-15 10:38:05 +1100 |
---|---|---|
committer | Tony Cook <tony@develop-help.com> | 2020-12-01 15:29:33 +1100 |
commit | 690ab4ba4bc90fa2f43c03eb418c3dc163f57ea8 (patch) | |
tree | fbc1bcc082bc03442570fe33d61e577695eb7260 /win32 | |
parent | 520fd6d3ecf7b0cec09bae8a26b939b7ed485bbf (diff) | |
download | perl-690ab4ba4bc90fa2f43c03eb418c3dc163f57ea8.tar.gz |
Win32: re-work FILETIME <=> time_t conversions
Current versions of Windows claim to support leap seconds, but the
time conversion I was using ignores that possibility.
Switch to using APIs (FileTimeToSystemTime() and SystemTimeToFileTime())
that are documented to support leap seconds that might be included
in a FILETIME.
Diffstat (limited to 'win32')
-rw-r--r-- | win32/win32.c | 56 |
1 files changed, 41 insertions, 15 deletions
diff --git a/win32/win32.c b/win32/win32.c index 829bdfbc60..1046f6cfd5 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -1474,16 +1474,24 @@ win32_kill(int pid, int sig) PERL_STATIC_INLINE time_t translate_ft_to_time_t(FILETIME ft) { - /* Based on Win32::UTCTime. - Older CRTs (including MSVCRT used for gcc builds) product - strange behaviour when the specified time and the current time - differ on whether DST was in effect, this code doesnt have that - problem. - */ - ULARGE_INTEGER u; - u.LowPart = ft.dwLowDateTime; - u.HighPart = ft.dwHighDateTime; - return (u.QuadPart - time_t_epoch_base_filetime.QuadPart) / FILETIME_CHUNKS_PER_SECOND; + SYSTEMTIME st, local_st; + struct tm pt; + + if (!FileTimeToSystemTime(&ft, &st) || + !SystemTimeToTzSpecificLocalTime(NULL, &st, &local_st)) { + return -1; + } + + Zero(&pt, 1, struct tm); + pt.tm_year = local_st.wYear - 1900; + pt.tm_mon = local_st.wMonth - 1; + pt.tm_mday = local_st.wDay; + pt.tm_hour = local_st.wHour; + pt.tm_min = local_st.wMinute; + pt.tm_sec = local_st.wSecond; + pt.tm_isdst = -1; + + return mktime(&pt); } static int @@ -2173,12 +2181,30 @@ win32_times(struct tms *timebuf) static BOOL filetime_from_time(PFILETIME pFileTime, time_t Time) { - ULARGE_INTEGER u; - u.QuadPart = Time; - u.QuadPart = u.QuadPart * FILETIME_CHUNKS_PER_SECOND + time_t_epoch_base_filetime.QuadPart; + struct tm *pt; + SYSTEMTIME st; - pFileTime->dwLowDateTime = u.LowPart; - pFileTime->dwHighDateTime = u.HighPart; + pt = gmtime(&Time); + if (!pt) { + pFileTime->dwLowDateTime = 0; + pFileTime->dwHighDateTime = 0; + fprintf(stderr, "fail bad gmtime\n"); + return FALSE; + } + + st.wYear = pt->tm_year + 1900; + st.wMonth = pt->tm_mon + 1; + st.wDay = pt->tm_mday; + st.wHour = pt->tm_hour; + st.wMinute = pt->tm_min; + st.wSecond = pt->tm_sec; + st.wMilliseconds = 0; + + if (!SystemTimeToFileTime(&st, pFileTime)) { + pFileTime->dwLowDateTime = 0; + pFileTime->dwHighDateTime = 0; + return FALSE; + } return TRUE; } |