Title: [272127] trunk
Revision
272127
Author
[email protected]
Date
2021-01-31 12:48:01 -0800 (Sun, 31 Jan 2021)

Log Message

Date.parse returns non-integral time value
https://bugs.webkit.org/show_bug.cgi?id=220687

Reviewed by Ross Kirsling.

JSTests:

* complex.yaml:
* complex/date-parse-milliseconds.js: Added.
(shouldBe):

Source/WTF:

Use milliseconds instead of seconds as a base unit to avoid floating point rounding for milliseconds.

* wtf/DateMath.cpp:
(WTF::ymdhmsToMilliseconds):
(WTF::parseES5TimePortion):
(WTF::parseES5DateFromNullTerminatedCharacters):
(WTF::parseDateFromNullTerminatedCharacters):
(WTF::ymdhmsToSeconds): Deleted.

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (272126 => 272127)


--- trunk/JSTests/ChangeLog	2021-01-31 20:31:24 UTC (rev 272126)
+++ trunk/JSTests/ChangeLog	2021-01-31 20:48:01 UTC (rev 272127)
@@ -1,3 +1,14 @@
+2021-01-31  Yusuke Suzuki  <[email protected]>
+
+        Date.parse returns non-integral time value
+        https://bugs.webkit.org/show_bug.cgi?id=220687
+
+        Reviewed by Ross Kirsling.
+
+        * complex.yaml:
+        * complex/date-parse-milliseconds.js: Added.
+        (shouldBe):
+
 2021-01-29  Yusuke Suzuki  <[email protected]>
 
         [JSC] Adjust property order of host JSFunction

Added: trunk/JSTests/complex/date-parse-milliseconds.js (0 => 272127)


--- trunk/JSTests/complex/date-parse-milliseconds.js	                        (rev 0)
+++ trunk/JSTests/complex/date-parse-milliseconds.js	2021-01-31 20:48:01 UTC (rev 272127)
@@ -0,0 +1,8 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+shouldBe(Date.parse("2514-06-01T00:00:00.148Z"), 17180035200148);
+shouldBe(Date.parse("2514-06-01T00:00:00.14Z"), 17180035200140);
+shouldBe(Date.parse("2514-06-01T00:00:00.1Z"), 17180035200100);

Modified: trunk/JSTests/complex.yaml (272126 => 272127)


--- trunk/JSTests/complex.yaml	2021-01-31 20:31:24 UTC (rev 272126)
+++ trunk/JSTests/complex.yaml	2021-01-31 20:48:01 UTC (rev 272127)
@@ -40,3 +40,6 @@
 
 - path: complex/timezone-range-cache-with-dst.js
   cmd: runComplexTest [], [], "TZ=America/Los_Angeles", "--useDollarVM=1"
+
+- path: complex/date-parse-milliseconds.js
+  cmd: runComplexTest [], [], "TZ=America/Los_Angeles", "--useDollarVM=1"

Modified: trunk/Source/WTF/ChangeLog (272126 => 272127)


--- trunk/Source/WTF/ChangeLog	2021-01-31 20:31:24 UTC (rev 272126)
+++ trunk/Source/WTF/ChangeLog	2021-01-31 20:48:01 UTC (rev 272127)
@@ -1,3 +1,19 @@
+2021-01-31  Yusuke Suzuki  <[email protected]>
+
+        Date.parse returns non-integral time value
+        https://bugs.webkit.org/show_bug.cgi?id=220687
+
+        Reviewed by Ross Kirsling.
+
+        Use milliseconds instead of seconds as a base unit to avoid floating point rounding for milliseconds.
+
+        * wtf/DateMath.cpp:
+        (WTF::ymdhmsToMilliseconds):
+        (WTF::parseES5TimePortion):
+        (WTF::parseES5DateFromNullTerminatedCharacters):
+        (WTF::parseDateFromNullTerminatedCharacters):
+        (WTF::ymdhmsToSeconds): Deleted.
+
 2021-01-30  Antti Koivisto  <[email protected]>
 
         Enable visibility aware resource load scheduling

Modified: trunk/Source/WTF/wtf/DateMath.cpp (272126 => 272127)


--- trunk/Source/WTF/wtf/DateMath.cpp	2021-01-31 20:31:24 UTC (rev 272126)
+++ trunk/Source/WTF/wtf/DateMath.cpp	2021-01-31 20:48:01 UTC (rev 272127)
@@ -371,19 +371,19 @@
     equivalentYearForDST(2000); // Need to call once to initialize a static used in this function.
 }
 
-static inline double ymdhmsToSeconds(int year, long mon, long day, long hour, long minute, double second)
+static inline double ymdhmsToMilliseconds(int year, long mon, long day, long hour, long minute, long second, double milliseconds)
 {
     int mday = firstDayOfMonth[isLeapYear(year)][mon - 1];
     double ydays = daysFrom1970ToYear(year);
 
-    double dateSeconds = second + minute * secondsPerMinute + hour * secondsPerHour + (mday + day - 1 + ydays) * secondsPerDay;
+    double dateMilliseconds = milliseconds + second * msPerSecond + minute * (secondsPerMinute * msPerSecond) + hour * (secondsPerHour * msPerSecond) + (mday + day - 1 + ydays) * (secondsPerDay * msPerSecond);
 
     // Clamp to EcmaScript standard (ecma262/#sec-time-values-and-time-range) of
     //  +/- 100,000,000 days from 01 January, 1970.
-    if (dateSeconds < -8640000000000.0 || dateSeconds > 8640000000000.0)
+    if (dateMilliseconds < -8640000000000000.0 || dateMilliseconds > 8640000000000000.0)
         return std::numeric_limits<double>::quiet_NaN();
     
-    return dateSeconds;
+    return dateMilliseconds;
 }
 
 // We follow the recommendation of RFC 2822 to consider all
@@ -506,7 +506,7 @@
 // Parses a time with the format HH:mm[:ss[.sss]][Z|(+|-)(00:00|0000|00)].
 // Fractional seconds parsing is lenient, allows any number of digits.
 // Returns 0 if a parse error occurs, else returns the end of the parsed portion of the string.
-static char* parseES5TimePortion(char* currentPosition, long& hours, long& minutes, double& seconds, bool& isLocalTime, long& timeZoneSeconds)
+static char* parseES5TimePortion(char* currentPosition, long& hours, long& minutes, long& seconds, double& milliseconds, bool& isLocalTime, long& timeZoneSeconds)
 {
     isLocalTime = false;
 
@@ -531,14 +531,12 @@
     if (*currentPosition == ':') {
         ++currentPosition;
     
-        long intSeconds;
         if (!isASCIIDigit(*currentPosition))
             return nullptr;
-        if (!parseLong(currentPosition, &postParsePosition, 10, &intSeconds))
+        if (!parseLong(currentPosition, &postParsePosition, 10, &seconds))
             return nullptr;
         if ((postParsePosition - currentPosition) != 2)
             return nullptr;
-        seconds = intSeconds;
         if (*postParsePosition == '.') {
             currentPosition = postParsePosition + 1;
             
@@ -554,7 +552,7 @@
                 return nullptr;
             
             long numFracDigits = postParsePosition - currentPosition;
-            seconds += fracSeconds * pow(10.0, static_cast<double>(-numFracDigits));
+            milliseconds = fracSeconds * pow(10.0, static_cast<double>(-numFracDigits + 3));
         }
         currentPosition = postParsePosition;
     }
@@ -637,7 +635,8 @@
     long day = 1;
     long hours = 0;
     long minutes = 0;
-    double seconds = 0;
+    long seconds = 0;
+    double milliseconds = 0;
     long timeZoneSeconds = 0;
 
     // Parse the date YYYY[-MM[-DD]]
@@ -648,7 +647,7 @@
     // Note: As of ES2016, when a UTC offset is missing, date-time forms are local time while date-only forms are UTC.
     if (*currentPosition == 'T') {
         // Parse the time HH:mm[:ss[.sss]][Z|(+|-)(00:00|0000|00)]
-        currentPosition = parseES5TimePortion(currentPosition + 1, hours, minutes, seconds, isLocalTime, timeZoneSeconds);
+        currentPosition = parseES5TimePortion(currentPosition + 1, hours, minutes, seconds, milliseconds, isLocalTime, timeZoneSeconds);
         if (!currentPosition)
             return std::numeric_limits<double>::quiet_NaN();
     }
@@ -672,13 +671,12 @@
         return std::numeric_limits<double>::quiet_NaN();
     if (seconds < 0 || seconds >= 61)
         return std::numeric_limits<double>::quiet_NaN();
-    if (seconds > 60) {
+    if (seconds == 60) {
         // Discard leap seconds by clamping to the end of a minute.
-        seconds = 60;
+        milliseconds = 0;
     }
         
-    double dateSeconds = ymdhmsToSeconds(year, month, day, hours, minutes, seconds) - timeZoneSeconds;
-    return dateSeconds * msPerSecond;
+    return ymdhmsToMilliseconds(year, month, day, hours, minutes, seconds, milliseconds) - (timeZoneSeconds * msPerSecond);
 }
 
 // Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore.
@@ -983,8 +981,7 @@
     }
     ASSERT(year);
 
-    double dateSeconds = ymdhmsToSeconds(year.value(), month + 1, day, hour, minute, second) - offset * secondsPerMinute;
-    return dateSeconds * msPerSecond;
+    return ymdhmsToMilliseconds(year.value(), month + 1, day, hour, minute, second, 0) - offset * (secondsPerMinute * msPerSecond);
 }
 
 double parseDateFromNullTerminatedCharacters(const char* dateString)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to