Reputation: 2849
I'm trying to code an interval round function using the d3.js
time intervals API.
The thing I want to do is fairly simple: write a function that rounds a time to the nearest 6 hours and returns it as a Date
object.
For example:
d3.hour.my6HourRound(new Date)
should return 12:00 todayd3.hour.my6HourRound(new Date)
should return 12:00 todayd3.hour.my6HourRound(new Date)
should return 00:00 tomorrowIt must not be so difficult, but d3.js
api lacks of usage demos in API.
Upvotes: 7
Views: 7654
Reputation: 165
Here's my solution which makes use of built-in d3 functions:
function another6HourRound(date) {
var subHalf = d3.time.hour.offset(date, -3);
var addHalf = d3.time.hour.offset(date, 3);
return d3.time.hours(subHalf, addHalf, 6)[0];
}
Returns the nearest 6 hour interval (on 00, 06, 12, or 18)
Upvotes: 4
Reputation: 2849
Well, I've implemented my own solution. By diving into the source code of D3, I found how they write their time functions. For hour it's like:
d3_time.hour = d3_time_interval(function(date) {
var timezone = date.getTimezoneOffset() / 60;
return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
}, function(date, offset) {
date.setTime(date.getTime() + Math.floor(offset) * 36e5);
}, function(date) {
return date.getHours();
});
d3_time.hours = d3_time.hour.range;
d3_time.hours.utc = d3_time.hour.utc.range;
and I simply write
my6HourRound = function(date) {
var hours = 6;
var timezone = date.getTimezoneOffset() / 60;
return new Date((Math.floor(date / 36e5 / hours - timezone) + timezone) * 36e5 * hours);
}
which works. I'm pretty sure there's a better method which makes this generic using D3 functions. Otherwise, you need to define custom functions for day, month, week, year etc. Therefore I'm not accepting my own question.
I'm looking forward to the one which make it in D3 way.
Upvotes: 2
Reputation: 34288
You are looking for this example: http://bl.ocks.org/mbostock/4149176
Working example for your case: http://bl.ocks.org/musically-ut/7699650
Code from example
function timeFormat(formats) {
return function(date) {
var i = formats.length - 1, f = formats[i];
while (!f[1](date)) f = formats[--i];
return d3.functor(f[0])(date);
};
}
var customTimeFormat = timeFormat([
[d3.time.format("%Y"), function() { return true; }],
[d3.time.format("%B"), function(d) { return d.getMonth(); }],
[d3.time.format("%b %d"), function(d) { return d.getDate() != 1; }],
[d3.time.format("%a %d"), function(d) { return d.getDay() && d.getDate() != 1; }],
[d3.time.format("%I %p"), function(d) { return d.getHours(); }],
[d3.time.format("%I:%M"), function(d) { return d.getMinutes(); }],
[d3.time.format(":%S"), function(d) { return d.getSeconds(); }],
[d3.time.format(".%L"), function(d) { return d.getMilliseconds(); }]
]);
var xAxis = d3.svg.axis()
.scale(x) // x is a scale.
.tickFormat(customTimeFormat);
In your case, you want something of this kind:
var customTimeFormat = timeFormat([
["00:00", function () { return true; }],
["06:00", function (d) { return 3 <= d.getHours() && d.getHours() < 9; }],
["12:00", function (d) { return 9 <= d.getHours() && d.getHours() < 15; }],
["18:00", function (d) { return 15 <= d.getHours() && d.getHours() < 21; }]
]);
Upvotes: 2