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

IT技术 javascript datetime dst timezone-offset datetime-conversion
2021-01-10 05:18:44

这是我需要的一些 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 是否有效。

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

6个回答

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

请注意,getTimezoneOffset返回UTC以西区域的分钟数,通常表示为小时数(因为它们“落后”于 UTC)。例如,洛杉矶是UTC-8h标准,UTC-7h DST。在 12 月(冬季,标准时间)返回(正 480 分钟),而不是. 它返回东半球的负数(例如冬季的悉尼,尽管这是“超前”(UTC+10h))。getTimezoneOffset480-480-600

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 期间之外。此外,在 TZDB 的所有时区中(有一个微不足道的例外),两个偏移量中较大的一个是 DST 偏移量。由于 JavaScriptgetTimezoneOffset返回相反值,Math.max因此确实返回标准偏移量。代码是正确的。
2021-03-13 05:18:44
这在一般情况下不起作用,例如有些国家在某些年份没有观察到夏令时,也有些国家在斋月期间恢复夏令时。除此之外,Date 的 ECMAScript 定义被破坏,并且在某些实现中对 TZ 环境变量的处理也被破坏。所有这些结合在一起使这种方法不可靠。您最好使用不使用日期的库,例如 timezonecomplete
2021-03-14 05:18:44
此代码在不遵守夏令时的国家/地区不起作用,例如南非或冰岛;这意味着如果您使用它来与这些国家/地区的其他时区进行比较,则不会在那里显示正确的时间。建议一直使用UTC,手动检查当前时间是否在一定的夏令时范围内。然后只需将正常时间UTC偏移量更改+1即可获得DST。
2021-03-31 05:18:44
对于使用以 UTC 作为本地时区的 AWS Lambda 或 Node 的任何人,这将不起作用。getTimezoneOffset() 将在 1 月和 7 月返回 0。
2021-04-06 05:18:44
但是,如果任何时区改变了它的定义,使得 1 月 1 日和 7 月 1 日都在 DST 中,或者都不在 DST 中(并且 DST 仍然适用),那么此代码将无法在该时区中工作。
2021-04-08 05:18:44

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


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

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

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

以下函数使用此算法。它接受一个日期对象,如果夏令时对该日期有效,d返回truefalse如果不是:

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(); 
}
这有效,但如果当前时区中没有 DST,那么它也会导致 true,这是不正确的。如果您将其切换为Math.max(...) != d.get...(),如果在给定的时区中观察到 DST 并且日期当前在 DST 中,它将返回 true。如果未遵守 DST 或日期与标准偏移量匹配,它将返回 false。
2021-03-21 05:18:44

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

  • 如果 1 月抵消 > 6 月抵消,则客户在北半球
  • 如果 1 月偏移 < 6 月偏移,则客户端位于南半球
  • 如果没有区别,客户端时区不遵守夏令时

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

  • 如果等于六月,北半球,则当前时区为 DST(+1 小时)
  • 如果等于一月,南半球,则当前时区为 DST(+1 小时)
您不需要半球,因为接受的答案清楚地表明:)
2021-03-16 05:18:44
问题是如何确定 DST 在客户端机器 Kebman 的时区中是否有效,而不是如何显示日期,Web 客户端已经为您处理了。
2021-03-21 05:18:44
为什么需要半球?如果当前日期的 getTimezoneOffset() 等于两个 getTimezoneOffset() 中的较小者,那么说它的 DST 是否还不够?[和偏移量是两者之间的差异?]
2021-03-26 05:18:44
您应该在 1 月和 7 月(或 2 月和 8 月、3 月和 9 月等)之间进行检查,因为它们相隔 6 个月。
2021-03-30 05:18:44
这行不通。最好的办法是确保使用 UTC 时间并手动设置所需区域的偏移量。然后手动查找同一区域(如果有)的 DST 的开始和结束时间。然后您要检查该区域的时间是否在 DST 范围内,然后用 +1 相应地更新偏移量。这使得比较遵守夏令时的国家和不遵守夏令时的国家成为可能。
2021-04-03 05:18:44

我今天遇到了同样的问题,但由于我们的夏令时开始和停止的时间与美国不同(至少根据我的理解),我使用了略有不同的路线。

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 进行比较,看看哪一个匹配。

不需要创建 365 个值,一种在确定偏移量变化后立即停止的二进制搜索方法应该会更加有效,即使在没有观察到夏令时也是如此。所有这些方法都假设地方每年都遵守夏令时,这不一定是真的。地方不时采用和放弃夏令时(尽管 ECMAScript 假定当前规则,无论它们位于哪个区域,始终适用)。
2021-03-15 05:18:44
Rob - 如果您不知道在哪里搜索(即您要查找的位置在您的测试点上方还是下方?),您如何通过二分搜索来完成此操作?
2021-03-23 05:18:44
我们也是这样做的。也就是说,计算出目标时区中 DST 在一年中的变化时间,并计算当天和最近更改日期的偏移量。它们要么相差一个小时,要么相等(假设所讨论的时区是一个小时偏移量)。
2021-04-06 05:18:44

基于 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。[并在每个测试年执行一次]。

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

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