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

前端 未结 14 770
栀梦
栀梦 2020-11-22 09:46

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         


        
相关标签:
14条回答
  • 2020-11-22 10:19

    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.

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

    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;
    }
    
    0 讨论(0)
  • 2020-11-22 10:19

    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.

    0 讨论(0)
  • 2020-11-22 10:22

    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
    
    0 讨论(0)
  • 2020-11-22 10:22

    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.

    0 讨论(0)
  • 2020-11-22 10:24

    This code uses the fact that getTimezoneOffset returns a greater value during Standard Time versus Daylight Saving Time (DST). Thus it determines the expected output during Standard Time, and it compares whether the output of the given date the same (Standard) or less (DST).

    Note that getTimezoneOffset returns positive numbers of minutes for zones west of UTC, which are usually stated as negative hours (since they're "behind" UTC). For example, Los Angeles is UTC–8h Standard, UTC-7h DST. getTimezoneOffset returns 480 (positive 480 minutes) in December (winter, Standard Time), rather than -480. It returns negative numbers for the Eastern Hemisphere (such -600 for Sydney in winter, despite this being "ahead" (UTC+10h).

    Date.prototype.stdTimezoneOffset = function () {
        var jan = new Date(this.getFullYear(), 0, 1);
        var jul = new Date(this.getFullYear(), 6, 1);
        return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
    }
    
    Date.prototype.isDstObserved = function () {
        return this.getTimezoneOffset() < this.stdTimezoneOffset();
    }
    
    var today = new Date();
    if (today.isDstObserved()) { 
        alert ("Daylight saving time!");
    }
    
    0 讨论(0)
  • 2020-11-22 10:25

    ES6 Style

    Math.min(...[0, 6].map(v => new Date(95, v, 1).getTimezoneOffset() * -1));
    
    0 讨论(0)
提交回复
热议问题