2929#include "jerryscript-port-default.h"
3030
3131#ifdef _WIN32
32- static const LONGLONG UnixEpochInTicks = 116444736000000000 ; /* difference between 1970 and 1601 */
32+ static const LONGLONG UnixEpochInTicks = 116444736000000000LL ; /* difference between 1970 and 1601 */
3333static const LONGLONG TicksPerMs = 10000 ; /* 1 tick is 100 nanoseconds */
3434
35+ /**
36+ * If you take the limit of SYSTEMTIME (last millisecond in 30827) then you end up with
37+ * a FILETIME of 0x7fff35f4f06c58f0 by using SystemTimeToFileTime(). However, if you put
38+ * 0x7fffffffffffffff into FileTimeToSystemTime() then you will end up in the year 30828,
39+ * although this date is invalid for SYSTEMTIME. Any larger value (0x8000000000000000 and above)
40+ * causes FileTimeToSystemTime() to fail.
41+ * https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime
42+ * https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
43+ */
44+ static const long long UnixEpochOfDate_1601_01_02 = -11644387200000LL ; /* unit: ms */
45+ static const long long UnixEpochOfDate_30827_12_29 = 9106702560000000LL ; /* unit: ms */
46+
3547/* https://support.microsoft.com/en-us/help/167296/how-to-convert-a-unix-time-t-to-a-win32-filetime-or-systemtime */
3648static void UnixTimeMsToFileTime (double t , LPFILETIME pft )
3749{
@@ -57,30 +69,59 @@ static double FileTimeToUnixTimeMs (FILETIME ft)
5769 * available. Otherwise, returns 0, assuming UTC time.
5870 */
5971double jerry_port_get_local_time_zone_adjustment (double unix_ms , /**< ms since unix epoch */
60- bool is_utc ) /**< is the time above in UTC? */
72+ bool is_utc ) /**< is the time above in UTC, */
6173{
6274#ifdef _WIN32
63- FILETIME fileTime , localFileTime ;
64- SYSTEMTIME systemTime , localSystemTime ;
65- ULARGE_INTEGER time , localTime ;
75+ FILETIME utcFileTime , localFileTime ;
76+ SYSTEMTIME utcSystemTime , localSystemTime ;
77+ bool timeConverted = false;
78+
79+ /**
80+ * If time is earlier than date 1601-01-02, then always using year 1601-01-02 to
81+ * query time zone adjustment, this date(1601-01-02) will make sure both utc/local
82+ * time both succeed with Win32 API, using date(1601-01-01) may leading win32 api
83+ * failure, as after convert between local time/utc time, the date may earlier than
84+ * 1601-01-01 in utc time, that's exceed the FILETIME representation range.
85+ */
86+ if (unix_ms < UnixEpochOfDate_1601_01_02 )
87+ {
88+ unix_ms = UnixEpochOfDate_1601_01_02 ;
89+ }
6690
67- UnixTimeMsToFileTime (unix_ms , & fileTime );
68- /* If time is earlier than year 1601, then always using year 1601 to query time zone adjustment */
69- if (fileTime .dwHighDateTime >= 0x80000000 )
91+ /* Same reason as upper, do not use the latest support day */
92+ if (unix_ms > UnixEpochOfDate_30827_12_29 )
7093 {
71- fileTime .dwHighDateTime = 0 ;
72- fileTime .dwLowDateTime = 0 ;
94+ unix_ms = UnixEpochOfDate_30827_12_29 ;
7395 }
7496
75- if (FileTimeToSystemTime (& fileTime , & systemTime )
76- && SystemTimeToTzSpecificLocalTime (0 , & systemTime , & localSystemTime )
77- && SystemTimeToFileTime (& localSystemTime , & localFileTime ))
97+ if (is_utc )
98+ {
99+ UnixTimeMsToFileTime (unix_ms , & utcFileTime );
100+ if (FileTimeToSystemTime (& utcFileTime , & utcSystemTime )
101+ && SystemTimeToTzSpecificLocalTime (0 , & utcSystemTime , & localSystemTime )
102+ && SystemTimeToFileTime (& localSystemTime , & localFileTime ))
103+ {
104+ timeConverted = true;
105+ }
106+ }
107+ else
108+ {
109+ UnixTimeMsToFileTime (unix_ms , & localFileTime );
110+ if (FileTimeToSystemTime (& localFileTime , & localSystemTime )
111+ && TzSpecificLocalTimeToSystemTime (0 , & localSystemTime , & utcSystemTime )
112+ && SystemTimeToFileTime (& utcSystemTime , & utcFileTime ))
113+ {
114+ timeConverted = true;
115+ }
116+ }
117+ if (timeConverted )
78118 {
79- time .LowPart = fileTime .dwLowDateTime ;
80- time .HighPart = fileTime .dwHighDateTime ;
119+ ULARGE_INTEGER utcTime , localTime ;
120+ utcTime .LowPart = utcFileTime .dwLowDateTime ;
121+ utcTime .HighPart = utcFileTime .dwHighDateTime ;
81122 localTime .LowPart = localFileTime .dwLowDateTime ;
82123 localTime .HighPart = localFileTime .dwHighDateTime ;
83- return (double ) (((LONGLONG ) localTime .QuadPart - (LONGLONG ) time .QuadPart ) / TicksPerMs );
124+ return (double ) (((LONGLONG ) localTime .QuadPart - (LONGLONG ) utcTime .QuadPart ) / TicksPerMs );
84125 }
85126 return 0.0 ;
86127#elif defined (__GNUC__ ) || defined (__clang__ )
0 commit comments