Fix some more DST issues
authorDan Vanderkam <danvdk@gmail.com>
Mon, 18 Feb 2013 02:17:51 +0000 (21:17 -0500)
committerDan Vanderkam <danvdk@gmail.com>
Mon, 18 Feb 2013 02:17:51 +0000 (21:17 -0500)
auto_tests/tests/axis_labels.js
dygraph-tickers.js
tests/daylight-savings.html

index a40a1d2..c95f35a 100644 (file)
@@ -782,4 +782,48 @@ AxisLabelsTestCase.prototype.testLabelsCrossDstChange = function() {
   for (var i = 0; i < xLabels.length; i++) {
     assertTrue(okLabels[xLabels[i]]);
   }
+
+  // This range had issues of its own on tests/daylight-savings.html.
+  g.updateOptions({
+    dateWindow: [1289109997722.8127, 1289261208937.7659]
+  });
+  xLabels = Util.getXLabels();
+  for (var i = 0; i < xLabels.length; i++) {
+    assertTrue(okLabels[xLabels[i]]);
+  }
+};
+
+
+// Tests data which crosses a "fall back" at a high enough frequency that you
+// can see both 1:00 A.M.s.
+AxisLabelsTestCase.prototype.testLabelsCrossDstChangeHighFreq = function() {
+  // Generate data which crosses the EST/EDT boundary.
+  var dst_data = [];
+  var base_ms = 1383454200000;
+  for (var x = base_ms; x < base_ms + 1000 * 60 * 80; x += 1000) {
+    dst_data.push([new Date(x), x]);
+  }
+
+  var g = new Dygraph(
+          document.getElementById("graph"),
+          dst_data,
+      { width: 1024, labels: ['Date', 'Value'] }
+      );
+
+  assertEquals([
+    '00:50', '00:55',
+    '01:00', '01:05', '01:10', '01:15', '01:20', '01:25',
+    '01:30', '01:35', '01:40', '01:45', '01:50', '01:55',
+    '01:00', '01:05'  // 1 AM number two!
+  ], Util.getXLabels());
+
+  // Now zoom past the initial 1 AM. This used to cause trouble.
+  g.updateOptions({
+    dateWindow: [1383454200000 + 15*60*1000, g.xAxisExtremes()[1]]}
+  );
+  assertEquals([
+    '01:05', '01:10', '01:15', '01:20', '01:25',
+    '01:30', '01:35', '01:40', '01:45', '01:50', '01:55',
+    '01:00', '01:05'  // 1 AM number two!
+  ], Util.getXLabels());
 };
index 65355e5..e57e8bd 100644 (file)
@@ -340,6 +340,25 @@ Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) {
   var ticks = [];
   var t;
 
+  var setters = {
+    ms: Date.prototype.setMilliseconds,
+    s: Date.prototype.setSeconds,
+    m: Date.prototype.setMinutes,
+    h: Date.prototype.setHours
+  };
+  var safeSet = function(d, parts) {
+    var tz = d.getTimezoneOffset();
+    for (var k in parts) {
+      if (!parts.hasOwnProperty(k)) continue;
+      var setter = setters[k];
+      if (!setter) throw "Invalid setter: " + k;
+      setter.call(d, parts[k]);
+      if (d.getTimezoneOffset() != tz) {
+        d.setTime(d.getTime() + (tz - d.getTimezoneOffset()) * 60 * 1000);
+      }
+    }
+  };
+
   if (granularity < Dygraph.MONTHLY) {
     // Generate one tick mark for every fixed interval of time.
     var spacing = Dygraph.SHORT_SPACINGS[granularity];
@@ -348,21 +367,25 @@ Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) {
     // for this granularity.
     var g = spacing / 1000;
     var d = new Date(start_time);
-    d.setMilliseconds(0);
+    safeSet(d, {ms: 0});
+
     var x;
     if (g <= 60) {  // seconds
-      x = d.getSeconds(); d.setSeconds(x - x % g);
+      x = d.getSeconds();
+      safeSet(d, {s: x - x % g});
     } else {
-      d.setSeconds(0);
+      safeSet(d, {s: 0});
       g /= 60;
       if (g <= 60) {  // minutes
-        x = d.getMinutes(); d.setMinutes(x - x % g);
+        x = d.getMinutes();
+        safeSet(d, {m: x - x % g});
       } else {
-        d.setMinutes(0);
+        safeSet(d, {m: 0});
         g /= 60;
 
         if (g <= 24) {  // days
-          x = d.getHours(); d.setHours(x - x % g);
+          x = d.getHours();
+          d.setHours(x - x % g);
         } else {
           d.setHours(0);
           g /= 24;
@@ -376,13 +399,15 @@ Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) {
     start_time = d.getTime();
 
     var start_offset_min = new Date(start_time).getTimezoneOffset();
+    var check_dst = (spacing >= Dygraph.SHORT_SPACINGS[Dygraph.TWO_HOURLY]);
+
     for (t = start_time; t <= end_time; t += spacing) {
       var d = new Date(t);
 
       // This ensures that we stay on the same hourly "rhythm" across
       // daylight savings transitions. Without this, the ticks could get off
       // by an hour. See tests/daylight-savings.html or issue 147.
-      if (d.getTimezoneOffset() != start_offset_min) {
+      if (check_dst && d.getTimezoneOffset() != start_offset_min) {
         t += (d.getTimezoneOffset() - start_offset_min) * 60 * 1000;
         d = new Date(t);
         start_offset_min = d.getTimezoneOffset();
index 2961883..4e9e4c0 100644 (file)
@@ -36,7 +36,9 @@
 "2010-11-07 00:00:00,177796\n" +
 "2010-11-08 00:00:00,165587\n" +
 "2010-11-09 00:00:00,164380\n",
-          { width: 1024 }
+          {
+            width: 1024
+          }
           );
 
       // Generate data which crosses the EST/EDT boundary.