16

In a previous question I wrote about a javascript date function that was mysteriously stopping on 11/07/101. Thanks to the stackoverflow users I was told my problem is Daylight Savings Time. Javascript date, is this my error or did I find a bug?

So my last question on this is what is the recommended approach in Javascript to deal with Daylight Savings Time?

Is http://code.google.com/p/datejs/ the best approach to solve this?

Community
  • 1
  • 1
davidjhp
  • 7,816
  • 9
  • 36
  • 56

3 Answers3

22

The best way is not to deal with DST. Use the UTC methods and you won't have to worry about crossing a DST boundary, or any other timezone discontinuity (locale timezone rules can change for more reasons than just DST).

var timestamp= Date.UTC(2010, 10-1, 31, 0, 0, 0); // zero-based month: 9->october
var nextday= new Date(timestamp+86400000); // add one day
var ymd= [
    nextday.getUTCFullYear(),
    nextday.getUTCMonth()+1, // zero-based month
    nextday.getUTCDate()
].join('-');
alert(ymd); // 2010-11-1

If the above had been done with new Date(2010, ...) and getDate() etc, it'd return 2010-10-31, the day add failing due to the DST change (in my region, anyway).

It is a pity that the ‘default’ most-obvious methods in Date are about local time, especially since JavaScript provides so very little context to scripts on what ‘local time’ actually is. UTC is a more stable proposition.

Avi Flax
  • 50,872
  • 9
  • 47
  • 64
bobince
  • 528,062
  • 107
  • 651
  • 834
  • 1
    Agree, I used to work on a time and attendance application, so this was a very common issue. Our approach is to always work with UTC methods. To display the correct time, (and to receive input from the employee) we needed to know the timezone offset for each employee (which could be in multiple timezones) and a list of they days that DST was active for that timezone offset – Ruan Mendes Nov 05 '10 at 22:00
3

Use Date.setHours(hour,min,sec,millisec) to set the hour default to noon: Date.setHours(11); (view reference)

24 hours after noon on a day is guaranteed to be the next day, though on daylight savings time days it will be one hour off (which doesn't change the result in your script at all).

Anthony Corbelli
  • 877
  • 4
  • 10
-1

I was in a situation where I needed the date in the local time zone, i was doing a lot of adding and subtracting days via time stamps, some time later DST gave me issues, I made a function to add days to a time stamp and check if the time zone changed cause of DST
Heres is my scratchpad test:

function timeToHuman(stamp) {
    var monthNames = ["January", "February", "March", "April", "May", "June",
            "July", "August", "September", "October", "November", "December"],
        date = new Date(stamp*1000),
        month = monthNames[date.getMonth()],
        day = date.getDate(),
        year = date.getFullYear(),
        hour = date.getHours(),
        min = date.getMinutes(),
        amp;
    if(hour>11){
        hour -= 12;
        amp = "PM";
    }
    else
        amp="AM";
    hour = hour==0?12:hour;
    min = min<10?"0"+min:min;
    return month + " " + day + ", " + year + " @ " +  hour + ":" + min + " " + amp +// Month/Day /Year
        " || "+year+"/"+(date.getMonth()+1)+"/"+day+ " @ " +  date.getHours() + ":" + min;// Year/Month/Day
}
function addDays(stamp,days){//stamp = new Date().getTime()/1000
    var sec=days*86400,
        B4=new Date(stamp*1000).getTimezoneOffset(),
        A=new Date((stamp+sec)*1000).getTimezoneOffset();
    if(B4!=A){// DST correction
        A=(A-B4)*60;
        console.log('DST adjust by:',A,'seconds');
        sec+=A;
    }
    return stamp+sec;
}
var sample=[
         Math.floor(new Date('Sun Mar 10 2018 11:38:59 GMT-0500 (EDT)').getTime()/1000),// day before DST change
         Math.floor(new Date('Sun Mar 11 2018 11:38:59 GMT-0400 (EDT)').getTime()/1000),// day after DST change
         Math.floor(new Date('Sun Nov 3 2018 11:38:59 GMT-0400 (EDT)').getTime()/1000),// day before DST change
         Math.floor(new Date('Sun Nov 4 2018 11:38:59 GMT-0500 (EDT)').getTime()/1000)// day after DST change
      ]
    date=[];
for(i in sample){
    i=parseInt(i,10);
  date.push('Without DST Detection, Part '+(i+1));
  date.push('\t'+timeToHuman(sample[i]+2*86400));
  date.push('\t'+timeToHuman(sample[i]+1*86400));
  date.push('\t'+timeToHuman(sample[i]));
  date.push('\t'+timeToHuman(sample[i]+-1*86400));
  date.push('\t'+timeToHuman(sample[i]+-2*86400));
  date.push('\t'+timeToHuman(sample[i]+-3*86400));
  date.push('With DST Detection, Part '+(i+1));
  date.push('\t'+timeToHuman(addDays(sample[i],2)));
  date.push('\t'+timeToHuman(addDays(sample[i],1)));
  date.push('\t'+timeToHuman(sample[i]));
  date.push('\t'+timeToHuman(addDays(sample[i],-1)));
  date.push('\t'+timeToHuman(addDays(sample[i],-2)));
  date.push('\t'+timeToHuman(addDays(sample[i],-3)));
}
date.join('\n');

/*
Without DST Detection, Part 1
    March 12, 2018 @ 12:38 PM || 2018/3/12 @ 12:38
    March 11, 2018 @ 12:38 PM || 2018/3/11 @ 12:38
    March 10, 2018 @ 11:38 AM || 2018/3/10 @ 11:38
    March 9, 2018 @ 11:38 AM || 2018/3/9 @ 11:38
    March 8, 2018 @ 11:38 AM || 2018/3/8 @ 11:38
    March 7, 2018 @ 11:38 AM || 2018/3/7 @ 11:38
With DST Detection, Part 1
    March 12, 2018 @ 11:38 AM || 2018/3/12 @ 11:38
    March 11, 2018 @ 11:38 AM || 2018/3/11 @ 11:38
    March 10, 2018 @ 11:38 AM || 2018/3/10 @ 11:38
    March 9, 2018 @ 11:38 AM || 2018/3/9 @ 11:38
    March 8, 2018 @ 11:38 AM || 2018/3/8 @ 11:38
    March 7, 2018 @ 11:38 AM || 2018/3/7 @ 11:38
Without DST Detection, Part 2
    March 13, 2018 @ 11:38 AM || 2018/3/13 @ 11:38
    March 12, 2018 @ 11:38 AM || 2018/3/12 @ 11:38
    March 11, 2018 @ 11:38 AM || 2018/3/11 @ 11:38
    March 10, 2018 @ 10:38 AM || 2018/3/10 @ 10:38
    March 9, 2018 @ 10:38 AM || 2018/3/9 @ 10:38
    March 8, 2018 @ 10:38 AM || 2018/3/8 @ 10:38
With DST Detection, Part 2
    March 13, 2018 @ 11:38 AM || 2018/3/13 @ 11:38
    March 12, 2018 @ 11:38 AM || 2018/3/12 @ 11:38
    March 11, 2018 @ 11:38 AM || 2018/3/11 @ 11:38
    March 10, 2018 @ 11:38 AM || 2018/3/10 @ 11:38
    March 9, 2018 @ 11:38 AM || 2018/3/9 @ 11:38
    March 8, 2018 @ 11:38 AM || 2018/3/8 @ 11:38
Without DST Detection, Part 3
    November 5, 2018 @ 10:38 AM || 2018/11/5 @ 10:38
    November 4, 2018 @ 10:38 AM || 2018/11/4 @ 10:38
    November 3, 2018 @ 11:38 AM || 2018/11/3 @ 11:38
    November 2, 2018 @ 11:38 AM || 2018/11/2 @ 11:38
    November 1, 2018 @ 11:38 AM || 2018/11/1 @ 11:38
    October 31, 2018 @ 11:38 AM || 2018/10/31 @ 11:38
With DST Detection, Part 3
    November 5, 2018 @ 11:38 AM || 2018/11/5 @ 11:38
    November 4, 2018 @ 11:38 AM || 2018/11/4 @ 11:38
    November 3, 2018 @ 11:38 AM || 2018/11/3 @ 11:38
    November 2, 2018 @ 11:38 AM || 2018/11/2 @ 11:38
    November 1, 2018 @ 11:38 AM || 2018/11/1 @ 11:38
    October 31, 2018 @ 11:38 AM || 2018/10/31 @ 11:38
Without DST Detection, Part 4
    November 6, 2018 @ 11:38 AM || 2018/11/6 @ 11:38
    November 5, 2018 @ 11:38 AM || 2018/11/5 @ 11:38
    November 4, 2018 @ 11:38 AM || 2018/11/4 @ 11:38
    November 3, 2018 @ 12:38 PM || 2018/11/3 @ 12:38
    November 2, 2018 @ 12:38 PM || 2018/11/2 @ 12:38
    November 1, 2018 @ 12:38 PM || 2018/11/1 @ 12:38
With DST Detection, Part 4
    November 6, 2018 @ 11:38 AM || 2018/11/6 @ 11:38
    November 5, 2018 @ 11:38 AM || 2018/11/5 @ 11:38
    November 4, 2018 @ 11:38 AM || 2018/11/4 @ 11:38
    November 3, 2018 @ 11:38 AM || 2018/11/3 @ 11:38
    November 2, 2018 @ 11:38 AM || 2018/11/2 @ 11:38
    November 1, 2018 @ 11:38 AM || 2018/11/1 @ 11:38
*/