score:4

Accepted answer

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)

score:2

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; }]
]);

score:2

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.


Related Query

More Query from same tag