如何检查 DST(夏令时)是不是有效,如果有效,偏移量?

Posted

技术标签:

【中文标题】如何检查 DST(夏令时)是不是有效,如果有效,偏移量?【英文标题】:How to check if DST (Daylight Saving Time) is in effect, and if so, the offset?如何检查 DST(夏令时)是否有效,如果有效,偏移量? 【发布时间】:2012-08-06 22:41:11 【问题描述】:

这是我需要的一些 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 小时。我不知道如何检查 DST 是否生效。

我如何知道夏令时的开始和结束时间?

【问题讨论】:

【参考方案1】:

此代码使用getTimezoneOffset 在标准时间与夏令时 (DST) 期间返回更大 值这一事实。因此,它确定标准时间期间的预期输出,并比较给定日期的输出是相同(标准)还是更少(DST)。

请注意,getTimezoneOffset 返回 UTC west 区域的分钟数,通常表示为 小时(因为它们'落后于 UTC)。例如,洛杉矶是 UTC–8h 标准,UTC-7h DST。 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!");

【讨论】:

我可以验证这在国际上是否有效。目前没有使用任何形式的 DST 的时区,其中 1 月 1 日和 7 月 1 日都在 DST 期间或两者都在 DST 期间之外。此外,在 TZDB (with one trivial exception) 中的所有时区中,两个偏移量中较大的一个是 DST 偏移量。由于 javascriptgetTimezoneOffset 返回反值,那么 Math.max 确实返回 standard 偏移量。代码是正确的。 但是,如果任何时区改变了它的定义,使得 1 月 1 日和 7 月 1 日都在 DST 中,或者都 not 在 DST 中(并且 DST 仍然适用) ,则此代码将无法在该区域中运行。 这通常不起作用,例如有些国家在某些年份没有遵守 DST,也有些国家在斋月期间恢复 DST。除此之外,在某些实现中,Date 的 ECMAScript 定义被破坏,并且 TZ 环境变量的处理也被破坏。所有这些结合起来使这种方法不可靠。您最好使用不使用 Date 的库,例如时区完成 此代码在不遵守 DST 的国家/地区不起作用,例如南非或冰岛;这意味着如果您使用它与这些国家的其他时区进行比较,它不会显示那里的正确时间。建议一路使用UTC,手动检查现在时间是否在一定的夏令时范围内。然后只需将正常时间 UTC 偏移量更改 +1 即可获得 DST。 对于使用 AWS Lambda 或以 UTC 作为本地时区的节点的任何人,这将不起作用。 getTimezoneOffset() 在 1 月和 7 月都将返回 0。【参考方案2】:

这个答案与接受的答案非常相似,但没有覆盖Date 原型,并且只使用一个函数调用来检查夏令时是否有效,而不是两个。


想法是,由于没有国家遵守持续 7 个月的 DST[1],因此在遵守 DST 的地区,1 月与 UTC 时间的偏移量将不同于 7 月的偏移量.

虽然夏令时移动时钟向前,但 JavaScript 在标准时间期间总是返回一个更大的值。因此,获取 1 月和 7 月之间的最小偏移量将获得 DST 期间的时区偏移量。

然后我们检查日期时区是否等于该最小值。如果是,那么我们在 DST;否则我们不是。

以下函数使用此算法。它接受一个日期对象d,如果夏令时对该日期有效,则返回true,否则返回false

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

【讨论】:

这行得通,但如果当前时区中没有夏令时,那么它也将返回 true,这是不正确的。如果您将其切换为Math.max(...) != d.get...(),它将返回真如果在给定时区观察到 DST 并且日期当前在 DST。如果没有遵守 DST 或日期与标准偏移量匹配,它将返回 false。 似乎答案已被编辑以适应上面评论中的修复。 @Toastrackenigma 您能否确认并添加说明是这种情况? 是的,这是@GreySage 的一个好地方,我在他们评论后很快就编辑了答案。【参考方案3】:

创建两个日期:一个在六月,一个在一月。比较他们的getTimezoneOffset() 值。

如果 1 月偏移 > 6 月偏移,则客户端位于北半球 如果一月偏移 如果没有差异,则客户端时区不遵守 DST

现在检查当前日期的getTimezoneOffset()

如果等于北半球六月,则当前时区为 DST(+1 小时) 如果等于 1 月,南半球,则当前时区为 DST(+1 小时)

【讨论】:

为什么需要半球?如果当前日期的 getTimezoneOffset() 等于两个 getTimezoneOffset() 中的较小者,那么说它的 DST 是否还不够? [和偏移量是两者的区别?] 你不需要半球,因为接受的答案清楚地表明:) 这行不通。最好的办法是确保使用 UTC 时间并手动设置所需区域的偏移量。然后手动查找同一区域(如果有)的 DST 的开始和结束。然后您要检查该区域的时间是否在 DST 范围内,然后用 +1 相应地更新偏移量。这样就可以比较遵守 DST 和不遵守 DST 的国家/地区。 问题是如何确定 DST 是否在客户端机器 Kebman 的时区中生效,而不是如何显示日期,Web 客户端已经为您处理了。 您应该在 1 月和 7 月(或 2 月和 8 月、3 月和 9 月等)之间进行检查,因为它们相隔 6 个月。【参考方案4】:

我今天也遇到了同样的问题,但是由于我们的夏令时开始和结束的时间与美国不同(至少根据我的理解),所以我使用了稍微不同的路线..

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

然后您只需将当前时区偏移量与 DST 和非 DST 进行比较,看看哪个匹配。

【讨论】:

这也是我们的做法。也就是说,找出目标时区中 DST 更改的时间,并计算当天和最近更改日期的偏移量。它们将相差一个小时或相等(假设所讨论的时区是一个小时偏移量)。 不需要创建 365 个值,一旦确定偏移量变化就停止的二进制搜索方法应该非常有效,即使在不遵守夏令时的情况下也是如此。所有这些方法都假设地方每年都遵守夏令时,这不一定是正确的。地方不时采用和放弃夏令时(尽管 ECMAScript 假定当前规则,无论它们位于何处,始终适用)。 Rob - 如果你不知道在哪里搜索,你怎么能通过二分搜索来做到这一点(即你要找的地方是在你的测试点之上还是之下?)【参考方案5】:

根据 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(); 
    ;

考虑到所有 cmets 和先前建议的答案,特别是它,它试图获得所有世界中最好的:

1) 缓存每年 stdTimezoneOffset 的结果,以便在同一年测试多个日期时无需重新计算。

2) 并不假定 DST(如果存在的话)一定是在 7 月, 即使它会在某个时间点和某个地方是任何一个月,它也会起作用。 但是,如果确实是 7 月(或接近几个月)确实是 DST,那么在性能方面它会运行得更快。

3) 更糟糕的情况是它会比较每个月第一天的 getTimezoneOffset。 [并且每个测试年执行一次]。

它仍然做的假设是,如果有 DST 期大于一个月。

如果有人想消除这种假设,他可以将循环更改为更类似于 Aaron Cole 提供的解决方案中的内容 - 但我仍然会提前半年跳出循环,当找到两个不同的偏移量时,我会跳出循环]

【讨论】:

【参考方案6】:

JavaScript 中的 getTimezoneOffset() 方法在浏览器中返回从 00:00 时区偏移的分钟数。例如,夏令时 (DST) 中的 America/New_York 时区返回数字 300。300 分钟与零相差 5 小时。 300 分钟除以 60 分钟等于 5 小时。每个时区都与零时区进行比较,+00:00 / Etc/GMT / 格林威治时间。

MDN Web Docs

接下来您必须知道的是,偏移量与实际时区的符号相反。

时区信息由 Internet 号码分配机构 (iana) 维护

iana time zones

joda.org 提供格式精美的时区表

joda-time Time Zones

+00:00 或 Etc/GMT 是格林威治时间

所有时区都与 +00:00 / "Etc/GMT" / 格林威治时间偏移

夏令时总是比夏季的“常规”时间更早。你把你的时钟拨回了秋季。 (“Fall Back”口号记住该做什么)

因此,夏令时(冬季)中的 America/New_York 时间比常规时间早一小时。例如,通常是下午 5 点。夏天在纽约市的下午,现在是下午 4 点。 America/New_York 夏令时。名称“America/New_York”时间是“长格式”时区名称。美国东海岸通常将其时区称为东部标准时间 (EST)

如果您想将今天的时区偏移量与其他日期的时区偏移量进行比较,您需要知道时区偏移量的数学符号(+/-“正/负”)与时间相反区域。

查看 joda.org 上的时区表,找到“America/New_York”的时区,它会在 Standard Offset 前面有一个负号。

地球绕它的轴逆时针旋转。一个在格林威治看日出的人在纽约市有人看到日出之前 5 小时看到了日出。而美国东海岸的人看到日出后,美国西海岸的人会看到日出。

您需要了解所有这些是有原因的。这样您就可以在逻辑上确定某些 JavaScript 代码是否正确获取 DST 状态,而无需在一年中的不同时间测试每个时区。

想象一下,现在是纽约市的 11 月,时钟拨快了一个小时。在纽约市的夏季,偏移量为 240 分钟或 4 小时。

您可以通过创建一个 7 月的日期然后获取偏移量来测试这一点。

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

console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

浏览器的开发者工具控制台日志会打印什么?

答案是:240

所以,现在您可以在 1 月创建一个日期,然后查看浏览器返回的冬季时区偏移量。

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)

答案是:300

显然 300 大于 240。那么,这是什么意思?您是否应该编写代码来测试冬季偏移量是否大于夏季偏移量?还是夏季偏移小于冬季偏移?如果夏季和冬季时区偏移之间存在差异,那么您可以假设该时区使用 DST。但这并不能告诉您 今天 是否使用 DST 作为浏览器时区。因此,您需要获取今天的时区偏移量。

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

console.log('todaysTimeZone : ' + todaysTimeZone)

答案是:? - 取决于一年中的时间

如果今天的时区偏移量和夏季时区偏移量相同,AND夏季和冬季时区偏移量不同,那么逻辑推论,今天一定不是夏令时。

你能省略比较夏季和冬季时区偏移量吗(要知道这个时区是否使用 DST)而只将今天的时区偏移量与夏季 TZ 偏移量进行比较,总能得到正确的答案吗?

today's TZ Offset !== Summer TZ Offset

嗯,今天是冬天还是夏天?如果您知道,那么您可以应用以下逻辑:

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

但问题是,您不知道今天的日期是在冬季还是夏季。每个时区都可以有自己的 DST 何时开始和停止的规则。您需要跟踪世界上每个时区的每个时区规则。所以,如果有更好更简单的方法,那就不如做更好更简单的方法。

我们剩下的就是,你需要知道这个时区是否使用 DST,然后将今天的时区偏移量与夏季时区偏移量进行比较。这总会给你一个可靠的答案。

最后的逻辑是:

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

判断浏览器时区是否使用夏令时的函数:

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

【讨论】:

According to dateandtime.com DST 于 2019 年 3 月 10 日开始,因此是夏季,而不是冬季,纽约的 DST 偏移量是 -4,而不是 -5。 如果需要对答案进行改进或修复,请进行编辑,我们将对其进行审核。【参考方案7】:

moment.js 库在其时间对象上提供了一个 .isDst() 方法。

moment#isDST 检查当前时刻是否处于夏令时。

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

【讨论】:

我试过 var moment = require('moment'); this.logger.info(moment([2011, 2, 12]).isDST()); this.logger.info(moment([2011, 2, 14]).isDST());两者都是错误的 夏令时更改日期因国家而异,即使在同一国家/地区的各州(即亚利桑那州)之间也是如此。在美国是在 2011-03-13,而在德国是在 2011-03-31。所以结果会根据 moment.js 配置的时区而有所不同。 它甚至在亚利桑那州范围内有所不同timeanddate.com/time/us/arizona-no-dst.html 我只有偏移量!如何检查我的日期是否在夏令时?我试过这个moment.utc().utcOffset('-05:00').isDST() 不工作! @HenonoaH 这是不可能的,因为这取决于国家,在某些国家甚至取决于州。您需要知道要确定 DST 状态的位置的时区名称。例如“Europe/Berlin”或“CEST”(而 CEST 已经暗示没有 DST,因为“Central European Summer Time”或“ET”存在为“EST”和“EDT”en.wikipedia.org/wiki/Eastern_Time_Zone)。【参考方案8】:

适用于所有时区的面向未来的解决方案

    x 为感兴趣年份的预期毫秒数,不考虑夏令时。 让y 为自关注日期年初以来Epoch 以来的毫秒数。 让z 为自感兴趣的完整日期和时间的Epoch 以来的毫秒数 让tzxy 的减法:z - y - x。这会产生由于 DST 造成的偏移量。 如果 t 为零,则 DST 无效。如果t 不为零,则夏令时生效。

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

我相信上面的代码 sn-p 优于这里发布的所有其他答案,原因有很多。

此答案适用于所有时区,即使是Antarctica/Casey。 夏令时可能会发生很大变化。可能在 20 年后,某些国家/地区可能有 3 个 DST 周期,而不是正常的 2 个。此代码通过返回以毫秒为单位的 DST 偏移量来处理这种情况,而不仅仅是 DST 是否有效。 一年中月份的大小和闰年的工作方式非常适合让我们的时间与太阳保持同步。哎呀,它运行得如此完美,以至于我们所做的只是adjust mere seconds here and there。我们当前的闰年系统自 February 24th, 1582 以来一直有效,并且在可预见的未来可能会继续有效。 此代码适用于不使用 DST 的时区。 此代码适用于实施 DST 之前的历史时期(例如 1900 年代)。 此代码已最大限度地进行整数优化,如果在紧密循环中调用,应该不会有任何问题。运行上面的代码 sn-p 后,向下滚动到输出的底部以查看性能基准。我的电脑在 FireFox 上可以在 29 毫秒内处理 16384 个日期。

但是,如果您不准备超过 2 个 DST 周期,则可以使用以下代码来确定 DST 是否作为布尔值有效。

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

【讨论】:

【参考方案9】:

我发现使用Moment.js 库和此处描述的一些概念(比较一月到六月)效果很好。

这个简单的函数将返回用户所在的时区是否遵守夏令时:

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

检查这是否有效的一种简单方法(在 Windows 上)是将您的时区更改为非 DST 区域,例如 Arizona 将返回 false,而 EST 或 PST 将返回 true。

【讨论】:

【参考方案10】:

你已经接近了,但有点偏离。您永远不需要计算自己的时间,因为它是您自己时钟的结果。它可以检测您是否在您的位置使用夏令时,但不适用于偏移量产生的远程位置:

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

如果他们在夏令时,这仍然是错误的并且会关闭一个小时。如果他们当前是否在 DST 内,您需要一个远程时间帐户并相应地进行调整。尝试计算这个并将您的时钟更改为 - 假设 2015 年 2 月 1 日并将时钟重新设置一个小时,就像在 DST 之外一样。然后计算一个仍应落后 2 小时的地方的偏移量。它将比两小时窗口提前一小时显示。您仍然需要考虑时间并进行调整。我为纽约和丹佛做了这件事,但在丹佛总是走错(提前一小时)。

【讨论】:

【参考方案11】:

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

如果观察到夏令时,moment().isDST(); 会给你。

它还具有帮助功能来为您计算相对时间。您无需手动计算 例如moment("20200105", "YYYYMMDD").fromNow();

【讨论】:

你有没有注意到“使用 Moment.js 的答案”是already given in 2017?【参考方案12】:

我最近需要使用 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>

【讨论】:

【参考方案13】:

使用Date.toString().indexOf('Daylight Time') &gt; -1是否有问题

"" + new Date()

1 月 1 日星期六 100050 00:00:00 GMT-0500(东部标准时间)

"" + new Date(...)

Sun May 01 100033 00:00:00 GMT-0400(东部日光时间)

这似乎兼容所有浏览器。

【讨论】:

是的,它并不适用于全世界。在欧洲的夏天,你会收到"Thu Jul 02 2020 14:07:01 GMT+0200 (Central European Summer Time)"【参考方案14】:

ES6 风格

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

【讨论】:

你能解释一下这种神秘的单线是如何以及为什么起作用的吗?【参考方案15】:

更新: 在尝试在自定义 datetime 选择器中使用这些功能后,我注意到从 3 月切换到 4 月会按预期切换时区,因为我的区域在 3 月切换 DST。出乎意料的是,它正在切换到下一个时区,而不是在同一时区的 Standard 和 Daylight 之间切换。

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

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

工作流程更新:

t 参数默认为new Date() 对于固定时间,传入现有的Date 对于当前时间,传入null 或不传入任何内容 std() 更新为使用 t.setMonth(v); 将月份更改为固定时间 .getTimezoneOffset() 不能链接到 .setMonth(),所以我们需要从单行符号转换为使用闭包 ()、终止符 (;) 和 return console.log() 示例每个月循环(011) 需要使用相同的时间戳克隆固定日期对象 (let ts = +t;) Date 类型之前的 + 将其转换为带有 Unix 时间戳的 number Date() 也接受 Unix 时间戳来创建固定时间 如果我们不克隆它,每个调用都会传递相同的 Date 对象,并将月份设置为 6,这违背了目的 好的,我们实际上并没有克隆,只是使用相同的设置创建一个新对象;相同的区别;)

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 的紧凑而神秘的解决方案,将其转变为一组可重用的函数。

工作流程:

所有函数的作用域都在命名空间ns 中,因此它们不会与代码中可能具有相同名称的其他函数发生冲突 命名空间还允许紧凑的函数表示法; std: ()=&gt;Math.max(), 等价于 function std() return Math.max(); std() 返回标准时间的时区偏移量 [0, 6] 设置没有 DST 的月份和有 DST 的月份的比较 0 一月份,因为 Date.setMonth() 是零索引 6 七月 显然,每个人的标准时间都不是一月,所以我们必须检查一月和七月 ...[] 将月份的 Array 转换为 Set,因此我们可以应用 map() 函数 原始数组无法运行map() map() 在同一个函数上运行一组变量并返回一个结果数组 用年、月、日创建一个新的Date对象 年份(示例中为95)是任意的,因为年份对于此计算并不重要 月份插入我们的值[0, 6] 作为变量v 日期(示例中为1)也是任意的 从逻辑上讲,我们可以创建一个new Date(),然后是.setMonth(v),但使用任意数字更紧凑、更快 现在我们有了日期,getTimezoneOffset() 返回每​​个月的偏移量并将它们推送到结果数组中 Math.max() 从结果中找到最大值,即标准时间偏移量 is_dst() 检查当前是否为夏令时 new Date().getTimezoneOffset() 获取当前偏移量,无论是否有夏令时 ns.std() 获取标准时间的偏移量 如果当前偏移量较低,则为 DST utc() 以 UTC 表示法返回字符串 std 参数默认为关闭 z = std ? ns.std() : new Date().getTimezoneOffset() 根据标志将时间设置为 DST 或标准 zm = z % 60 会记录分钟数,例如某些区域使用 30 分钟 (z &gt; 0 ? '-' : '+') 为每个 UTC 符号分配正确的符号;正偏移值在符号中显示为负偏移 (z / 60) 根据符号以单位数格式捕获小时数,因此对于两位数格式无需 .toString().padStart(2,'0)` (zm ? ':' + zm : '') 附加分钟(如果它们存在于时区)

由于此版本旨在紧凑,您可以通过去除多余的空白来节省更多空间。虽然这确实是一个缩小器的工作。

std:()=&gt;Math.max(...[0,6].map(v=&gt;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) => 
    let z = std ? ns.std() : new Date().getTimezoneOffset(),
      zm = z % 60;
    return 'UTC' + (z > 0 ? '-' : '+') + (z / 60) + (zm ? ':' + zm : '');
  
;

console.log(ns.std(), ns.is_dst(), ns.utc(), ns.utc(1));

【讨论】:

【参考方案16】:

用https://date-fns.org/v2.22.1/docs/Time-Zones一行就可以解决

new Date().getUTCHours() + getTimezoneOffset('Europe/Amsterdam') / 1000 / 60 / 60;

【讨论】:

什么意思?

以上是关于如何检查 DST(夏令时)是不是有效,如果有效,偏移量?的主要内容,如果未能解决你的问题,请参考以下文章

确定 DST 是不是对给定 time_t 的指定时区有效

检查夏令时是不是有效?

检查夏令时是否有效?

有没有办法检查它是不是是 UTC 的 DST(夏令时)?

检测当前是不是启用 DST

如何确定夏令时是不是在 C 中处于活动状态?