这是我的一点JS代码,这是需要的:

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);

我想在“前”得到日期时间,但如果DST正在使用,那么日期是1小时。我不知道如何检查夏令时是否有效。

我怎样才能知道夏令时何时开始和结束?


当前回答

更新: 在尝试在自定义日期时间选择器中使用这些函数后,我注意到从3月切换到4月会像预期的那样切换时区,因为我的区域在3月切换夏令时。出乎意料的是,它正在切换到下一个时区,而不是在同一时区的标准时区和夏令时时区之间切换。

原来,这是因为我原来的函数总是为当前时间或过去的任意固定时间创建新的Date()。将其与3月和4月的相对时间进行比较,意味着它将在逻辑上检测到夏令时切换为切换时区。

解决办法是将相对时间传递到效用函数中,所以我所有的比较都是相对时间,而不是现在或任意固定的时间。失去了一些紧凑性,但现在逻辑可以根据需要工作。

更新工作流程:

t parameter defaults to new Date() For fixed time, pass in an existing Date For current time, pass in null or nothing std() updated to use t.setMonth(v); to change the month for fixed times .getTimezoneOffset() cannot chain to .setMonth(), so we need to swap from one-line notation to use closures ({}), terminators (;), and return console.log() example loops through each month (0 to 11) The fixed date object needs to be cloned using the same timestamp (let ts = +t;) The + before the Date type casts it to a number with the Unix timestamp Date() also accepts Unix timestamps to create fixed times If we don't clone it, each call would pass around the same Date object with the months set to 6, which defeats the purpose Ok, we're not actually cloning, just creating a new object using the same settings; same difference ;)

let ns = { std: (t = new Date()) => Math.max(...[0, 6].map(v => { t.setMonth(v); return t.getTimezoneOffset(); })), is_dst: (t = new Date()) => t.getTimezoneOffset() < ns.std(t), utc: (t, std = 0) => { t = t || new Date(); let z = std ? ns.std(t) : t.getTimezoneOffset(), zm = z % 60; return 'UTC' + (z > 0 ? '-' : '+') + (z / 60) + (zm ? ':' + zm : ''); } }; //current time only console.log(ns.std(), ns.is_dst(), ns.utc(), ns.utc(null, 1)); //iterate each month let t = new Date(2021,0,1); for (let i = 0; i < 12; i++) { t.setMonth(i); let ts = +t; console.log(t.toDateString().split(" ")[1], ns.std(new Date(ts)), ns.is_dst(new Date(ts)), ns.utc(new Date(ts)), ns.utc(new Date(ts), 1)); }


扩展来自@nkitku的紧凑而神秘的解决方案,将其转换为一组可重用的函数。

工作流程:

All functions are scoped in a namespace ns so they don't conflict with other functions in the code that may have the same name Namespacing also allows for compact function notation; std: ()=>Math.max(), is equivalent to function std(){ return Math.max(); } std() returns the timezone offset in Standard Time [0, 6] sets up a comparison of a month without DST and a month with DST 0 for January, since Date.setMonth() is zero-indexed 6 for July Apparently, Standard Time is not in January for everyone, so we have to check both January and July ...[] converts the Array of months to a Set so we can apply the map() function Raw arrays cannot run map() map() runs a set of variables on the same function and returns an array of results Create a new Date object with year, month, day The year (95 in the example) is arbitrary since the year isn't important for this calculation The month plugs in our values [0, 6] as a variable v The day (1 in the example) is also arbitrary Logically we could have created a new Date(), then .setMonth(v), but using the arbitrary numbers is more compact and faster Now that we have the dates, getTimezoneOffset() returns the offsets for each month and pushes them to the results array Math.max() finds the largest value from the results, which will be the Standard Time offset is_dst() checks if it is currently Daylight Savings Time new Date().getTimezoneOffset() gets the current offset, with or without DST ns.std() gets the offset in Standard Time If the current offset is lower, then it's DST utc() returns a string in UTC notation The std parameter defaults to off z = std ? ns.std() : new Date().getTimezoneOffset() sets the time to DST or standard based on the flag zm = z % 60 captures minutes since some zones use 30 minutes for example (z > 0 ? '-' : '+') assigns the correct sign per UTC notation; positive offset values are shown as negative offsets in the notation (z / 60) captures the hours in single-digit format per the notation, so no need to .toString().padStart(2,'0)` for double-digit format (zm ? ':' + zm : '') appends minutes if they exist for the timezone

由于这个版本是紧凑的,您可以通过去掉多余的空白来节省更多的空间。不过这真的是一个迷你机的工作。

std:()=>Math.max(...[0,6].map(v=>new Date(95,v,1).getTimezoneOffset())),

Const ns = { std: () => Math.max(…(0, 6)。map(v => new Date(95, v, 1).getTimezoneOffset())), is_dst: () => new Date().getTimezoneOffset() < ns.std(), Utc: (std = 0) => { 让z = STD ?ns.std(): new Date().getTimezoneOffset(), Zm = z % 60; 返回'UTC' + (z > 0 ?'-': '+') + (z / 60) + (zm ?':' + zm: "); } }; ns.is_dst console.log (ns.std () (), ns.utc (), ns.utc (1));

其他回答

这段代码使用了这样一个事实,即getTimezoneOffset在标准时间与日光节约时间(DST)期间返回更大的值。因此,它确定标准时间内的预期输出,并比较给定日期的输出是否相同(标准)或更少(DST)。

注意,getTimezoneOffset对于UTC以西的区域返回正数分钟,通常表示为负小时(因为它们“落后”UTC)。例如,洛杉矶是UTC-8h标准,UTC-7h夏令时。getTimezoneOffset在12月(冬季,标准时间)返回480(正480分钟),而不是-480。它返回东半球的负数(例如冬季悉尼的-600,尽管这是“超前”(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!");
}

使用Moment.js (https://momentjs.com/)

.isDST时刻()();如果日光节约被观察,将会给你。

还有辅助功能,为您计算相对时间。你不需要手动计算 例如moment("20200105", "YYYYMMDD").fromNow();

我发现使用Moment.js库和这里描述的一些概念(比较Jan和June)效果非常好。

这个简单的函数将返回用户所在的时区是否遵守日光节约时间:

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

检查它是否有效的一个简单方法(在Windows上)是将您的时区更改为非夏令时区域,例如亚利桑那州将返回false,而EST或PST将返回true。

我最近需要用UTC和DST创建一个日期字符串,根据Sheldon的回答,我把它放在一起:

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

基于Matt Johanson对Sheldon Griffin提供的解决方案的评论,我创建了以下代码:

    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(); 
    };

考虑到所有的评论和之前建议的答案,它试图得到所有世界的最好结果,特别是:

1)缓存每年stdTimezoneOffset的结果,这样当您在同一年测试多个日期时就不需要重新计算它。

2)它没有假设夏令时(如果它存在的话)一定是在7月, 即使在任何一个月的某个时间某个地点,它也会起作用。 但是性能方面,如果七月(或临近月份)确实是DST,它会工作得更快。

3)在更糟糕的情况下,它将比较每个月的第一个getTimezoneOffset。[并且每年测试一次]。

它所做的假设仍然是,如果有夏令时周期比一个月大。

如果有人想要消除这种假设,他可以把循环变成更像Aaron Cole提供的溶液中的东西-但我仍然会提前半年,当发现两个不同的偏移时跳出循环]