assertEquals('e', iter.next());
assertFalse(iter.hasNext);
-}
+};
UtilsTestCase.prototype.testIterator_predicate = function() {
var array = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
var array = [];
var iter = Dygraph.createIterator([], 0, 0);
assertFalse(iter.hasNext);
-}
+};
UtilsTestCase.prototype.testIterator_outOfRange = function() {
var array = ['a', 'b', 'c'];
assertEquals('c', iter.next());
assertFalse(iter.hasNext);
-}
+};
// Makes sure full array is tested, and that the predicate isn't called
// with invalid boundaries.
assertEquals('c', iter.next());
assertFalse(iter.hasNext);
assertNull(iter.next());
-}
+};
UtilsTestCase.prototype.testIterator_no_args = function() {
var array = ['a', 'b', 'c'];
assertEquals('c', iter.next());
assertFalse(iter.hasNext);
assertNull(iter.next());
-}
+};
+
+UtilsTestCase.prototype.testDateSet = function() {
+ var base = new Date(1383455100000);
+ var d = new Date(base);
+
+ // A one hour shift -- this is surprising behavior!
+ d.setMilliseconds(10);
+ assertEquals(3600010, d.getTime() - base.getTime());
+
+ // setDateSameTZ compensates for this surprise.
+ d = new Date(base);
+ Dygraph.setDateSameTZ(d, {ms: 10});
+ assertEquals(10, d.getTime() - base.getTime());
+};
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];
// for this granularity.
var g = spacing / 1000;
var d = new Date(start_time);
- safeSet(d, {ms: 0});
+ Dygraph.setDateSameTZ(d, {ms: 0});
var x;
if (g <= 60) { // seconds
x = d.getSeconds();
- safeSet(d, {s: x - x % g});
+ Dygraph.setDateSameTZ(d, {s: x - x % g});
} else {
- safeSet(d, {s: 0});
+ Dygraph.setDateSameTZ(d, {s: 0});
g /= 60;
if (g <= 60) { // minutes
x = d.getMinutes();
- safeSet(d, {m: x - x % g});
+ Dygraph.setDateSameTZ(d, {m: x - x % g});
} else {
- safeSet(d, {m: 0});
+ Dygraph.setDateSameTZ(d, {m: 0});
g /= 60;
if (g <= 24) { // days
}
start_time = d.getTime();
+ // For spacings coarser than two-hourly, we want to ignore daylight
+ // savings transitions to get consistent ticks. For finer-grained ticks,
+ // it's essential to show the DST transition in all its messiness.
var start_offset_min = new Date(start_time).getTimezoneOffset();
var check_dst = (spacing >= Dygraph.SHORT_SPACINGS[Dygraph.TWO_HOURLY]);
return Math.pow(base, exp);
};
+// For Dygraph.setDateSameTZ, below.
+Dygraph.dateSetters = {
+ ms: Date.prototype.setMilliseconds,
+ s: Date.prototype.setSeconds,
+ m: Date.prototype.setMinutes,
+ h: Date.prototype.setHours
+};
+
+/**
+ * This is like calling d.setSeconds(), d.setMinutes(), etc, except that it
+ * adjusts for time zone changes to keep the date/time parts consistent.
+ *
+ * For example, d.getSeconds(), d.getMinutes() and d.getHours() will all be
+ * the same before/after you call setDateSameTZ(d, {ms: 0}). The same is not
+ * true if you call d.setMilliseconds(0).
+ *
+ * @type {function(!Date, Object.<number>)}
+ */
+Dygraph.setDateSameTZ = function(d, parts) {
+ var tz = d.getTimezoneOffset();
+ for (var k in parts) {
+ if (!parts.hasOwnProperty(k)) continue;
+ var setter = Dygraph.dateSetters[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);
+ }
+ }
+};