I have a large collection of data with various datetimes. Currently I have been able to group all my data to display properly in a local timezone; however, when trying to display this data in a different timezone the lines on a lineChart get choppy and the connection between them is not as smooth as when in a local timezone.
I had found this link here detailing a possible solution, but sadly this won't work without me duplicating my entire dataset with times offset from utc and then once as normal. The data I have is not only used in several charts to gain insights about trends and statistics, but there is a raw table used for display/editing/reviewing specific data members. Thus translating one into a utc time and calculating the time change in utc time would throw the other off.
https://groups.google.com/forum/#!msg/d3-js/iWmP9Npv2Go/xyypdLjWu2QJ
My question is: Is there a way to translate datetime data across timezones and have dc.js respect the timezone you would like to display in. I would like the adjusted graphs to look the same way the local graph looks where the lines are not one-sided based on the timezone.
fiddle: https://jsfiddle.net/spacarar/j0urt9sy/49/
this is the correctly displaying image for my local timezone. The lines are smooth transitions between dates.
This is the incorrectly displaying image for any other timezone (depending on which side of my local changes orientation from leaning left to leaning right)
A simplified version of my data looks something like this:
var data = [
{
value: 42,
datetime: '2019-10-24T07:18:00.000000'
},
{
value: 10,
datetime: '2019-10-24T07:19:12.000000'
},
{
value: 12,
datetime: '2019-10-29T04:18:00.000000'
},
{
value: 8,
datetime: '2019-10-29T09:18:00.000000'
}
]
which I then fake group to fill in any dates that may not be present in the data and translate them using moment-timezone to end up with a data structure similar to this
{
value: 0,
datetime: moment timezone object with full datetime,
date: moment timezone object representing only date (0 hours, minutes, seconds, ms)
}
this fake grouped/fixed data is then used to create the chart with the following code
var ndx = dc.crossfilter(fakeGroupedData)
var dateDim = ndx.dimension(dc.pluck('date'))
var top = dateDim.top(1)[0] ? dateDim.top(1)[0].date : null
var bottom = dateDim.bottom(1)[0] ? dateDim.bottom(1)[0].date : null
var chart = dc.lineChart('#date-chart')
chart.yAxis().tickFormat(dc.d3.format(',.0f'))
chart.xAxis().ticks(10).tickFormat(d => moment(d).format('M/D'))
chart.dimension(dateDim)
.group(dateDim.group().reduceSum(dc.pluck('value')))
.x(dc.d3.scaleTime().domain([bottom, top]).nice())
.elasticY(true)
.renderArea(true)
.render()
A couple of points about your date-filling.
This is not what's normally meant by a "fake group". You're filling in the source data and all of your crossfilter groups are completely "real" :)
There isn't any point in filling at a higher resolution than you intend to show. To simplify the problem, I changed your code to fill by days, and it worked exactly the same:
let start = moment.tz(startDate, tzSelection).startOf('day')
let end = moment.tz(endDate, tzSelection).endOf('day')
let hours = end.diff(start, 'days')
for (let i = 0; i < hours; i++) {
let fakeTime = moment(start).add(i, 'days')
let date = moment(fakeTime.format('YYYY-MM-DD'))
fakeGroupedData.push({
value: 0,
datetime: fakeTime,
date
})
}
It might be easier to use d3-time, since that integrates tighter with dc.js, but I didn't want to make big changes to your code.
However, you are essentially quantizing by day, so you can set up your dimension to quantize to the beginning of the day in the current timezone, and that will fix your chart:
var dateDim = ndx.dimension(d => d3.timeDay(dc.pluck('date')(d)))
If you do this, you don't need to modify your input dates:
el.date = el.datetime //.clone().startOf('day')
D3 will truncate to the current day, and then crossfilter will bin at that resolution.
https://jsfiddle.net/gordonwoodhull/Lxvcoq3h/19/
Note that it's binning both of the 10/29 entries into one.
In my timezone UTC-5, the moment startOf('day')
rounding was causing the first of those entries to land on the 28th, which matches what you said you wanted:
https://jsfiddle.net/gordonwoodhull/Lxvcoq3h/21/
You'll have to decide which one is correct for your application. The main point is that if you're displaying your charts in the local timezone, the data should be quantized to local days.