68

I noticed that for us on Eastern Time zone ("America/New_York") with timezone offset of "-05:00" Date.getTimezoneOffset() returns a positive number of 300. I would expect offset in minutes to be negative in areas to the West from Utc, and to be positive in areas to the east of Utc, but apparently it's "flippded". What's the reasoning behind that decision?

http://momentjs.com/ follows the same rule and returns...

moment.parseZone("01/13/2014 3:38:00 PM +01:00").zone()   // == -60
moment.parseZone("01/13/2014 3:38:00 PM -01:00").zone()   // == 60

At the same time DateTimePicker http://trentrichardson.com/examples/timepicker/ does not flip numbers when setting its initial 'timezone' parameter. Is it wrong?

vkelman
  • 1,501
  • 1
  • 15
  • 25

2 Answers2

100

Because that's how it's defined. Quoting the doc (MDN):

The time-zone offset is the difference, in minutes, between UTC and local time. Note that this means that the offset is positive if the local timezone is behind UTC and negative if it is ahead.

raina77ow
  • 103,633
  • 15
  • 192
  • 229
  • 5
    Right, The time-zone offset is relative to the local. For example, if you lived in -01:00 zone, UTC is 60 minutes ahead of you, or +60. – lemieuxster Jan 13 '14 at 22:19
  • 84
    The question in my mind is why the hell they designed it this way. – Andy Apr 21 '17 at 15:55
  • 3
    @Andy—because the javascript Date object was a copy of the Java date object, warts and all (even a 2 digit *getYear* method). – RobG Jul 10 '17 at 08:55
  • 2
    @RobG heh, that confirms something I've wondered for a long time! – Andy Jul 11 '17 at 14:37
  • 3
    To get ride of this issue, just multiply the result with minus (-) sign. This way you will get what you want. – Tahir Afridi Jan 02 '19 at 09:51
  • 1
    The simplest way to get the offset you're expecting is `new Date().getTimezoneOffset()/-60)` .. easy peasy. This will return the offset as a person would normally expect (in hours, with negatives as you'd expect) – cowsay Feb 15 '19 at 17:01
21

Elaborating a bit on raina77ow's perfectly acceptable answer...

First, understand that the main standards involved here are ISO 8601 and RFC 822 (and its relatives 733, 1123 & 2822), which were all (in-part) derived from ANSI X3.51-1975.

All of these standards use the convention of positive values being East of UTC/GMT and negative values being West of UTC/GMT.

The only standard that I am aware of that has that reversed is POSIX (see the POSIX section of the timezone tag wiki, and this article), and thus explains why the backwards compatibility Olson time zones like "Etc/GMT+5" have their sign inverted. (Of course it's possible there are others usages and I am just unaware of them.)

Believe it or not, JavaScript does it BOTH ways. When used as a string (in either RFC 822 or ISO 8601 syntax) it uses hours and minutes with positive offsets East of UTC. But when calling the getTimezoneOffset() method on the Date object, it returns whole minutes that are positive West of UTC.

One can only speculate why this inconsistency exists. The ECMAScript spec is full of issues like this. Perhaps it's because when you see an offset in an ISO 8601 or RFC 822 string, that offset has already been applied. But when you call getTimezoneOffset() it's the offset to apply to bring it back to UTC.

For example, 2014-01-01T00:00:00-05:00 is equal to 2014-01-01T05:00:00Z. So getTimezoneOffset() would return 300. If you add 300 minutes to the original value, you get back to UTC.

It's two sides to the same coin. See?

In regards to whether or not that specific control is incorrect, I am not sure. I'm not familiar with that particular control. I see in their docs the example of -0400 being equal to -240, which one might expect to be reversed, but then again it's a bit strange to have a value like -240 presented to a user. Really, you shouldn't expose offsets to a user either way (IMHO). You're much better off using a time zone picker control, like this one or this one.

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Matt, I was surprised that Noda Time's Offset structure doesn't follow those standards. Documentation says, "A positive value means that the local time is ahead of UTC (e.g. for Europe); a negative value means that the local time is behind UTC (e.g. for America)." http://nodatime.org/1.1.x/api/html/T_NodaTime_Offset.htm I just got a bug reported to me because I thought it's doing opposite. – vkelman Feb 20 '14 at 17:09
  • I'm also using Moment.js and am comparing offsets parsed from a string by Moment.parseZone().zone() (as we discussed with you in another post http://goo.gl/9EaxG5) against offset returned by Noda Time, it's a bit messy. – vkelman Feb 20 '14 at 17:24
  • @vkelman - I'm not sure what you're getting at. Noda does the right thing. It's only JavaScripts `getTimeZoneOffset` that is inverted. Moment handles either form, using JS's way (positive to the west) when passing numbers, or using the ISO way (positive to the east) when passed as string. See [this part of the moment docs](http://momentjs.com/docs/#/manipulating/timezone-offset/) – Matt Johnson-Pint Feb 20 '14 at 19:33
  • But in Noda Time, when you use Offset..Milliseconds / (60000) to get offset minutes (a number) it is negative for areas to the west of UTC. For the same area, given a correctly formatted DateTimeZone string to create a Moment and using Moment.parseZone().zone() we're getting positive minute number. I would think that correct (but confusing) thing for Noda TimeOffset.Milliseconds() would be to return positive number for areas to the west of UTC. – vkelman Feb 20 '14 at 20:25
  • 1
    This is probably best discussed on the Noda Time group, but I wouldn't say that what Moment is doing is any more or less correct than Noda, it's just taking influence from different sources. – Matt Johnson-Pint Feb 20 '14 at 21:33
  • Now that I think about it, it would sort of be nicer if `2014-01-01T00:00:00-05:00` literally meant subtract five hours to get the real time :) – Andy Apr 21 '17 at 15:57
  • @Andy - That would require deprecating ISO8601 in favor of a new standard, and somehow conveying to the millions of people who use it every day which standard you meant. https://xkcd.com/927/ – Matt Johnson-Pint Apr 21 '17 at 16:25
  • I disagree that ECMAScript "*does it both ways*". When parsing or formatting a string in ISO 8601 or RFC 822 format, of course it uses the convention of those standards, otherwise the built-in parser and formatter would be totally useless (instead of just being mostly useless). ;-) – RobG Jul 10 '17 at 09:03