Skip to content

Commit a3a16c4

Browse files
committed
Revise implementation of jerry_port_get_local_time_zone_adjustment on Win32
Handle is_utc and not is_utc properly. Handle the limitation of Win32 date API properly. JerryScript-DCO-1.0-Signed-off-by: Yonggang Luo [email protected]
1 parent 2a6917b commit a3a16c4

File tree

2 files changed

+58
-16
lines changed

2 files changed

+58
-16
lines changed

jerry-port/default/default-date.c

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,20 @@
2929
#include "jerryscript-port-default.h"
3030

3131
#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 */
3446

3547
/* https://support.microsoft.com/en-us/help/167296/how-to-convert-a-unix-time-t-to-a-win32-filetime-or-systemtime */
3648
static void UnixTimeMsToFileTime (double t, LPFILETIME pft)
@@ -60,27 +72,56 @@ double jerry_port_get_local_time_zone_adjustment (double unix_ms, /**< ms since
6072
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 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+
}
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+
/* Like above, do not use the last supported day */
92+
if (unix_ms > (double) UnixEpochOfDate_30827_12_29)
7093
{
71-
fileTime.dwHighDateTime = 0;
72-
fileTime.dwLowDateTime = 0;
94+
unix_ms = (double) 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__)

tests/jerry/date-getters.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ assert (isNaN (d.getTimezoneOffset()));
9797
/* 5. test case */
9898
assert (new Date(2013, -1).getMonth() === 11);
9999
assert (new Date(-2, -2).getFullYear() === -3);
100+
assert (new Date(30888, 2).getFullYear() === 30888);
100101
assert (new Date(-1, -1).getFullYear() === -2);
101102
assert (new Date(-1, -1, -1).getMonth() === 10);
102103
assert (new Date(-1, -1, -1, -1).getDate() === 28);

0 commit comments

Comments
 (0)