1

I"m using d3 v4. My x-axis data consists of time in milliseconds (since 1970). I would like to display this as eastern standard time, for example

08/09/17 5:20 PM EDT

so I tried

focus.select("text").text(d.value).append("tspan")
      .attr("x", 10).attr("dy", "1.5em").text(d3.timeFormat("%m/%d/%Y %H:%M %p %Z+5")(d.index_date));

but unfortunately it is instead displaying as

08/09/17 5:20 PM -0500 +%

What's the proper way to format the date/time as EDT (US Eastern standard time)?

Dave
  • 15,639
  • 133
  • 442
  • 830

2 Answers2

1

D3 v4 time format has support for custom locales, but I don't see anything for time zones (so you can show the date-time in Russian, but only with the browser's local time zone), which is understandable, as it requires having the TZ data locally.

The only way I see is to bring another library.
Edit: no wait, Date.toLocaleString supports timeZone parameter (but it seems browser support is limited, e.g. Android does not support this (well, Chrome does, Firefox does not, and maybe WebViews won't)):

new Date(1502769000000).toLocaleString('en-US', { timeZone: 'America/New_York' })
// 8/14/2017, 11:50:00 PM"

(so you'd just need to add the "EDT" suffix yourself)

Alternatively, with moment-timezone (which itself requires moment):

var t = 1502769000000;
var f = 'M/D/Y h:mma z';
moment(t).tz('America/New_York').format(f);
// 8/14/2017 11:50pm EDT
moment(t).tz('Europe/Paris').format(f);
// 8/15/2017 5:50am CEST

Since you always need the same TZ, you might be interested to note that it's also technically possible to build a lighter version yourself with only the subset of TZ data you require.

Hugues M.
  • 19,846
  • 6
  • 37
  • 65
  • Other than including the library you linked to here is there anything else I need to do to get moment working? After including the library and running your code I'm getting the error, "ReferenceError: moment is not defined" – Dave Aug 15 '17 at 15:51
  • Ah, the library I linked to is a plugin for [momentjs](https://momentjs.com/), so you need to install 2 libraries, sorry that was unclear – Hugues M. Aug 15 '17 at 15:52
  • K, I included the "moment" JS file you linked to above in the line before th emoment-timezone file but yet I still get the error, "TypeError: moment is undefined" coming from http://localhost:3000/assets/moment-timezone.self-3635c5815990517b36f417fa9112870283008691bbd03d999215a2bce80e42fb.js?body=1 upon page load. – Dave Aug 15 '17 at 16:45
  • Hmm see [example](https://zami.fr/7c3ed4f7c7fb3529e783527bad9d0296.html) -- (also please notice my edit, maybe there is a no-library solution) – Hugues M. Aug 15 '17 at 17:05
  • Yeah taht no-library solution is lookin' solid. – Dave Aug 15 '17 at 18:48
  • Yeah well, add Safari 9 to the list of browsers that don't support it. Depending on your site audience, you might want to consider moment-timezone. – Hugues M. Aug 15 '17 at 19:39
0

The toString() method on a regular javascript Date object includes the time zone abbreviation but the d3-time-format library doesn't seem to include a way to get it.

var date = new Date(123456789);
console.log(date.toString()); //"Fri Jan 02 1970 05:17:36 GMT-0500 (EST)"

var d3Format = d3.timeFormat("%c %Z");
console.log(d3Format(date)); //"1/2/1970, 5:17:36 AM -0500"

So you'll have to add in the time zone abbreviation manually with your own function.

var jenny = new Date(8675309);
var d3Format = d3.timeFormat("%c"); //%c is shorthand for %x %X (date and time)

// Add "EST" to the end of every string
var addEST = function(date) {
    return d3Format(date) + " EST";
}

console.log(addEST(jenny)); //"12/31/1969, 9:24:35 PM EST"
gmferland
  • 117
  • 5
  • You mean "var d3Format = d3.timeFormat("%c %Z");" instead of what you have, right? B/c I was getting a JS error complaining about undefined timeformat the other way. Anyway, even with what I suggest here, the output is still incorrect. I'm getting "8/9/2017, 1:10:08 AM -0500 CDT" but what I want is "8/29/2017 2:10:08 AM EDT". – Dave Aug 11 '17 at 14:58
  • Sure, what you call your function depends on whatever name you choose to give the imported d3 library. d3.timeFormat("%c") will give you back just the date and time with no time zone information. – gmferland Aug 11 '17 at 15:06
  • Another thing I didn't consider is date.toString() will return your current time zone, so if you're somewhere in central time it will always return CDT. If you want your data to all be EST then forget the whole regex business and just concatenate "EST" to the d3 formatted string. – gmferland Aug 11 '17 at 15:10
  • I need an example here b/c if I concatenate "EST" to the string, taht would give me "8/9/2017, 1:10:08 AM -0500 CDT EST" which is all kinds of confusing. – Dave Aug 11 '17 at 15:13
  • Ok, I'll update my above code snipped to reflect what I mean – gmferland Aug 11 '17 at 15:16
  • Thx although its still nto quite right. Its showing things like "8/10/2017, 2:40:09 PM EST" but it should be "8/10/2017, 3:40:09 PM EST". I think the "new Date(8675309);" is returning things in CDT b/c taht's where I am, but this function should display the time in EST whether you're on a browser in Denver, Anchorage, or Mars. – Dave Aug 11 '17 at 16:51
  • Ok I see the problem now I think. The d3.timeFormat function only works on Date objects, and if you pass in a number or string instead it will convert to a Date. So it's always biased to your location. The only alternative I see is d3.utcFormat, which interprets dates without time zones, then converting to EST manually. But then you have to account for daylight savings time which is a mess... Sorry I don't seem to be of much help – gmferland Aug 11 '17 at 17:35
  • Np I appreciate your thoughts on all this. It may lead to an answer yet. – Dave Aug 11 '17 at 20:14