Skip to content

Commit 4aae4f7

Browse files
committed
Add d3.time.scale.utc.
Also fix a bug in d3.time.hour in regards to daylight savings. Also fix a number of tests that weren't testing the desired functionality.
1 parent f32995e commit 4aae4f7

19 files changed

Lines changed: 848 additions & 75 deletions

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ d3.time.js: \
172172
src/time/year.js \
173173
src/time/years.js \
174174
src/time/scale.js \
175+
src/time/scale-utc.js \
175176
src/end.js
176177

177178
d3.geom.js: \
@@ -232,6 +233,7 @@ test: \
232233
test/time/test-parse-utc.test \
233234
test/time/test-parse.test \
234235
test/time/test-scale.test \
236+
test/time/test-scale-utc.test \
235237
test/time/test-second.test \
236238
test/time/test-seconds.test \
237239
test/time/test-week.test \

d3.time.js

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,8 @@ d3.time.minute.utc = d3.time.minute;d3.time.minutes = d3_time_range(d3.time.minu
392392
});
393393

394394
d3.time.minutes.utc = d3.time.minutes;d3.time.hour = function(date) {
395-
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours());
395+
var offset = date.getTimezoneOffset() / 60;
396+
return new Date((~~(date / 36e5 - offset) + offset) * 36e5);
396397
};
397398

398399
d3.time.hour.utc = function(date) {
@@ -463,7 +464,7 @@ d3.time.years.utc = d3_time_range(d3.time.year.utc, function(date) {
463464
date.setUTCFullYear(date.getUTCFullYear() + 1);
464465
});
465466
// TODO nice
466-
d3.time.scale = function() {
467+
function d3_time_scale(methods, format) {
467468
var linear = d3.scale.linear();
468469

469470
function scale(x) {
@@ -486,11 +487,11 @@ d3.time.scale = function() {
486487
target = span / m;
487488
i = d3.bisect(d3_time_scaleSteps, target, 1, d3_time_scaleSteps.length - 1);
488489
if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i;
489-
return d3_time_scaleMethods[i](extent[0], extent[1]);
490+
return methods[i](extent[0], extent[1]);
490491
};
491492

492493
scale.tickFormat = function() {
493-
return d3_time_scaleFormat;
494+
return format;
494495
};
495496

496497
// TOOD expose d3_scale_linear_rebind?
@@ -500,7 +501,7 @@ d3.time.scale = function() {
500501
scale.clamp = d3.rebind(scale, linear.clamp);
501502

502503
return scale;
503-
};
504+
}
504505

505506
// TODO expose d3_scaleExtent?
506507
function d3_time_scaleExtent(domain) {
@@ -512,21 +513,13 @@ function d3_time_scaleDate(t) {
512513
return new Date(t);
513514
}
514515

515-
var d3_time_scaleFormats = [
516-
[d3.time.format("%Y"), function(d) { return true; }],
517-
[d3.time.format("%B"), function(d) { return d.getMonth(); }],
518-
[d3.time.format("%b %d"), function(d) { return d.getDate() != 1; }],
519-
[d3.time.format("%a %d"), function(d) { return d.getDay() && d.getDate() != 1; }],
520-
[d3.time.format("%I %p"), function(d) { return d.getHours(); }],
521-
[d3.time.format("%I:%M"), function(d) { return d.getMinutes(); }],
522-
[d3.time.format(":%S"), function(d) { return d.getSeconds() || d.getMilliseconds(); }]
523-
];
524-
525-
var d3_time_scaleFormat = function(date) {
526-
var i = d3_time_scaleFormats.length - 1, f = d3_time_scaleFormats[i];
527-
while (!f[1](date)) f = d3_time_scaleFormats[--i];
528-
return f[0](date);
529-
};
516+
function d3_time_scaleFormat(formats) {
517+
return function(date) {
518+
var i = formats.length - 1, f = formats[i];
519+
while (!f[1](date)) f = formats[--i];
520+
return f[0](date);
521+
};
522+
}
530523

531524
var d3_time_scaleSteps = [
532525
1e3, // 1-second
@@ -549,7 +542,7 @@ var d3_time_scaleSteps = [
549542
31536e6 // 1-year
550543
];
551544

552-
var d3_time_scaleMethods = [
545+
var d3_time_scaleLocalMethods = [
553546
d3.time.seconds,
554547
function(a, b) { return d3.time.seconds(a, b).filter(function(t) { return !(t.getSeconds() % 5); }); },
555548
function(a, b) { return d3.time.seconds(a, b).filter(function(t) { return !(t.getSeconds() % 15); }); },
@@ -570,9 +563,55 @@ var d3_time_scaleMethods = [
570563
d3.time.years
571564
];
572565

573-
function d3_time_scaleFilter(method, filter) {
574-
return function(a, b) {
575-
return method(a, b).filter(filter);
576-
};
577-
}
566+
var d3_time_scaleLocalFormats = [
567+
[d3.time.format("%Y"), function(d) { return true; }],
568+
[d3.time.format("%B"), function(d) { return d.getMonth(); }],
569+
[d3.time.format("%b %d"), function(d) { return d.getDate() != 1; }],
570+
[d3.time.format("%a %d"), function(d) { return d.getDay() && d.getDate() != 1; }],
571+
[d3.time.format("%I %p"), function(d) { return d.getHours(); }],
572+
[d3.time.format("%I:%M"), function(d) { return d.getMinutes(); }],
573+
[d3.time.format(":%S"), function(d) { return d.getSeconds() || d.getMilliseconds(); }]
574+
];
575+
576+
var d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);
577+
578+
d3.time.scale = function() {
579+
return d3_time_scale(d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
580+
};
581+
var d3_time_scaleUTCMethods = [
582+
d3.time.seconds.utc,
583+
function(a, b) { return d3.time.seconds.utc(a, b).filter(function(t) { return !(t.getUTCSeconds() % 5); }); },
584+
function(a, b) { return d3.time.seconds.utc(a, b).filter(function(t) { return !(t.getUTCSeconds() % 15); }); },
585+
function(a, b) { return d3.time.seconds.utc(a, b).filter(function(t) { return !(t.getUTCSeconds() % 30); }); },
586+
d3.time.minutes.utc,
587+
function(a, b) { return d3.time.minutes.utc(a, b).filter(function(t) { return !(t.getUTCMinutes() % 5); }); },
588+
function(a, b) { return d3.time.minutes.utc(a, b).filter(function(t) { return !(t.getUTCMinutes() % 15); }); },
589+
function(a, b) { return d3.time.minutes.utc(a, b).filter(function(t) { return !(t.getUTCMinutes() % 30); }); },
590+
d3.time.hours.utc,
591+
function(a, b) { return d3.time.hours.utc(a, b).filter(function(t) { return !(t.getUTCHours() % 3); }); },
592+
function(a, b) { return d3.time.hours.utc(a, b).filter(function(t) { return !(t.getUTCHours() % 6); }); },
593+
function(a, b) { return d3.time.hours.utc(a, b).filter(function(t) { return !(t.getUTCHours() % 12); }); },
594+
d3.time.days.utc,
595+
function(a, b) { return d3.time.days.utc(a, b).filter(function(t) { return t.getUTCDate() % 2; }); },
596+
d3.time.weeks.utc,
597+
d3.time.months.utc,
598+
function(a, b) { return d3.time.months.utc(a, b).filter(function(t) { return !(t.getUTCMonth() % 3); }); },
599+
d3.time.years.utc
600+
];
601+
602+
var d3_time_scaleUTCFormats = [
603+
[d3.time.format.utc("%Y"), function(d) { return true; }],
604+
[d3.time.format.utc("%B"), function(d) { return d.getUTCMonth(); }],
605+
[d3.time.format.utc("%b %d"), function(d) { return d.getUTCDate() != 1; }],
606+
[d3.time.format.utc("%a %d"), function(d) { return d.getUTCDay() && d.getUTCDate() != 1; }],
607+
[d3.time.format.utc("%I %p"), function(d) { return d.getUTCHours(); }],
608+
[d3.time.format.utc("%I:%M"), function(d) { return d.getUTCMinutes(); }],
609+
[d3.time.format.utc(":%S"), function(d) { return d.getUTCSeconds() || d.getUTCMilliseconds(); }]
610+
];
611+
612+
var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);
613+
614+
d3.time.scale.utc = function() {
615+
return d3_time_scale(d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);
616+
};
578617
})();

d3.time.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/time/hour.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
d3.time.hour = function(date) {
2-
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours());
2+
var offset = date.getTimezoneOffset() / 60;
3+
return new Date((~~(date / 36e5 - offset) + offset) * 36e5);
34
};
45

56
d3.time.hour.utc = function(date) {

src/time/scale-utc.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
var d3_time_scaleUTCMethods = [
2+
d3.time.seconds.utc,
3+
function(a, b) { return d3.time.seconds.utc(a, b).filter(function(t) { return !(t.getUTCSeconds() % 5); }); },
4+
function(a, b) { return d3.time.seconds.utc(a, b).filter(function(t) { return !(t.getUTCSeconds() % 15); }); },
5+
function(a, b) { return d3.time.seconds.utc(a, b).filter(function(t) { return !(t.getUTCSeconds() % 30); }); },
6+
d3.time.minutes.utc,
7+
function(a, b) { return d3.time.minutes.utc(a, b).filter(function(t) { return !(t.getUTCMinutes() % 5); }); },
8+
function(a, b) { return d3.time.minutes.utc(a, b).filter(function(t) { return !(t.getUTCMinutes() % 15); }); },
9+
function(a, b) { return d3.time.minutes.utc(a, b).filter(function(t) { return !(t.getUTCMinutes() % 30); }); },
10+
d3.time.hours.utc,
11+
function(a, b) { return d3.time.hours.utc(a, b).filter(function(t) { return !(t.getUTCHours() % 3); }); },
12+
function(a, b) { return d3.time.hours.utc(a, b).filter(function(t) { return !(t.getUTCHours() % 6); }); },
13+
function(a, b) { return d3.time.hours.utc(a, b).filter(function(t) { return !(t.getUTCHours() % 12); }); },
14+
d3.time.days.utc,
15+
function(a, b) { return d3.time.days.utc(a, b).filter(function(t) { return t.getUTCDate() % 2; }); },
16+
d3.time.weeks.utc,
17+
d3.time.months.utc,
18+
function(a, b) { return d3.time.months.utc(a, b).filter(function(t) { return !(t.getUTCMonth() % 3); }); },
19+
d3.time.years.utc
20+
];
21+
22+
var d3_time_scaleUTCFormats = [
23+
[d3.time.format.utc("%Y"), function(d) { return true; }],
24+
[d3.time.format.utc("%B"), function(d) { return d.getUTCMonth(); }],
25+
[d3.time.format.utc("%b %d"), function(d) { return d.getUTCDate() != 1; }],
26+
[d3.time.format.utc("%a %d"), function(d) { return d.getUTCDay() && d.getUTCDate() != 1; }],
27+
[d3.time.format.utc("%I %p"), function(d) { return d.getUTCHours(); }],
28+
[d3.time.format.utc("%I:%M"), function(d) { return d.getUTCMinutes(); }],
29+
[d3.time.format.utc(":%S"), function(d) { return d.getUTCSeconds() || d.getUTCMilliseconds(); }]
30+
];
31+
32+
var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);
33+
34+
d3.time.scale.utc = function() {
35+
return d3_time_scale(d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);
36+
};

src/time/scale.js

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// TODO nice
2-
d3.time.scale = function() {
2+
function d3_time_scale(methods, format) {
33
var linear = d3.scale.linear();
44

55
function scale(x) {
@@ -22,11 +22,11 @@ d3.time.scale = function() {
2222
target = span / m;
2323
i = d3.bisect(d3_time_scaleSteps, target, 1, d3_time_scaleSteps.length - 1);
2424
if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i;
25-
return d3_time_scaleMethods[i](extent[0], extent[1]);
25+
return methods[i](extent[0], extent[1]);
2626
};
2727

2828
scale.tickFormat = function() {
29-
return d3_time_scaleFormat;
29+
return format;
3030
};
3131

3232
// TOOD expose d3_scale_linear_rebind?
@@ -36,7 +36,7 @@ d3.time.scale = function() {
3636
scale.clamp = d3.rebind(scale, linear.clamp);
3737

3838
return scale;
39-
};
39+
}
4040

4141
// TODO expose d3_scaleExtent?
4242
function d3_time_scaleExtent(domain) {
@@ -48,21 +48,13 @@ function d3_time_scaleDate(t) {
4848
return new Date(t);
4949
}
5050

51-
var d3_time_scaleFormats = [
52-
[d3.time.format("%Y"), function(d) { return true; }],
53-
[d3.time.format("%B"), function(d) { return d.getMonth(); }],
54-
[d3.time.format("%b %d"), function(d) { return d.getDate() != 1; }],
55-
[d3.time.format("%a %d"), function(d) { return d.getDay() && d.getDate() != 1; }],
56-
[d3.time.format("%I %p"), function(d) { return d.getHours(); }],
57-
[d3.time.format("%I:%M"), function(d) { return d.getMinutes(); }],
58-
[d3.time.format(":%S"), function(d) { return d.getSeconds() || d.getMilliseconds(); }]
59-
];
60-
61-
var d3_time_scaleFormat = function(date) {
62-
var i = d3_time_scaleFormats.length - 1, f = d3_time_scaleFormats[i];
63-
while (!f[1](date)) f = d3_time_scaleFormats[--i];
64-
return f[0](date);
65-
};
51+
function d3_time_scaleFormat(formats) {
52+
return function(date) {
53+
var i = formats.length - 1, f = formats[i];
54+
while (!f[1](date)) f = formats[--i];
55+
return f[0](date);
56+
};
57+
}
6658

6759
var d3_time_scaleSteps = [
6860
1e3, // 1-second
@@ -85,7 +77,7 @@ var d3_time_scaleSteps = [
8577
31536e6 // 1-year
8678
];
8779

88-
var d3_time_scaleMethods = [
80+
var d3_time_scaleLocalMethods = [
8981
d3.time.seconds,
9082
function(a, b) { return d3.time.seconds(a, b).filter(function(t) { return !(t.getSeconds() % 5); }); },
9183
function(a, b) { return d3.time.seconds(a, b).filter(function(t) { return !(t.getSeconds() % 15); }); },
@@ -106,8 +98,18 @@ var d3_time_scaleMethods = [
10698
d3.time.years
10799
];
108100

109-
function d3_time_scaleFilter(method, filter) {
110-
return function(a, b) {
111-
return method(a, b).filter(filter);
112-
};
113-
}
101+
var d3_time_scaleLocalFormats = [
102+
[d3.time.format("%Y"), function(d) { return true; }],
103+
[d3.time.format("%B"), function(d) { return d.getMonth(); }],
104+
[d3.time.format("%b %d"), function(d) { return d.getDate() != 1; }],
105+
[d3.time.format("%a %d"), function(d) { return d.getDay() && d.getDate() != 1; }],
106+
[d3.time.format("%I %p"), function(d) { return d.getHours(); }],
107+
[d3.time.format("%I:%M"), function(d) { return d.getMinutes(); }],
108+
[d3.time.format(":%S"), function(d) { return d.getSeconds() || d.getMilliseconds(); }]
109+
];
110+
111+
var d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);
112+
113+
d3.time.scale = function() {
114+
return d3_time_scale(d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
115+
};

test/time/test-days.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ d3.time.days(parse("2011-11-05T07:00:00Z"), parse("2011-11-07T11:00:00Z")).forEa
1818
console.log("");
1919

2020
console.log("days.utc(2010-12-30T22:00:00Z, 2011-01-02T02:00:00Z):");
21-
d3.time.days(parse("2010-12-30T22:00:00Z"), parse("2011-01-02T02:00:00Z")).forEach(log);
21+
d3.time.days.utc(parse("2010-12-30T22:00:00Z"), parse("2011-01-02T02:00:00Z")).forEach(log);
2222
console.log("");
2323

2424
function log(date) {

test/time/test-days.out

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ days(2011-11-05T07:00:00Z, 2011-11-07T11:00:00Z):
1414
Mon Nov 07 2011 00:00:00 GMT-0800 (PST)
1515

1616
days.utc(2010-12-30T22:00:00Z, 2011-01-02T02:00:00Z):
17-
Fri Dec 31 2010 00:00:00 GMT-0800 (PST)
18-
Sat Jan 01 2011 00:00:00 GMT-0800 (PST)
17+
Thu Dec 30 2010 16:00:00 GMT-0800 (PST)
18+
Fri Dec 31 2010 16:00:00 GMT-0800 (PST)
19+
Sat Jan 01 2011 16:00:00 GMT-0800 (PST)
1920

test/time/test-hour.js

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,48 @@ console.log(" 2011-11-06T09:00:00Z -> " + format(d3.time.hour(parse("2011-11-06
1818
console.log(" 2011-11-06T10:00:00Z -> " + format(d3.time.hour(parse("2011-11-06T10:00:00Z"))));
1919
console.log("");
2020

21+
var tz = process.env.TZ;
22+
try {
23+
process.env.TZ = "Asia/Kathmandu"; new Date().toString();
24+
console.log("hour.npt:");
25+
console.log(" 2010-12-31T23:59:59Z -> " + format(d3.time.hour(parse("2010-12-31T23:59:59Z"))));
26+
console.log(" 2011-01-01T00:00:00Z -> " + format(d3.time.hour(parse("2011-01-01T00:00:00Z"))));
27+
console.log(" 2011-01-01T00:59:00Z -> " + format(d3.time.hour(parse("2011-01-01T00:59:00Z"))));
28+
console.log(" 2011-01-01T01:00:00Z -> " + format(d3.time.hour(parse("2011-01-01T01:00:00Z"))));
29+
console.log(" 2011-03-13T08:00:00Z -> " + format(d3.time.hour(parse("2011-03-13T08:00:00Z"))));
30+
console.log(" 2011-03-13T09:00:00Z -> " + format(d3.time.hour(parse("2011-03-13T09:00:00Z"))));
31+
console.log(" 2011-03-13T10:00:00Z -> " + format(d3.time.hour(parse("2011-03-13T10:00:00Z"))));
32+
console.log(" 2011-11-06T08:00:00Z -> " + format(d3.time.hour(parse("2011-11-06T08:00:00Z"))));
33+
console.log(" 2011-11-06T09:00:00Z -> " + format(d3.time.hour(parse("2011-11-06T09:00:00Z"))));
34+
console.log(" 2011-11-06T10:00:00Z -> " + format(d3.time.hour(parse("2011-11-06T10:00:00Z"))));
35+
console.log("");
36+
37+
process.env.TZ = "Asia/Calcutta"; new Date().toString();
38+
console.log("hour.ist:");
39+
console.log(" 2010-12-31T23:59:59Z -> " + format(d3.time.hour(parse("2010-12-31T23:59:59Z"))));
40+
console.log(" 2011-01-01T00:00:00Z -> " + format(d3.time.hour(parse("2011-01-01T00:00:00Z"))));
41+
console.log(" 2011-01-01T00:59:00Z -> " + format(d3.time.hour(parse("2011-01-01T00:59:00Z"))));
42+
console.log(" 2011-01-01T01:00:00Z -> " + format(d3.time.hour(parse("2011-01-01T01:00:00Z"))));
43+
console.log(" 2011-03-13T08:00:00Z -> " + format(d3.time.hour(parse("2011-03-13T08:00:00Z"))));
44+
console.log(" 2011-03-13T09:00:00Z -> " + format(d3.time.hour(parse("2011-03-13T09:00:00Z"))));
45+
console.log(" 2011-03-13T10:00:00Z -> " + format(d3.time.hour(parse("2011-03-13T10:00:00Z"))));
46+
console.log(" 2011-11-06T08:00:00Z -> " + format(d3.time.hour(parse("2011-11-06T08:00:00Z"))));
47+
console.log(" 2011-11-06T09:00:00Z -> " + format(d3.time.hour(parse("2011-11-06T09:00:00Z"))));
48+
console.log(" 2011-11-06T10:00:00Z -> " + format(d3.time.hour(parse("2011-11-06T10:00:00Z"))));
49+
console.log("");
50+
} finally {
51+
process.env.TZ = tz;
52+
}
53+
2154
console.log("hour.utc:");
2255
console.log(" 2010-12-31T23:59:59Z -> " + format(d3.time.hour.utc(parse("2010-12-31T23:59:59Z"))));
2356
console.log(" 2011-01-01T00:00:00Z -> " + format(d3.time.hour.utc(parse("2011-01-01T00:00:00Z"))));
2457
console.log(" 2011-01-01T00:59:00Z -> " + format(d3.time.hour.utc(parse("2011-01-01T00:59:00Z"))));
2558
console.log(" 2011-01-01T01:00:00Z -> " + format(d3.time.hour.utc(parse("2011-01-01T01:00:00Z"))));
26-
console.log(" 2011-03-13T08:00:00Z -> " + format(d3.time.hour(parse("2011-03-13T08:00:00Z"))));
27-
console.log(" 2011-03-13T09:00:00Z -> " + format(d3.time.hour(parse("2011-03-13T09:00:00Z"))));
28-
console.log(" 2011-03-13T10:00:00Z -> " + format(d3.time.hour(parse("2011-03-13T10:00:00Z"))));
29-
console.log(" 2011-11-06T08:00:00Z -> " + format(d3.time.hour(parse("2011-11-06T08:00:00Z"))));
30-
console.log(" 2011-11-06T09:00:00Z -> " + format(d3.time.hour(parse("2011-11-06T09:00:00Z"))));
31-
console.log(" 2011-11-06T10:00:00Z -> " + format(d3.time.hour(parse("2011-11-06T10:00:00Z"))));
59+
console.log(" 2011-03-13T08:00:00Z -> " + format(d3.time.hour.utc(parse("2011-03-13T08:00:00Z"))));
60+
console.log(" 2011-03-13T09:00:00Z -> " + format(d3.time.hour.utc(parse("2011-03-13T09:00:00Z"))));
61+
console.log(" 2011-03-13T10:00:00Z -> " + format(d3.time.hour.utc(parse("2011-03-13T10:00:00Z"))));
62+
console.log(" 2011-11-06T08:00:00Z -> " + format(d3.time.hour.utc(parse("2011-11-06T08:00:00Z"))));
63+
console.log(" 2011-11-06T09:00:00Z -> " + format(d3.time.hour.utc(parse("2011-11-06T09:00:00Z"))));
64+
console.log(" 2011-11-06T10:00:00Z -> " + format(d3.time.hour.utc(parse("2011-11-06T10:00:00Z"))));
3265
console.log("");

0 commit comments

Comments
 (0)