Bug 836404 - Provide better timezone support in jstests. r=jwalden
authorAndré Bargull <andrebargull@googlemail.com>
Wed, 03 Apr 2013 12:20:02 -0700
changeset 127697 695eb5588304e963bd3587eb49e592646d7c8453
parent 127696 a65a4e4b385d44b9b7c579515420fb6200f2ef56
child 127698 04f2c0f0a220b409af15722eaec46304979f04ac
push id24512
push userryanvm@gmail.com
push dateFri, 05 Apr 2013 20:13:49 +0000
treeherdermozilla-central@139b6ba547fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs836404
milestone23.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 836404 - Provide better timezone support in jstests. r=jwalden
js/src/tests/ecma/shell.js
--- a/js/src/tests/ecma/shell.js
+++ b/js/src/tests/ecma/shell.js
@@ -3,28 +3,37 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 /*
  * Date functions used by tests in Date suite
  *
  */
+var msPerYear =  31536000000;
 var msPerDay =   86400000;
 var HoursPerDay =  24;
 var MinutesPerHour = 60;
 var SecondsPerMinute = 60;
 var msPerSecond =  1000;
 var msPerMinute =  60000;  // msPerSecond * SecondsPerMinute
 var msPerHour =   3600000; // msPerMinute * MinutesPerHour
-var TZ_DIFF = getTimeZoneDiff();  // offset of tester's timezone from UTC
-var TZ_ADJUST  = TZ_DIFF * msPerHour;
+
 var TZ_PST = -8;  // offset of Pacific Standard Time from UTC
+var TZ_DIFF_RAW = GetRawTimezoneOffset();  // raw offset of tester's timezone from UTC
+var TZ_DIFF = GetTimezoneOffset();  // offset of tester's timezone from UTC
+var PST_DIFF_RAW = TZ_DIFF_RAW - TZ_PST;  // raw offset of tester's timezone from PST
 var PST_DIFF = TZ_DIFF - TZ_PST;  // offset of tester's timezone from PST
+var TZ_ADJUST  = TZ_DIFF_RAW * msPerHour;
 var PST_ADJUST = TZ_PST * msPerHour;
+
+var DST_PERIOD = DaylightSavingPeriod();  // time period when DST is used
+var DST_1970 = DaylightSavingObserved(1970);  // Was DST observed in 1970?
+var DST_1971 = DaylightSavingObserved(1971);  // Was DST observed in 1971?
+
 var TIME_0000  = (function ()
   { // calculate time for year 0
     for ( var time = 0, year = 1969; year >= 0; year-- ) {
       time -= TimeInYear(year);
     }
     return time;
   })();
 var TIME_1970  = 0;
@@ -38,19 +47,81 @@ var TIME_NOW = now.valueOf();  //valueOf
                                //Date.parse() is accurate only to the second
 
 /*
  * Originally, the test suite used a hard-coded value TZ_DIFF = -8.
  * But that was only valid for testers in the Pacific Standard Time Zone!
  * We calculate the proper number dynamically for any tester. We just
  * have to be careful not to use a date subject to Daylight Savings Time...
  */
-function getTimeZoneDiff()
+function GetRawTimezoneOffset()
+{
+  var t1 = new Date(2000, 1, 1).getTimezoneOffset();
+  var t2 = new Date(2000, 1 + 6, 1).getTimezoneOffset();
+  if ((t1 - t2) >= 0) {
+    // 1) timezone without daylight saving time
+    // 2) northern hemisphere with daylight saving time
+    return -t1 / MinutesPerHour;
+  } else {
+    // 3) southern hemisphere with daylight saving time
+    return -t2 / MinutesPerHour;
+  }
+}
+
+/*
+ * Returns the timezone offset, possibly including daylight saving time.
+ * (This function is only used to obtain the relative timezone offset to PST,
+ * see TZ_DIFF and PST_DIFF in adjustResultArray().)
+ */
+function GetTimezoneOffset()
+{
+  return -(new Date(2000, 1, 1).getTimezoneOffset()) / MinutesPerHour;
+}
+
+/*
+ * Determine when daylight saving time is used in the current timezone.
+ */
+function DaylightSavingPeriod()
 {
-  return -((new Date(2000, 1, 1)).getTimezoneOffset())/60;
+  var t1 = new Date(2000, 1, 1).getTimezoneOffset();
+  var t2 = new Date(2000, 1 + 6, 1).getTimezoneOffset();
+  if (t1 == t2) {
+    // timezone without daylight saving time
+    return 0;
+  } else if ((t1 - t2) > 0) {
+    // northern hemisphere with daylight saving time
+    return 1;
+  } else {
+    // southern hemisphere with daylight saving time
+    return -1;
+  }
+}
+
+/*
+ * Test whether daylight time saving was observed in the supplied year
+ */
+function DaylightSavingObserved(y)
+{
+  var t1 = new Date(y, 1, 1).getTimezoneOffset();
+  var t2 = new Date(y, 1 + 6, 1).getTimezoneOffset();
+  return (t1 != t2);
+}
+
+/*
+ * Don't apply DST near start of epoch unless absolutely necessary
+ */
+function IgnoreDaylightSaving(t)
+{
+  if ((0 <= t && t < msPerYear) && !DST_1970) {
+    return true;
+  }
+  if ((msPerYear <= t && t < 2*msPerYear) && !DST_1971) {
+    return true;
+  }
+  return false;
 }
 
 /*
  * Date test "ResultArrays" are hard-coded for Pacific Standard Time.
  * We must adjust them for the tester's own timezone -
  */
 function adjustResultArray(ResultArray, msMode)
 {
@@ -69,24 +140,28 @@ function adjustResultArray(ResultArray, 
    * like dt.getHours() etc. No correction is necessary for dt.getUTCHours() etc.
    *
    * In the second case, it is exactly the other way around -
    */
   if (msMode)
   {
     // The hard-coded UTC milliseconds from Time 0 derives from a UTC date.
     // Shift to the right by the offset between UTC and the tester.
-    var t = ResultArray[TIME]  +  TZ_DIFF*msPerHour;
+    if (IgnoreDaylightSaving(ResultArray[TIME])) {
+      var t = ResultArray[TIME]  +  TZ_DIFF_RAW*msPerHour;
+    } else {
+      var t = ResultArray[TIME]  +  TZ_DIFF*msPerHour;
+    }
 
     // Use our date arithmetic functions to determine the local hour, day, etc.
     ResultArray[HOURS] = HourFromTime(t);
     ResultArray[DAY] = WeekDay(t);
     ResultArray[DATE] = DateFromTime(t);
     ResultArray[MONTH] = MonthFromTime(t);
-    ResultArray[YEAR] = YearFromTime(t); 
+    ResultArray[YEAR] = YearFromTime(t);
   }
   else
   {
     // The hard-coded UTC milliseconds from Time 0 derives from a PST date.
     // Shift to the left by the offset between PST and the tester.
     var t = ResultArray[TIME]  -  PST_DIFF*msPerHour;
 
     // Use our date arithmetic functions to determine the UTC hour, day, etc.
@@ -290,32 +365,46 @@ function SecFromTime( t ) {
   var sec = Math.floor( t / msPerSecond ) % SecondsPerMinute;
   return ( (sec < 0 ) ? SecondsPerMinute + sec : sec );
 }
 function msFromTime( t ) {
   var ms = t % msPerSecond;
   return ( (ms < 0 ) ? msPerSecond + ms : ms );
 }
 function LocalTZA() {
-  return ( TZ_DIFF * msPerHour );
+  return ( TZ_DIFF_RAW * msPerHour );
 }
 function UTC( t ) {
   return ( t - LocalTZA() - DaylightSavingTA(t - LocalTZA()) );
 }
 function LocalTime( t ) {
   return ( t + LocalTZA() + DaylightSavingTA(t) );
 }
 function DaylightSavingTA( t ) {
-  t = t - LocalTZA();
+  if (IgnoreDaylightSaving(t)) {
+    return 0;
+  }
+
+  if (DST_PERIOD > 0) {
+    // northern hemisphere
+    var dst_start = GetDSTStart(t);
+    var dst_end   = GetDSTEnd(t);
 
-  var dst_start = GetDSTStart(t);
-  var dst_end   = GetDSTEnd(t);
+    if ( t >= dst_start && t < dst_end )
+      return msPerHour;
+  } else if (DST_PERIOD < 0) {
+    // southern hemisphere
+    var dst_start = GetDSTStart_Southern(t);
+    var dst_end   = GetDSTEnd_Southern(t);
 
-  if ( t >= dst_start && t < dst_end )
-    return msPerHour;
+    if ( t >= dst_start && t < GetDSTEnd_Southern(t + msPerYear) )
+      return msPerHour;
+    if ( t < dst_end && t >= GetDSTEnd_Southern(t - msPerYear) )
+      return msPerHour;
+  }
 
   return 0;
 }
 
 function GetFirstSundayInMonth( t, m ) {
   var year = YearFromTime(t);
   var leap = InLeapYear(t);
 
@@ -411,16 +500,31 @@ function GetOldDSTStart( t )
   return (GetFirstSundayInMonth(t, 3) + 2*msPerHour - LocalTZA());
 }
 
 function GetOldDSTEnd( t )
 {
   return (GetLastSundayInMonth(t, 9) + 2*msPerHour - LocalTZA());
 }
 
+/*
+ * Daylight saving time start/end date for 'Australia'
+ * (arbitrarily chosen as a representative for the southern hemisphere)
+ */
+
+function GetDSTStart_Southern( t )
+{
+  return (GetFirstSundayInMonth(t, 9) + 2*msPerHour - LocalTZA());
+}
+
+function GetDSTEnd_Southern( t )
+{
+  return (GetFirstSundayInMonth(t, 3) + 2*msPerHour - LocalTZA());
+}
+
 function MakeTime( hour, min, sec, ms ) {
   if ( isNaN( hour ) || isNaN( min ) || isNaN( sec ) || isNaN( ms ) ) {
     return Number.NaN;
   }
 
   hour = ToInteger(hour);
   min  = ToInteger( min);
   sec  = ToInteger( sec);