Bug 1346211 - Part 1: Avoid returning negative zero for time components with dates before 1970. r=Waldo
authorAndré Bargull <andre.bargull@gmail.com>
Thu, 16 Aug 2018 08:26:26 -0700
changeset 487322 b5c5bbed871f65fea01fbc25047c1865a23d6553
parent 487321 9cef845a1039dc4ca84ead1240a7361049e4b60f
child 487323 62d58886e8d759f52c871a82dbe4d9c2a266c0c7
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1346211
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1346211 - Part 1: Avoid returning negative zero for time components with dates before 1970. r=Waldo
js/src/jsdate.cpp
js/src/tests/non262/Date/time-components-negative-zero.js
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -116,29 +116,40 @@ static Atomic<JS::ReduceMicrosecondTimeP
  *
  *     setDay
  *     before
  *     after
  *     equals
  *     hashCode
  */
 
+// ES2019 draft rev 0ceb728a1adbffe42b26972a6541fd7f398b1557
+// 5.2.5 Mathematical Operations
+static inline double
+PositiveModulo(double dividend, double divisor)
+{
+    MOZ_ASSERT(divisor > 0);
+    MOZ_ASSERT(IsFinite(divisor));
+
+    double result = fmod(dividend, divisor);
+    if (result < 0)
+        result += divisor;
+    return result + (+0.0);
+}
+
 static inline double
 Day(double t)
 {
     return floor(t / msPerDay);
 }
 
 static double
 TimeWithinDay(double t)
 {
-    double result = fmod(t, msPerDay);
-    if (result < 0)
-        result += msPerDay;
-    return result;
+    return PositiveModulo(t, msPerDay);
 }
 
 /* ES5 15.9.1.3. */
 static inline bool
 IsLeapYear(double year)
 {
     MOZ_ASSERT(ToInteger(year) == year);
     return fmod(year, 4) == 0 && (fmod(year, 100) != 0 || fmod(year, 400) == 0);
@@ -335,19 +346,17 @@ MakeDay(double year, double month, doubl
     double y = ToInteger(year);
     double m = ToInteger(month);
     double dt = ToInteger(date);
 
     /* Step 5. */
     double ym = y + floor(m / 12);
 
     /* Step 6. */
-    int mn = int(fmod(m, 12.0));
-    if (mn < 0)
-        mn += 12;
+    int mn = int(PositiveModulo(m, 12));
 
     /* Steps 7-8. */
     bool leap = IsLeapYear(ym);
 
     double yearday = floor(TimeFromYear(ym) / msPerDay);
     double monthday = DayFromMonth(mn, leap);
 
     return yearday + monthday + dt - 1;
@@ -523,47 +532,35 @@ UTC(double t)
 
     return t - AdjustTime(t - DateTimeInfo::localTZA() - msPerHour);
 }
 
 /* ES5 15.9.1.10. */
 static double
 HourFromTime(double t)
 {
-    double result = fmod(floor(t/msPerHour), HoursPerDay);
-    if (result < 0)
-        result += HoursPerDay;
-    return result;
+    return PositiveModulo(floor(t/msPerHour), HoursPerDay);
 }
 
 static double
 MinFromTime(double t)
 {
-    double result = fmod(floor(t / msPerMinute), MinutesPerHour);
-    if (result < 0)
-        result += MinutesPerHour;
-    return result;
+    return PositiveModulo(floor(t / msPerMinute), MinutesPerHour);
 }
 
 static double
 SecFromTime(double t)
 {
-    double result = fmod(floor(t / msPerSecond), SecondsPerMinute);
-    if (result < 0)
-        result += SecondsPerMinute;
-    return result;
+    return PositiveModulo(floor(t / msPerSecond), SecondsPerMinute);
 }
 
 static double
 msFromTime(double t)
 {
-    double result = fmod(t, msPerSecond);
-    if (result < 0)
-        result += msPerSecond;
-    return result;
+    return PositiveModulo(t, msPerSecond);
 }
 
 /* ES5 15.9.1.11. */
 static double
 MakeTime(double hour, double min, double sec, double ms)
 {
     /* Step 1. */
     if (!IsFinite(hour) ||
new file mode 100644
--- /dev/null
+++ b/js/src/tests/non262/Date/time-components-negative-zero.js
@@ -0,0 +1,18 @@
+// Don't return negative zero for get[Hours,Minutes,Seconds,Milliseconds] for dates before 1970.
+
+let date = new Date(1955, 0, 1);
+assertEq(date.getTime() < 0, true);
+assertEq(date.getHours(), +0);
+assertEq(date.getMinutes(), +0);
+assertEq(date.getSeconds(), +0);
+assertEq(date.getMilliseconds(), +0);
+
+let utc = new Date(Date.UTC(1955, 0, 1));
+assertEq(utc.getTime() < 0, true);
+assertEq(utc.getUTCHours(), +0);
+assertEq(utc.getUTCMinutes(), +0);
+assertEq(utc.getUTCSeconds(), +0);
+assertEq(utc.getUTCMilliseconds(), +0);
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);