Reputation: 21
I have an angular application using highcharts-ng to make a line graph. The y-axis is numbers and the x-axis is datetime's.
I am trying to properly account for Daylight Savings Time changes when converting between the two timezones of "America/New_York" and "Europe/London" using moment.js.
London is currently in BST (as of the time of posting this), so it is +1:00.
tick.TimeStamp
> "2015-04-21T16:06:06.0786392-04:00"
tick.TimeStamp is my "America/New_York" time (currently in EDT). I convert that to London time using...
moment(tick.TimeStamp).tz("Europe/London").format()
> "2015-04-21T21:06:06+01:00"
I need my result in Unix Epoch ticks to plot them for the x-axis in highcharts-ng, so I use...
var d = moment(tick.TimeStamp).tz("Europe/London").format()
moment(d).valueOf()
which yields
1429646766000
The issue is that this tick value result as a datetime is
Tue, 21 Apr 2015 20:06:06 GMT
where it should be
Tue, 21 Apr 2015 21:06:06 GMT
since London is currently in BST +1:00
Am I doing something wrong, or is moment just calculating this incorrectly?
Any help would be greatly appreciated. Thank you!
EDIT: I should mention that my moment-timezones.js is the most recent from their site with all of the timezone info.
Upvotes: 2
Views: 14862
Reputation: 21
just wanted to post a quick update of what I figured out. Since I ran into lots of quirks trying to do this on the client side, I found a nice way to handle this on the server side in my Controller code (.NET). Instead of just returning the timestamp (tick.TimeStamp), I now return EasternTimeStamp and LondonTimeStamp. I was able to accomplish this using a nice method off of the TimeZoneInfo class.
/// <summary>
/// Converts the time to eastern standard time.
/// This should properly account for DST, putting the time in EST (-5:00) or EDT (-4:00)
/// </summary>
public static DateTime ConvertTimeToEasternStandardTime(DateTime inputDateTime)
{
// US eastern timezone=Eastern Standard Time
string targetTimeZoneId = "Eastern Standard Time";
DateTime outputDateTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(inputDateTime, targetTimeZoneId);
return outputDateTime;
}
/// <summary>
/// Converts the time to GMT standard time.
/// This should properly account for DST, putting the time in BST (+1:00) or GMT (+0:00)
/// </summary>
public static DateTime ConvertTimeToGMTStandardTime(DateTime inputDateTime)
{
// London timezone=GMT Standard Time
string targetTimeZoneId = "GMT Standard Time";
DateTime outputDateTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(inputDateTime, targetTimeZoneId);
return outputDateTime;
}
Hopefully anyone who runs into this issue can find this useful. I've found it to be quite stressful trying to find a nice way to deal with DST and timezones like this over the past week.
Upvotes: 0
Reputation: 271
I've updated a JS fiddle to provide a sample. http://jsfiddle.net/x0z90vqg/ (Updated fiddle showing type
property on xAxis if not using HighStock)
I believe your issue is that you're not using the Highcharts global object's properties useUTC and timezoneOffset properties appropriately. Using the highcharts-ng
control masks some of the capabilities of the Highcharts library, but you're still able to access the features you need pretty easily.
The relevant piece of the fiddle is:
Highcharts.setOptions({
global : {
useUTC : false,
timezoneOffset: -5
}
});
$scope.chartConfig.getHighcharts().redraw();
The above example sets the Highcharts global object to not use UTC for the date/time series and set's the offset to -5 hours (you can obtain the needed offset using the moment.js like you already are), and then telling the chart to redraw through the highcharts-ng
's exposed getHighcharts()
method. That method returns the actual chart object and from there it's like you're using highcharts directly and not through any intermediary component.
Edit
@Matt brought up a very good point. Setting the timezoneOffset like this isn't quite the same thing as setting a true timezone. A true timezone would take into account DST changes and such, this is just a static offset from UTC. Setting the UTC offset like this also affects the entire graph, not just one series. If you require displaying (and comparing) two or more series on the same graph in different timezones, and displaying that data as their respective timezones, you can enable multiple X-axis and in the format label logic for each axis, take the X value for the tick and convert it via javascript function into the timezone'd value and label you want to display. This should result in two X-axis with labels in two different timezones, but the data in the central part of the graph running off the same UTC scale. If doing this, you would likely also want to override the formatter for the tool tip popup as well so that you can convert the value displayed in the tool tip to show the timezone'd value for each point if you didn't want it to display UTC.
All of this still doesn't solve the problem of displaying a time series of data that crosses over the point where DST switches. I don't believe Highcharts has any way of representing that, and I'm not aware of another charting library that does either. It seems like it would be a fairly common problem though, so I'm sure it's been solved somewhere...
Upvotes: 2
Reputation: 18513
Moment is calculating this correctly.
Tue, 21 Apr 2015 20:06:06 GMT
, Tue, 21 Apr 2015 21:06:06 BST
, and Tue, 21 Apr 2015 16:06:06 EDT
all refer to the same time and will all have the same unix timestamp. When you call .tz()
you are just changing how that time will be formatted. You aren't changing the actual time.
Note: To get the unix time stamp you can use .unix()
e.g.
moment(tick.TimeStamp).unix()
Or this will return the same value
moment(tick.TimeStamp).tz("Europe/London").unix()
Upvotes: 4