mbostock/d3 — Issue #389: d3.time intervals are not correct
Author: nross83
Created: 2011-11-24 00:47:00+00:00
State: open

I found a bug while trying to add an x axis to a line chart. If I try to specify a 2 day gap between labels I run into an issue when I span between months that have 31 days. In the example below, I want to insert 3 evenly spaced labels in a 6 day period (Oct 29 - Nov 3). I'm expecting to see labels at Oct 29, Oct 31, and Nov 2. Instead I see labels at Oct 29, Oct 31, and Nov 1. See the test case below.

var data = [new Date(2011, 9, 29), new Date(2011, 9, 30), new Date(2011, 9, 31), new Date(2011, 10, 1), new Date(2011, 10, 2), new Date(2011, 10, 3)];
var xScale = d3.time.scale().range([0, 1000]).domain([data[0], data[data.length - 1]]);
var xAxis = d3.svg.axis().scale(xScale).tickFormat(d3.time.format('%b %d')).ticks(d3.time.days, 2);

var vis = d3.select('body')
.append('svg:svg')
.attr('width', 1000)
.attr('height', 250)
.append('svg:g')
.attr('transform', 'translate(30, 30)');

vis.append('svg:g')
.attr('class', 'xTick')
.call(xAxis);

After digging around through the source code, I think the problem lies in the d3_time_formatIsoNative.toString function in d3.time.js. Line 404's fuction number(date) subtracts 1 from date.getDate() and then tries to mod by 2. If the result is zero, the date will be included on the axis. So Oct 31 becomes 30 % 2 which passes. Then, Nov 1 becomes 0 % 2 which also passes. So I get two labels in a row when I shouldn't be. This function might need to include some logic to handle these specific cases.

Thanks so much for D3.js! It is an incredible library and I'm hoping to use it many many times in the future.

- Nate