|
29 | 29 | #include "jerryscript-port-default.h" |
30 | 30 |
|
31 | 31 | #ifdef _WIN32 |
32 | | -static const LONGLONG UnixEpochInTicks = 116444736000000000; /* difference between 1970 and 1601 */ |
33 | | -static const LONGLONG TicksPerMs = 10000; /* 1 tick is 100 nanoseconds */ |
| 32 | +static const LONGLONG UnixEpochInTicks = 116444736000000000LL; /* difference between 1970 and 1601 */ |
| 33 | +static const LONGLONG TicksPerMs = 10000LL; /* 1 tick is 100 nanoseconds */ |
| 34 | + |
| 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 LONGLONG UnixEpochOfDate_1601_01_02 = -11644387200000LL; /* unit: ms */ |
| 45 | +static const LONGLONG UnixEpochOfDate_30827_12_29 = 9106702560000000LL; /* unit: ms */ |
34 | 46 |
|
35 | 47 | /* https://support.microsoft.com/en-us/help/167296/how-to-convert-a-unix-time-t-to-a-win32-filetime-or-systemtime */ |
36 | 48 | static void UnixTimeMsToFileTime (double t, LPFILETIME pft) |
@@ -72,27 +84,56 @@ double jerry_port_get_local_time_zone_adjustment (double unix_ms, /**< ms since |
72 | 84 |
|
73 | 85 | return ((double) tm.tm_gmtoff) * 1000; |
74 | 86 | #elif defined (_WIN32) |
75 | | - FILETIME fileTime, localFileTime; |
76 | | - SYSTEMTIME systemTime, localSystemTime; |
77 | | - ULARGE_INTEGER time, localTime; |
| 87 | + FILETIME utcFileTime, localFileTime; |
| 88 | + SYSTEMTIME utcSystemTime, localSystemTime; |
| 89 | + bool timeConverted = false; |
| 90 | + |
| 91 | + /* |
| 92 | + * If the time is earlier than the date 1601-01-02, then always using date 1601-01-02 to |
| 93 | + * query time zone adjustment. This date (1601-01-02) will make sure both UTC and local |
| 94 | + * time succeed with Win32 API. The date 1601-01-01 may lead to a win32 api failure, as |
| 95 | + * after converting between local time and utc time, the time may be earlier than 1601-01-01 |
| 96 | + * in UTC time, that exceeds the FILETIME representation range. |
| 97 | + */ |
| 98 | + if (unix_ms < (double) UnixEpochOfDate_1601_01_02) |
| 99 | + { |
| 100 | + unix_ms = (double) UnixEpochOfDate_1601_01_02; |
| 101 | + } |
78 | 102 |
|
79 | | - UnixTimeMsToFileTime (unix_ms, &fileTime); |
80 | | - /* If time is earlier than year 1601, then always using year 1601 to query time zone adjustment */ |
81 | | - if (fileTime.dwHighDateTime >= 0x80000000) |
| 103 | + /* Like above, do not use the last supported day */ |
| 104 | + if (unix_ms > (double) UnixEpochOfDate_30827_12_29) |
82 | 105 | { |
83 | | - fileTime.dwHighDateTime = 0; |
84 | | - fileTime.dwLowDateTime = 0; |
| 106 | + unix_ms = (double) UnixEpochOfDate_30827_12_29; |
85 | 107 | } |
86 | 108 |
|
87 | | - if (FileTimeToSystemTime (&fileTime, &systemTime) |
88 | | - && SystemTimeToTzSpecificLocalTime (0, &systemTime, &localSystemTime) |
89 | | - && SystemTimeToFileTime (&localSystemTime, &localFileTime)) |
| 109 | + if (is_utc) |
| 110 | + { |
| 111 | + UnixTimeMsToFileTime (unix_ms, &utcFileTime); |
| 112 | + if (FileTimeToSystemTime (&utcFileTime, &utcSystemTime) |
| 113 | + && SystemTimeToTzSpecificLocalTime (0, &utcSystemTime, &localSystemTime) |
| 114 | + && SystemTimeToFileTime (&localSystemTime, &localFileTime)) |
| 115 | + { |
| 116 | + timeConverted = true; |
| 117 | + } |
| 118 | + } |
| 119 | + else |
| 120 | + { |
| 121 | + UnixTimeMsToFileTime (unix_ms, &localFileTime); |
| 122 | + if (FileTimeToSystemTime (&localFileTime, &localSystemTime) |
| 123 | + && TzSpecificLocalTimeToSystemTime (0, &localSystemTime, &utcSystemTime) |
| 124 | + && SystemTimeToFileTime (&utcSystemTime, &utcFileTime)) |
| 125 | + { |
| 126 | + timeConverted = true; |
| 127 | + } |
| 128 | + } |
| 129 | + if (timeConverted) |
90 | 130 | { |
91 | | - time.LowPart = fileTime.dwLowDateTime; |
92 | | - time.HighPart = fileTime.dwHighDateTime; |
| 131 | + ULARGE_INTEGER utcTime, localTime; |
| 132 | + utcTime.LowPart = utcFileTime.dwLowDateTime; |
| 133 | + utcTime.HighPart = utcFileTime.dwHighDateTime; |
93 | 134 | localTime.LowPart = localFileTime.dwLowDateTime; |
94 | 135 | localTime.HighPart = localFileTime.dwHighDateTime; |
95 | | - return (double) (((LONGLONG) localTime.QuadPart - (LONGLONG) time.QuadPart) / TicksPerMs); |
| 136 | + return (double) (((LONGLONG) localTime.QuadPart - (LONGLONG) utcTime.QuadPart) / TicksPerMs); |
96 | 137 | } |
97 | 138 | return 0.0; |
98 | 139 | #elif defined (__GNUC__) || defined (__clang__) |
|
0 commit comments