|
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) |
@@ -60,27 +72,56 @@ double jerry_port_get_local_time_zone_adjustment (double unix_ms, /**< ms since |
60 | 72 | bool is_utc) /**< is the time above in UTC? */ |
61 | 73 | { |
62 | 74 | #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 the time is earlier than the date 1601-01-02, then always using date 1601-01-02 to |
| 81 | + * query time zone adjustment. This date (1601-01-02) will make sure both UTC and local |
| 82 | + * time succeed with Win32 API. The date 1601-01-01 may lead to a win32 api failure, as |
| 83 | + * after converting between local time and utc time, the time may be earlier than 1601-01-01 |
| 84 | + * in UTC time, that exceeds the FILETIME representation range. |
| 85 | + */ |
| 86 | + if (unix_ms < (double) UnixEpochOfDate_1601_01_02) |
| 87 | + { |
| 88 | + unix_ms = (double) UnixEpochOfDate_1601_01_02; |
| 89 | + } |
66 | 90 |
|
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 | + /* Like above, do not use the last supported day */ |
| 92 | + if (unix_ms > (double) UnixEpochOfDate_30827_12_29) |
70 | 93 | { |
71 | | - fileTime.dwHighDateTime = 0; |
72 | | - fileTime.dwLowDateTime = 0; |
| 94 | + unix_ms = (double) UnixEpochOfDate_30827_12_29; |
73 | 95 | } |
74 | 96 |
|
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) |
78 | 118 | { |
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; |
81 | 122 | localTime.LowPart = localFileTime.dwLowDateTime; |
82 | 123 | localTime.HighPart = localFileTime.dwHighDateTime; |
83 | | - return (double) (((LONGLONG) localTime.QuadPart - (LONGLONG) time.QuadPart) / TicksPerMs); |
| 124 | + return (double) (((LONGLONG) localTime.QuadPart - (LONGLONG) utcTime.QuadPart) / TicksPerMs); |
84 | 125 | } |
85 | 126 | return 0.0; |
86 | 127 | #elif defined (__GNUC__) || defined (__clang__) |
|
0 commit comments