[javascript] How to check if DST (Daylight Saving Time) is in effect, and if so, the offset?

This is a bit of my JS code for which this is needed:

var secDiff = Math.abs(Math.round((utc_date-this.premiere_date)/1000));
this.years = this.calculateUnit(secDiff,(86400*365));
this.days = this.calculateUnit(secDiff-(this.years*(86400*365)),86400);
this.hours = this.calculateUnit((secDiff-(this.years*(86400*365))-(this.days*86400)),3600);
this.minutes = this.calculateUnit((secDiff-(this.years*(86400*365))-(this.days*86400)-(this.hours*3600)),60);
this.seconds = this.calculateUnit((secDiff-(this.years*(86400*365))-(this.days*86400)-(this.hours*3600)-(this.minutes*60)),1);

I want to get the datetime in "ago", but if the DST is in use then the dates are off by 1 hour. I don't know how to check if the DST is in effect or not.

How can I know when the daylight saving starts and ends?

The answer is


Is there an issue using the Date.toString().indexOf('Daylight Time') > -1

"" + new Date()

Sat Jan 01 100050 00:00:00 GMT-0500 (Eastern Standard Time)

"" + new Date(...)

Sun May 01 100033 00:00:00 GMT-0400 (Eastern Daylight Time)

This seems compatible with all browsers.


I was faced with this same problem today but since our daylight saving starts and stops at differing times from the USA (at least from my understanding), I used a slightly different route..

var arr = [];
for (var i = 0; i < 365; i++) {
 var d = new Date();
 d.setDate(i);
 newoffset = d.getTimezoneOffset();
 arr.push(newoffset);
}
DST = Math.min.apply(null, arr);
nonDST = Math.max.apply(null, arr);

Then you simply compare the current timezone offset with DST and nonDST to see which one matches.


ES6 Style

Math.min(...[0, 6].map(v => new Date(95, v, 1).getTimezoneOffset() * -1));

Use Moment.js (https://momentjs.com/)

moment().isDST(); will give you if Day light savings is observed.

Also it has helper function to calculate relative time for you. You don't need to do manual calculations e.g moment("20200105", "YYYYMMDD").fromNow();


Your're close but a little off. You never need to calculate your own time as it is a result of your own clock. It can detect if you are using daylight saving time in your location but not for a remote location produced by the offset:

newDateWithOffset = new Date(utc + (3600000*(offset)));

This will still be wrong and off an hour if they are in DST. You need for a remote time account if they are currently inside their DST or not and adjust accordingly. try calculating this and change your clock to - lets say 2/1/2015 and reset the clock back an hour as if outside DST. Then calculate for an offset for a place that should still be 2 hours behind. It will show an hour ahead of the two hour window. You would still need to account for the hour and adjust. I did it for NY and Denver and always go the incorrect (hour ahead) in Denver.


The getTimezoneOffset() method in JavaScript, in a browser, returns the number of minutes offset from the 00:00 time zone. For example, America/New_York time zone in Daylight Savings (DST) returns the number 300. 300 minutes is 5 hours difference from zero. 300 minutes divided by 60 minutes is 5 hours. Every time zone is compared to the zero time zone, +00:00 / Etc/GMT / Greenwich time.

MDN Web Docs

The next thing that you must know, is that the offset has the opposite sign of the actual time zone.

Information about time zones is maintained by the Internet Assigned Numbers Authority (iana)

iana time zones

A nicely formatted table of Time Zones is supplied by joda.org

joda-time Time Zones

+00:00 or Etc/GMT is Greenwich time

All time zones are offset from +00:00 / "Etc/GMT" / Greenwich time

Daylight Savings Time is always an earlier time than the "regular" time in the summer. You set your clocks back in the fall season. ("Fall Back" slogan to remember what to do)

So, America/New_York time in Daylight Savings (winter) is one hour before the regular time. So, for example, what was normally 5 p.m. in the afternoon in New York city in the summer, is now 4 p.m. America/New_York time in Daylight Savings. The name "America/New_York" time is a "Long Format" time zone name. The east coast of the U.S typically calls their time zone Eastern Standard Time (EST)

If you want to compare today's time zone offset to the time zone offset of some other date, you need to know that mathematical sign (+/- "Positive / Negative") of the time zone offset is the opposite of the time zone.

Look at the time zone table at joda.org and find the time zone for "America/New_York" It will have a negative sign in front of the Standard Offset.

The earth rotates counter-clockwise on it's axis. A person watch the sunrise in Greenwich sees the sunrise 5 hours before someone in New York City will see the sunrise. And someone on the West Coast of the U.S. will see the sunrise after someone on the East Coast of the U.S. sees the sunrise.

There's a reason why you need to know all of this. So that you'll be able to logically determine whether some JavaScript code is getting the DST status correctly or not, without needing to test every time zone at different times of the year.

Imagine that it's November in New York City, and the clocks have been set back an hour. In the summer in New York City, the offset is 240 minutes or 4 hours.

You can test this by creating a date that is in July and then getting the offset.

var July_Date = new Date(2017, 6, 1);
var july_Timezone_OffSet = July_Date.getTimezoneOffset();

console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

What will print to the browser's developer tools console log?

Answer is: 240

So, now you can create a date in January and see what your browser returns for a time zone offset for the winter season.

var Jan_Date = new Date(2017, 0, 1);//Month is zero indexed - Jan is zero
var jan_Timezone_OffSet = Jan_Date.getTimezoneOffset();

console.log('jan_Timezone_OffSet: ' + jan_Timezone_OffSet)

Answer is: 300

Obviously 300 is bigger than 240. So, what does this mean? Should you write code that tests for the winter offset being bigger than the summer offset? Or the summer offset less than the winter offset? If there is a difference between the summer and winter time zone offsets, then you can assume that DST is being used for this time zone. But that doesn't tell you if today is using DST for the browsers time zone. So, you'll need to get the time zone offset for today.

var today = new Date();
var todaysTimeZone = today.getTimezoneOffset();

console.log('todaysTimeZone : ' + todaysTimeZone)

Answer is: ? - Depends on the time of year

If today's time zone offset and the summer time zone offset is the same, AND the summer and winter time zone offsets are different, then by logical deduction, today must be NOT be in DST.

Can you omit comparing the summer and winter time zone offsets, (To know if DST is used for this time zone) and just compare today's time zone offset to the summer TZ offset, and always get the correct answer?

today's TZ Offset !== Summer TZ Offset

Well, is today in the winter or summer? If you knew that then you could apply the following logic:

if ( it_is_winter && ( todays_TZ_Offset !== summer_TZ_Offset) {
  var are_We_In_DST = true;
}

But the problem is, that you don't know if today's date is in winter or summer. Every time zone can have it's own rules for when DST starts and stops. You'd need to keep track of every time zone's rules for every time zone in the world. So, if there is a better and easier way then you might as well do it the better and easier way.

What we are left with, is that you need to know if this time zone uses DST, and then compare today's time zone offset with the summer time zone offset. That will always give you a reliable answer.

The final logic is:

if ( DST_Is_Used_In_This_Time_Zone && ( todays_TZ_Offset !== summer_TZ_Offset) {
  var are_We_In_DST = true;
}

Function to determine if the time zone in the browser uses DST:

function is_DST_Used_In_This_TimeZone() {
  var Jan_Date, jan_Timezone_OffSet, July_Date, july_Timezone_OffSet 
      offsetsNotEqual, thisYear, today;

  today = new Date();//Create a date object that is now
  thisYear = today.getFullYear();//Get the year as a number

  Jan_Date = new Date(thisYear, 0, 1);//Month is zero indexed - Jan is zero
  jan_Timezone_OffSet = Jan_Date.getTimezoneOffset();

  console.log('jan_Timezone_OffSet: ' + jan_Timezone_OffSet)

  July_Date = new Date(thisYear, 6, 1);
  july_Timezone_OffSet = July_Date.getTimezoneOffset();

  console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

  offsetsNotEqual = july_Timezone_OffSet !== jan_Timezone_OffSet;//True if not equal

  console.log('offsetsNotEqual: ' + offsetsNotEqual);

  return offsetsNotEqual;//If the offsets are not equal for summer and
       //winter then the only possible reason is that DST is used for
       //this time zone
}

The moment.js library provides an .isDst() method on its time objects.

moment#isDST checks if the current moment is in daylight saving time.

moment([2011, 2, 12]).isDST(); // false, March 12 2011 is not DST
moment([2011, 2, 14]).isDST(); // true, March 14 2011 is DST

Create two dates: one in June, one in January. Compare their getTimezoneOffset() values.

  • if January offset > June offset, client is in northern hemisphere
  • if January offset < June offset, client is in southern hemisphere
  • if no difference, client timezone does not observe DST

Now check getTimezoneOffset() of the current date.

  • if equal to June, northern hemisphere, then current time zone is DST (+1 hour)
  • if equal to January, southern hemisphere, then current time zone is DST (+1 hour)

Future-Proof Solution That Works In All Time Zones

  1. Let x be the expected number of milliseconds into the year of interest without factoring in daylight savings.
  2. Let y be the number of milliseconds since the Epoch from the start of the year of the date of interest.
  3. Let z be the number of milliseconds since the Epoch of the full date and time of interest
  4. Let t be the subtraction of both x and y from z: z - y - x. This yields the offset due to DST.
  5. If t is zero, then DST is not in effect. If t is not zero, then DST is in effect.

_x000D_
_x000D_
(function(){"use strict";_x000D_
function dstOffsetAtDate(dateInput) {_x000D_
    var fullYear = dateInput.getFullYear()|0;_x000D_
 // "Leap Years are any year that can be exactly divided by 4 (2012, 2016, etc)_x000D_
  //   except if it can be exactly divided by 100, then it isn't (2100,2200,etc)_x000D_
  //   except if it can be exactly divided by 400, then it is (2000, 2400)"_x000D_
 // (https://www.mathsisfun.com/leap-years.html)._x000D_
    var isLeapYear = ((fullYear & 3) | (fullYear/100 & 3)) === 0 ? 1 : 0;_x000D_
 // (fullYear & 3) = (fullYear % 4), but faster_x000D_
    //Alternative:var isLeapYear=(new Date(currentYear,1,29,12)).getDate()===29?1:0_x000D_
    var fullMonth = dateInput.getMonth()|0;_x000D_
    return (_x000D_
        // 1. We know what the time since the Epoch really is_x000D_
        (+dateInput) // same as the dateInput.getTime() method_x000D_
        // 2. We know what the time since the Epoch at the start of the year is_x000D_
        - (+new Date(fullYear, 0, 0)) // day defaults to 1 if not explicitly zeroed_x000D_
        // 3. Now, subtract what we would expect the time to be if daylight savings_x000D_
        //      did not exist. This yields the time-offset due to daylight savings._x000D_
        - ((_x000D_
            ((_x000D_
                // Calculate the day of the year in the Gregorian calendar_x000D_
                // The code below works based upon the facts of signed right shifts_x000D_
                //    • (x) >> n: shifts n and fills in the n highest bits with 0s _x000D_
                //    • (-x) >> n: shifts n and fills in the n highest bits with 1s_x000D_
                // (This assumes that x is a positive integer)_x000D_
                (31 & ((-fullMonth) >> 4)) + // January // (-11)>>4 = -1_x000D_
                ((28 + isLeapYear) & ((1-fullMonth) >> 4)) + // February_x000D_
                (31 & ((2-fullMonth) >> 4)) + // March_x000D_
                (30 & ((3-fullMonth) >> 4)) + // April_x000D_
                (31 & ((4-fullMonth) >> 4)) + // May_x000D_
                (30 & ((5-fullMonth) >> 4)) + // June_x000D_
                (31 & ((6-fullMonth) >> 4)) + // July_x000D_
                (31 & ((7-fullMonth) >> 4)) + // August_x000D_
                (30 & ((8-fullMonth) >> 4)) + // September_x000D_
                (31 & ((9-fullMonth) >> 4)) + // October_x000D_
                (30 & ((10-fullMonth) >> 4)) + // November_x000D_
                // There are no months past December: the year rolls into the next._x000D_
                // Thus, fullMonth is 0-based, so it will never be 12 in Javascript_x000D_
                _x000D_
                (dateInput.getDate()|0) // get day of the month_x000D_
    _x000D_
            )&0xffff) * 24 * 60 // 24 hours in a day, 60 minutes in an hour_x000D_
            + (dateInput.getHours()&0xff) * 60 // 60 minutes in an hour_x000D_
            + (dateInput.getMinutes()&0xff)_x000D_
        )|0) * 60 * 1000 // 60 seconds in a minute * 1000 milliseconds in a second_x000D_
        - (dateInput.getSeconds()&0xff) * 1000 // 1000 milliseconds in a second_x000D_
        - dateInput.getMilliseconds()_x000D_
    );_x000D_
}_x000D_
_x000D_
// Demonstration:_x000D_
var date = new Date(2100, 0, 1)_x000D_
for (var i=0; i<12; i=i+1|0, date.setMonth(date.getMonth()+1|0))_x000D_
    console.log(date.getMonth()+":\t"+dstOffsetAtDate(date)/60/60/1000+"h\t"+date);_x000D_
date = new Date(1900, 0, 1);_x000D_
for (var i=0; i<12; i=i+1|0, date.setMonth(date.getMonth()+1|0))_x000D_
    console.log(date.getMonth()+":\t"+dstOffsetAtDate(date)/60/60/1000+"h\t"+date);_x000D_
_x000D_
// Performance Benchmark:_x000D_
console.time("Speed of processing 16384 dates");_x000D_
for (var i=0,month=date.getMonth()|0; i<16384; i=i+1|0)_x000D_
    date.setMonth(month=month+1+(dstOffsetAtDate(date)|0)|0);_x000D_
console.timeEnd("Speed of processing 16384 dates");_x000D_
})();
_x000D_
_x000D_
_x000D_

I believe that the above code snippet is superior to all other answers posted here for many reasons.

  • This answer works in all time zones, even Antarctica/Casey.
  • Daylight savings is very much subject to change. It might be that 20 years from now, some country might have 3 DST periods instead of the normal 2. This code handles that case by returning the DST offset in milliseconds, not just whether DST is in effect or not in effect.
  • The size of the months of the year and the way that Leap Years work fits perfectly into keeping our time on track with the sun. Heck, it works so perfectly that all we ever do is just adjust mere seconds here and there. Our current system of leap years has been in effect since February 24th, 1582, and will likely stay in effect for the foreseeable future.
  • This code works in timezones that do not use DST.
  • This code works in historic times before when DST was implemented (such as the 1900s).
  • This code is maximally integer-optimized and should give you no problem if called in a tight loop. After running the code snippet above, scroll down to the bottom of the output to see the performance benchmark. My computer is able to process 16384 dates in ~97ms on Chrome.

However, if you are not preparing for over 2 DST periods, then the below code can be used to determine whether DST is in effect as a boolean.

function isDaylightSavingsInEffect(dateInput) {
    // To satisfy the original question
    return dstOffsetAtDate(dateInput) !== 0;
}

I've found that using the Moment.js library with some of the concepts described here (comparing Jan to June) works very well.

This simple function will return whether the timezone that the user is in observes Daylight Saving Time:

function HasDST() {
    return moment([2017, 1, 1]).isDST() != moment([2017, 6, 1]).isDST();
}

A simple way to check that this works (on Windows) is to change your timezone to a non DST zone, for example Arizona will return false, whereas EST or PST will return true.

enter image description here


Based on Matt Johanson's comment on the solution provided by Sheldon Griffin I created the following code:

    Date.prototype.stdTimezoneOffset = function() {
        var fy=this.getFullYear();
        if (!Date.prototype.stdTimezoneOffset.cache.hasOwnProperty(fy)) {

            var maxOffset = new Date(fy, 0, 1).getTimezoneOffset();
            var monthsTestOrder=[6,7,5,8,4,9,3,10,2,11,1];

            for(var mi=0;mi<12;mi++) {
                var offset=new Date(fy, monthsTestOrder[mi], 1).getTimezoneOffset();
                if (offset!=maxOffset) { 
                    maxOffset=Math.max(maxOffset,offset);
                    break;
                }
            }
            Date.prototype.stdTimezoneOffset.cache[fy]=maxOffset;
        }
        return Date.prototype.stdTimezoneOffset.cache[fy];
    };

    Date.prototype.stdTimezoneOffset.cache={};

    Date.prototype.isDST = function() {
        return this.getTimezoneOffset() < this.stdTimezoneOffset(); 
    };

It tries to get the best of all worlds taking into account all the comments and previously suggested answers and specifically it:

1) Caches the result for per year stdTimezoneOffset so that you don't need to recalculate it when testing multiple dates in the same year.

2) It does not assume that DST (if it exists at all) is necessarily in July, and will work even if it will at some point and some place be any month. However Performance-wise it will work faster if indeed July (or near by months) are indeed DST.

3) Worse case it will compare the getTimezoneOffset of the first of each month. [and do that Once per tested year].

The assumption it does still makes is that the if there is DST period is larger then a single month.

If someone wants to remove that assumption he can change loop into something more like whats in the solutin provided by Aaron Cole - but I would still jump half a year ahead and break out of the loop when two different offsets are found]


I recently needed to create a date string with UTC and DST, and based on Sheldon's answer I put this together:

_x000D_
_x000D_
Date.prototype.getTimezone = function(showDST) {_x000D_
    var jan = new Date(this.getFullYear(), 0, 1);_x000D_
    var jul = new Date(this.getFullYear(), 6, 1);_x000D_
_x000D_
    var utcOffset = new Date().getTimezoneOffset() / 60 * -1;_x000D_
    var dstOffset = (jan.getTimezoneOffset() - jul.getTimezoneOffset()) / 60;_x000D_
_x000D_
    var utc = "UTC" + utcOffset.getSign() + (utcOffset * 100).preFixed(1000);_x000D_
    var dst = "DST" + dstOffset.getSign() + (dstOffset * 100).preFixed(1000);_x000D_
_x000D_
    if (showDST) {_x000D_
        return utc + " (" + dst + ")";_x000D_
    }_x000D_
_x000D_
    return utc;_x000D_
}_x000D_
Number.prototype.preFixed = function (preCeiling) {_x000D_
    var num = parseInt(this, 10);_x000D_
    if (preCeiling && num < preCeiling) {_x000D_
        num = Math.abs(num);_x000D_
        var numLength   = num.toString().length;_x000D_
        var preCeilingLength = preCeiling.toString().length;_x000D_
        var preOffset   = preCeilingLength - numLength;_x000D_
        for (var i = 0; i < preOffset; i++) {_x000D_
            num = "0" + num;_x000D_
        }_x000D_
    }_x000D_
    return num;_x000D_
}_x000D_
Number.prototype.getSign = function () {_x000D_
    var num  = parseInt(this, 10);_x000D_
    var sign = "+";_x000D_
    if (num < 0) {_x000D_
        sign = "-";_x000D_
    }_x000D_
    return sign;_x000D_
}_x000D_
_x000D_
document.body.innerHTML += new Date().getTimezone() + "<br>";_x000D_
document.body.innerHTML += new Date().getTimezone(true);
_x000D_
<p>Output for Turkey (UTC+0200) and currently in DST: &nbsp; UTC+0300 (DST+0100)</p>_x000D_
<hr>
_x000D_
_x000D_
_x000D_


This answer is quite similar to the accepted answer, but doesn't override the Date prototype, and only uses one function call to check if Daylight Savings Time is in effect, rather than two.


The idea is that, since no country observes DST that lasts for 7 months[1], in an area that observes DST the offset from UTC time in January will be different to the one in July.

While Daylight Savings Time moves clocks forwards, JavaScript always returns a greater value during Standard Time. Therefore, getting the minimum offset between January and July will get the timezone offset during DST.

We then check if the dates timezone is equal to that minimum value. If it is, then we are in DST; otherwise we are not.

The following function uses this algorithm. It takes a date object, d, and returns true if daylight savings time is in effect for that date, and false if it is not:

function isDST(d) {
    let jan = new Date(d.getFullYear(), 0, 1).getTimezoneOffset();
    let jul = new Date(d.getFullYear(), 6, 1).getTimezoneOffset();
    return Math.max(jan, jul) != d.getTimezoneOffset(); 
}

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to datetime

Comparing two joda DateTime instances How to format DateTime in Flutter , How to get current time in flutter? How do I convert 2018-04-10T04:00:00.000Z string to DateTime? How to get current local date and time in Kotlin Converting unix time into date-time via excel Convert python datetime to timestamp in milliseconds SQL Server date format yyyymmdd Laravel Carbon subtract days from current date Check if date is a valid one Why is ZoneOffset.UTC != ZoneId.of("UTC")?

Examples related to dst

How to check if DST (Daylight Saving Time) is in effect, and if so, the offset? Daylight saving time and time zone best practices

Examples related to timezone-offset

Free Rest API to retrieve current datetime as string (timezone irrelevant) How to check if DST (Daylight Saving Time) is in effect, and if so, the offset? javascript toISOString() ignores timezone offset Determine a user's timezone

Examples related to datetime-conversion

How to convert ZonedDateTime to Date? How to check if DST (Daylight Saving Time) is in effect, and if so, the offset? Convert from days to milliseconds Compare DATETIME and DATE ignoring time portion