# 如何检查DST（夏令时）是否有效，以及偏移是否有效？

2020/11/03 01:22 · javascript ·  · 0评论

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

``````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()) {
}
``````

• 如果1月抵消> 6月抵消，则客户在北半球
• 如果一月抵消量<六月抵消量，则客户在南半球
• 如果没有差异，则客户端时区不遵守DST

• 如果等于北半球6月，则当前时区为DST（+1小时）
• 如果等于一月，南半球，则当前时区为夏令时（+1小时）

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

I was faced with this same problem today but since our daylight saving starts and stops at differing times from the USA (at least from my understanding), I used a slightly different route..

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

Then you simply compare the current timezone offset with DST and nonDST to see which one matches.

``````    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）它不假设DST（如果有的话）一定是在7月，并且即使在某个时间，某个地点是任何月份都可以使用。但是，从性能角度来看，如果确实是7月（或接近几个月）确实是DST，它将更快地工作。

3）更糟糕的情况是，它将比较每月第一天的getTimezoneOffset。[并且每年进行一次测试]。

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
``````

`getTimezoneOffset()`在浏览器中，JavaScript中方法返回从00:00时区偏移的分钟数。例如，夏令时（DST）中的America / New_York时区返回数字300。300分钟是从零开始的5个小时差异。300分钟除以60分钟就是5小时。将每个时区与零时区+00：00 / Etc / GMT /格林威治时间进行比较。

MDN网络文档

joda.org提供了格式正确的时区表

+00：00或Etc / GMT为格林威治时间

Imagine that it's November in New York City, and the clocks have been set back an hour. In the summer in New York City, the offset is 240 minutes or 4 hours.

You can test this by creating a date that is in July and then getting the offset.

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

console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)
``````

What will print to the browser's developer tools console log?

So, now you can create a date in January and see what your browser returns for a time zone offset for the winter season.

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

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

console.log('todaysTimeZone : ' + todaysTimeZone)
``````

``````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
}
``````

`moment().isDST();` 如果观察到日光节约，将会给您。

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

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

ES6风格

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

``````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>``````

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

1. `x`是毫秒到感兴趣的一年的期望数量，而不在夏令保。
2. `y`是因为毫秒数时代从感兴趣的日期的年份的开始。
3. `z`是毫秒数，因为时代完整的日期和感兴趣的时间的
4. 我们`t`是两者的减法`x``y`来自`z``z - y - x`由于DST，这将产生偏移。
5. 如果`t`为零，则DST无效。如果`t`不为零，则DST生效。
``````(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");
})();``````

• 这个答案适用于所有时区，甚至包括南极洲/卡西
• 夏令时非常容易发生变化。可能是从现在开始的20年后，某个国家/地区可能会有3个DST周期，而不是正常的2个。这段代码通过返回以毫秒为单位的DST偏移量来处理这种情况，而不仅仅是DST是否有效。
• 一年中各个月份的大小以及Le年的工作方式非常适合使我们的时间与太阳同步。哎呀，它是如此完美地工作，以至于我们所要做的只是到处调整几秒钟我们当前的of年系统自15822月24日起生效，并且在可预见的将来可能会继续有效。
• 此代码在不使用DST的时区中工作。
• 此代码在实施DST之前的历史时期（例如1900年代）起作用。
• 此代码已最大程度地优化了整数，如果在紧密循环中调用，则不会出现任何问题。运行上面的代码段后，向下滚动到输出的底部以查看性能基准。我的计算机在Chrome上能够在约97毫秒内处理16384个日期。

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

`"" + new Date()`

1月01日，星期六100050 00:00:00 GMT-0500（东部标准时间）

`"" + new Date(...)`