Timescale axis in timezone other than local or UTC?

2,608 views
Skip to first unread message

Idan Gazit

unread,
Mar 19, 2014, 6:19:17 AM3/19/14
to d3...@googlegroups.com
Hey all,

I'm struggling to create an axis for dates in neither UTC or browser "localtime". In my application, I need to provide a timezone selector, and rerender the timeline according to the selected timezone.

Here's a good example of the kind of output I want: http://codepen.io/idan/full/xejuD

If I had a uniform set of ticks, I'd use a UTC scale and write a custom tickFormat function to render times into the desired timezone. However, with multiple-scale ticks (like the larger ticks at each midnight), that doesn't work.

I've dug into the source, and it seems like I need to write a custom time interval, like d3.time.day/d3.time.day.utc, but with a configurable timezone offset. Am I on the right track here? Are there existing efforts I should be aware of? Any pointers?

Cheers,

Idan

Mike Bostock

unread,
Mar 19, 2014, 12:06:24 PM3/19/14
to d3...@googlegroups.com
Tricky. Have you considered replacing the native Date class with a replacement that allows you to set the timezone? Something like TimezoneJS.Date might work, though you’ll have to load it before D3 since D3 captures a reference to the Date global:


Mike

Julian Schrittwieser

unread,
Jul 7, 2014, 12:12:10 PM7/7/14
to d3...@googlegroups.com, mi...@ocks.org
I tried this, but it doesn't quite work - d3.time.scale() seems to copy the dates internally, throwing away the timezone information and subsequently displaying in the wrong (local) timezone.

I'm not yet sure how to work around this correctly, I assume this means I have to write my own scale?

Julian Schrittwieser

unread,
Jul 7, 2014, 1:35:09 PM7/7/14
to d3...@googlegroups.com, mi...@ocks.org
So after some digging, it seems nearly impossible to re-use the
current time.scale() code - there are countless new d3_date() calls
all over the place, with some files defining their own wrapper for new
Date() (time/scale.js) and others randomly calling new Date() directly
(time/interval.js).

Is there a reason why you are not using one single function to create
new dates? That would make it much easier to make the time scale
timezone aware.
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "d3-js" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/d3-js/iWmP9Npv2Go/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> d3-js+un...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Dario Villanueva

unread,
Jul 8, 2014, 4:32:32 AM7/8/14
to d3...@googlegroups.com, mi...@ocks.org
how about you give moment.js a try? it will create isostrings with timezone information, and it might be what you are looking for.


You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.

Cancan Gunadi

unread,
Oct 11, 2014, 10:00:29 PM10/11/14
to d3...@googlegroups.com, mi...@ocks.org
I came across this posts while looking for solution to similar situation.
I thought I'd post my workaround in case it helps anyone.

To force the d3 time scale to show time on different timezone (not local browser time and not UTC), the trick is the calculate the difference between the local computer's time zone offset and the desired time zone, and manually shift all the data including the start and end range of the time scale by that difference.

For example, assume that the data coming in from the backend is in UTC, and your user's local computer is set to CDT/Central, while the desired timezone you want to be displayed on the d3 time scale is EDT/Eastern.

Then the steps are:

1. Figure out what's the timezone offset of CDT by using the normal javascript Date, like so:
          (new Date()).getTimezoneOffset() --> returns -300 minutes.
2. Figure out the timezone offset of the desired timezone, in this case EDT, which comes out to be -240 minutes.
3. Calculate the difference between these two timezone: -240 - (-300) = 60 mins
4. Manually shift all the data which comes from backend, i.e: + 60 mins and feed them into d3 time scale (use d3.time.scale.utc()). I used moment.js so all I have to do to shift is just use the moment.add(60, 'm') call, or you can convert the difference to millisec and shift the data that way too.
5. Voila! The d3 time scale renders the data in the desired EDT timezone.

Hope this helps!

Julian Schrittwieser

unread,
Oct 12, 2014, 12:20:13 AM10/12/14
to d3...@googlegroups.com, mi...@ocks.org

Yes, that's also what I've been doing. It only gets problematic when you want to convert those times back, and a daylight savings switch is in the middle of your data.

Jake Puffer

unread,
Jul 27, 2017, 5:03:25 PM7/27/17
to d3-js
It looks like this is still a pain point in D3, all these years later.  Someone has ostensibly solved it here: https://www.npmjs.com/package/d3-chronological but it looks like it's written for D3 v3.  
Has anyone come across an effort to plug into D3 v4 to add support for time scales using Moment date objects with rich timezone information instead of native date objects?
Reply all
Reply to author
Forward
0 new messages