这是我的一点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小时。我不知道如何检查夏令时是否有效。

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


这段代码使用了这样一个事实,即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!");
}

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

如果一月抵消>六月抵消,客户端在北半球 如果1月偏移量< 6月偏移量,则客户在南半球 如果没有差异,则客户端时区不遵守夏令时

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

如果等于北半球的6月,则当前时区为夏时制(+1小时) 如果等于南半球的1月,则当前时区为夏时制(+1小时)


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

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


基于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提供的溶液中的东西-但我仍然会提前半年,当发现两个不同的偏移时跳出循环]


你很接近了,但是有点差。你永远不需要计算你自己的时间,因为它是你自己的时钟的结果。它可以检测您是否在您的位置使用日光节约时间,但不能检测由偏移量产生的远程位置:

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.


这个答案与公认的答案非常相似,但没有覆盖Date原型,并且只使用一个函数调用来检查日光节约时间是否有效,而不是两个。


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

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

然后检查dates timezone是否等于该最小值。如果是,那么我们就是在夏令时;否则我们就不是了。

下面的函数使用这个算法。它接受一个日期对象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();    
}

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


js库在它的time对象上提供了一个. 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

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

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

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

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


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

MDN Web文档

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

有关时区的信息由互联网编号分配机构(iana)维护。

Iana时区

joda.org提供了一个格式很好的时区表

时区

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

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

夏时制总是比夏天的“常规”时间早。你在秋天把时钟调慢了。(“后退”口号,记住该做什么)

因此,美国/纽约夏令时(冬季)比正常时间早一小时。举个例子,纽约市夏天的下午5点,现在是下午4点。美国/纽约夏令时。“America/New_York”时间名称是“Long Format”时区名称。美国东海岸通常称他们所在的时区为东部标准时间(EST)。

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

查看joda.org上的时区表,找到“America/New_York”的时区。在标准偏移前会有一个负号。

地球绕地轴逆时针旋转。在格林威治看日出的人比纽约市的人早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。但这并没有告诉您今天浏览器时区是否使用夏令时。所以,你需要得到今天的时区偏移。

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

console.log('todaysTimeZone : ' + todaysTimeZone)

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

如果今天的时区偏移量和夏季时区偏移量是相同的,而夏季和冬季时区偏移量是不同的,那么根据逻辑推断,今天一定不是夏时制。

你能忽略比较夏季和冬季时区偏移量吗(要知道这个时区是否使用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;
}

但问题是,你不知道今天是冬天还是夏天。每个时区都有自己的夏令时开始和停止的规则。您需要跟踪世界上每个时区的每个时区的规则。所以,如果有更好更简单的方法,你也可以用更好更简单的方法来做。

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

最后的逻辑是:

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
}

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

设x为在不考虑夏时制的情况下进入利息年的预期毫秒数。 设y为从感兴趣日期的年份开始到Epoch的毫秒数。 设z为自感兴趣的完整日期和时间的Epoch以来的毫秒数 设t是z减去x和y: z - y - x。这就得到了由于夏令时而产生的偏移量。 如果t为零,则DST不生效。如果t不为零,则DST生效。

"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)) // 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) -1 + // first day in the year is day 1 (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");

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

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 29ms on FireFox.

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

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

使用Date.toString()是否有问题。indexOf('Daylight Time') > -1

"" +新日期()

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

"" +新日期(…)

5月01日100033 00:00:00 GMT-0400(东部夏令时)

这似乎与所有浏览器兼容。


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

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

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


更新: 在尝试在自定义日期时间选择器中使用这些函数后,我注意到从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));


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

新日期()getUTCHours() + gettimezoneset(‘欧洲/阿姆斯特丹’)/ 1000 / 60;