Closed Bug 742427 Opened 13 years ago Closed 8 years ago

Date/setHours/getHours (in javascript interpreter) has an important bug in hour manipulation

Categories

(Core :: JavaScript Engine, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: lextr, Unassigned)

Details

User Agent: Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0 Build ID: 20120312181643 Steps to reproduce: First of all it's very hard to track because it depends on your timezone. So for demonstration purposes I will suppose you are in the timezone GMT+1 (Brussels, Copenhagen, Madrid, Paris). For testing you have to switch to this timezone, otherwise the problem won't be visible. Here is the code that reveals the bug : <script type="text/javascript"> //BUG var d = new Date("Mar 29 2009 01:00:00"); alert("Old date : " + d); d.setHours(d.getHours() + 1); alert("New date : " + d); //stays same //OTHER DATES WORKING, eg var d = new Date("Mar 29 2010 01:00:00"); alert("Old date : " + d); d.setHours(d.getHours() + 1); alert("New date : " + d); //displays +1 h </script> Actual results: The problem is that the hours are not added correctly : 1 - the date is not changing (no hours added) and staying at 01:00:00 2 - timezone is switched Expected results: The result should be 1 hour added to the date showing : 02:00:00, instead of staying at same 01:00:00 It can be reproduced with any timezone, but a different date should be used. For instance for the timezone UTC-5 (Indiana East) or GMT-4, the date which would be concerned is : var d = new Date("Mar 08 2009 01:00:00"); P.S: I'm marking this question as security related as well, because I have encountered possibility to exploit similar bugs.
OS: Windows 7 → All
Hardware: x86 → All
Assignee: nobody → general
Component: Untriaged → JavaScript Engine
Product: Firefox → Core
QA Contact: untriaged → general
You're advancing the date by an hour from 1am on the morning when daylight savings time starts. The first "Old date" alert is already wrong for me. It shows the timezone as "GMT-0500 (EDT)". The right thing is either "GMT-0400 (EDT)" or "GMT-0500 (EST)". Advancing from the 1am in the latter should put you at 1am in the former, I would think. Interestingly, Chrome and Safari and Opera all have the same behavior we do (except they always list EST, not EDT), so I wonder what the spec actually calls for here...
I also noticed this in other browsers as well, so this is actually a general javascript behavior. The thing is that this kind of bug can be very hard to track as they are generally left unnoticed, but are important when the timing should be precise. Is this the general definition of GMT/UTC system which causes this? or a particular implementation of these functions?
Here is the code to make the problem visible on any timezone : <script type="text/javascript"> var d = new Date("Jan 01 2008 01:00:00"); var d_c = 0, d_prev = 0, ci = 0; while (true) { ci++; d_prev = d_c; d_c = d.setHours(d.getHours() + 1); if (d_c == d_prev) alert("For your timezone the bug is at :\r\n" + d + "\r\nMs : " + d.getTime() + "\r\nLoops : " + ci); } </script>
Also this shows that some timezones are affected while others are not, example : no bug : GMT+0400 (Russian Standard Time) / UTC+4 Moscow, St.Petersburg, Volgograd no bug : GMT+1000 (Yakutsk Standard Time) / UTC + 10 Yakutsk no bug : GMT+0000 (Coordinated Universal Time) / UTC yes, bug present : GMT+0200 / UTC+1 Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna yes, bug present : GMT-0600 (Mountain Daylight Time) / UTC-7 Mountain Time (US & Canada)
The "not affected" timezones are simply the ones that don't have daylight savings time, no?
Yes and no, for example, Russia used DST before February 8, 2011 (which should still make it an unaffected & affected timezone), and they have also planned on reintroducing it, so for RST and Yakutsk or other Russia's regions it shouldn't actually affect these calculations while it does
The other thing is that the 2 "affected" dates in ms or timestamp will be converted/shown as a wrong dates/times. So even without setHours/getHours (or that writing format when initializing) there will still be a bug in "Date" because the timestamp is shift by 1h. Eg: in GMT-0400 (US Eastern Daylight Time) / UTC-5 Indiana (East) timezone : new Date(1205038800000) new Date(1205042400000) are incorrectly shown as : Sun Mar 09 2008 01:00:00 GMT-0500 (US Eastern Standard Time) Sun Mar 09 2008 00:00:00 GMT-0500 (US Eastern Standard Time) while a closer timestamp is shown correctly : new Date(1205049600000) Sun Mar 09 2008 04:00:00 GMT-0400 (US Eastern Daylight Time)
Summary: setHours/getHours (in javascript interpreter) has an important bug in hour manipulation → Date/setHours/getHours (in javascript interpreter) has an important bug in hour manipulation
This also means that : 1205038800000 < 1205042400000, while 01:00 < 00:00 is not true, so while the timestamps are actually successive the timing is not (00:00 < 01:00), like it should be. in GMT+1 the previous dates are : Sun Mar 09 2008 06:00:00 GMT+0100 Sun Mar 09 2008 07:00:00 GMT+0100 which satisfies the relation t1 < t2, but is not true in the concerned timezones for particular timestamps.
This means there is a problem counting actual time : MS 1 206 831 600 000 1 206 835 200 000 1 206 838 800 000 MS (H) 0 3 600 000 3 600 000 ---------- 7 200 000 This means 2 hours. Now in timing system for same dates in GMT+1 : Sun Mar 30 2008 00:00:00 GMT+0100 Sun Mar 30 2008 01:00:00 GMT+0100 1h Sun Mar 30 2008 03:00:00 GMT+0200 2h 3 hours. There is 1 hour "missing" which is 02:00, while it should be there. We are dealing with an unefficiency in the GMT/UTC system.
Also it's better visible on the GMT+01:00 (Brussels, Copenhagen, Madrid, Paris) timezone: alert(new Date(1206828000000)); alert(new Date(1206831600000)); alert(new Date(1206835200000)); alert(new Date(1206838800000)); alert(new Date(1206842400000)); Sat Mar 29 2008 23:00:00 GMT+0100 Sun Mar 30 2008 00:00:00 GMT+0100 Sun Mar 30 2008 01:00:00 GMT+0100 Sun Mar 30 2008 03:00:00 GMT+0200 <--- ??? Sun Mar 30 2008 04:00:00 GMT+0200 <--- ??? while doesn't seem to be such thing for GMT-5 Indiana
Indiana does not have daylight savings time.
According to Windows 7 clock Indiana East UTC-05:00 has DST (there are probably some regions which don't). But if it doesn't then the problem encompasses timezones without DST : Here is the problem for Indiana : alert(new Date(1205035200000)); alert(new Date(1205038800000)); alert(new Date(1205042400000)); alert(new Date(1205046000000)); alert(new Date(1205049600000)); Sat Mar 08 2008 23:00:00 GMT-0500 (US Eastern Standard Time) Sun Mar 09 2008 00:00:00 GMT-0500 (US Eastern Standard Time) Sun Mar 09 2008 01:00:00 GMT-0500 (US Eastern Standard Time) Sun Mar 09 2008 03:00:00 GMT-0400 (US Eastern Daylight Time) <--- ? Sun Mar 09 2008 04:00:00 GMT-0400 (US Eastern Daylight Time) <--- ?
The step in the timestamps above is 3600000 (1H)
Oh, hmm. Looks like Indiana switched to observing DST in 2006, actually. Then I'm not sure what was going on in comment 10.
This also means there is a problem calculating hours for these particular days in timestamps and also that some dates have many timestamp presentations (not unique)
Here is an example to illustrate it (Indiana) : //Problem of unicity : alert("X1.a"); t = "Mar 09 2008 02:00:00"; x = new Date(t); alert(t + "\r\n" + x + "\r\n" + x.getTime()); /* Result : Mar 09 2008 02:00:00 Sun Mar 09 2008 01:00:00 GMT-0500 (US Eastern Standard Time) 1205042400000 */ alert("X1.b"); t = "Mar 09 2008 02:30:00"; x = new Date(t); alert(t + "\r\n" + x + "\r\n" + x.getTime()); /* Result : Mar 09 2008 02:30:00 Sun Mar 09 2008 01:30:00 GMT-0500 (US Eastern Standard Time) 1205044200000 */ /* From this observation we see that timestamps are equal : 1205042400000 Sun Mar 09 2008 01:00:00 GMT-0500 (US Eastern Standard Time) 1205044200000 Sun Mar 09 2008 01:30:00 GMT-0500 (US Eastern Standard Time) But 01:00 is not equal to 01:30 There are 2 different timestamps which after some internal conversion result in equal timestamps for two different dates So there is either a problem of unicity or a collision */
Ok, it's not same, just got confused with the 24,42 from looking too long, but the other problems are still there
This example for uniqueness is better : //Problem of unicity : alert("X1.a"); t = "Mar 09 2008 02:00:00"; x = new Date(t); alert(t + "\r\n" + x + "\r\n" + x.getTime()); /* Mar 09 2008 02:00:00 Sun Mar 09 2008 01:00:00 GMT-0500 (US Eastern Standard Time) 1205042400000 */ alert("X1.b"); t = "Mar 09 2008 01:00:00"; x = new Date(t); alert(t + "\r\n" + x + "\r\n" + x.getTime()); /* Mar 09 2008 01:00:00 Sun Mar 09 2008 01:00:00 GMT-0500 (US Eastern Standard Time) 1205042400000 */
daylight savings is hard, but this can't be used to hack Firefox itself so it doesn't need to be hidden. Site authors need to take care.
Group: core-security
It were marked as security related to limit potential possibility of buffer overflow exploitation (and other) since it affects all js interpreters and there were no information on how and why it were provoked within the js interpreter core. So feel free to remove the security level of that bug if you think such exploitations cannot be done, since it requires a deeper analysis and a POC.
Assignee: general → nobody
Fixed in https://hg.mozilla.org/mozilla-central/rev/b7ef07909cc4 Before (Win10): new Date("Mar 29 2009 01:00:00").toString() "Sun Mar 29 2009 01:00:00 GMT+0100 (Romance Daylight Time)" d = new Date("Mar 29 2009 01:00:00"); d.setHours(d.getHours() + 1); d.toString() "Sun Mar 29 2009 03:00:00 GMT+0200 (Romance Standard Time)" new Date(1205038800000).toString() "Sun Mar 09 2008 00:00:00 GMT-0500 (Eastern Daylight Time)" After (Win10): new Date("Mar 29 2009 01:00:00").toString() "Sun Mar 29 2009 01:00:00 GMT+0100 (Romance Standard Time)" d = new Date("Mar 29 2009 01:00:00"); d.setHours(d.getHours() + 1); d.toString() "Sun Mar 29 2009 03:00:00 GMT+0200 (Romance Daylight Time)" new Date(1205038800000).toString() "Sun Mar 09 2008 00:00:00 GMT-0500 (Eastern Standard Time)"
Status: UNCONFIRMED → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.