Làm cách nào để kiểm tra xem DST (Giờ tiết kiệm ánh sáng ban ngày) có hiệu lực hay không và nếu có thì phần bù?


154

Đây là một chút mã JS của tôi mà điều này là cần thiết:

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

Tôi muốn lấy datetime trong "trước", nhưng nếu DST được sử dụng thì ngày sẽ hết 1 giờ. Tôi không biết cách kiểm tra xem DST có hiệu lực hay không.

Làm thế nào tôi có thể biết khi nào việc tiết kiệm ánh sáng ban ngày bắt đầu và kết thúc?

Câu trả lời:


313

Mã này sử dụng thực tế getTimezoneOffsettrả về giá trị lớn hơn trong Giờ chuẩn so với Giờ tiết kiệm ánh sáng ban ngày (DST). Do đó, nó xác định đầu ra dự kiến ​​trong Giờ chuẩn và so sánh xem đầu ra của ngày đã cho có cùng (Tiêu chuẩn) hay ít hơn (DST) hay không.

Lưu ý rằng getTimezoneOffsettrả về số phút tích cực cho các khu vực phía tây UTC, thường được nêu là giờ âm (vì chúng "đứng sau" UTC). Ví dụ: Los Angeles là Tiêu chuẩn 8 giờ của UTC , UTC-7h DST. getTimezoneOffsettrở lại 480(tích cực 480 phút) vào tháng 12 (mùa đông, Giờ chuẩn), thay vì -480. Nó trả về số âm cho Đông bán cầu (chẳng hạn như -600Sydney vào mùa đông, mặc dù điều này là "phía trước" ( 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!");
}

28
Tôi có thể xác minh rằng điều này hoạt động quốc tế. Hiện tại không có múi giờ sử dụng bất kỳ hình thức DST nào trong đó cả ngày 1 tháng 1 và ngày 1 tháng 7 đều ở cả hoặc trong cả giai đoạn DST. Ngoài ra, trong tất cả các múi giờ trong TZDB ( với một ngoại lệ không đáng kể ), phần lớn hơn của hai độ lệch là phần bù DST. Vì JavaScript getTimezoneOffsettrả về giá trị nghịch đảo, nên Math.maxthực sự trả về giá trị bù chuẩn . Mã là chính xác.
Matt Johnson-Pint

7
Tuy nhiên, nếu bất kỳ múi giờ nào thay đổi định nghĩa sao cho cả ngày 1 tháng 1 và ngày 1 tháng 7 đều ở DST hoặc cả hai không ở DST (và DST vẫn được áp dụng), thì mã này sẽ không hoạt động trong vùng đó.
Matt Johnson-Pint

9
Điều này không hoạt động nói chung, ví dụ, có những quốc gia chưa quan sát DST trong một số năm nhất định và cũng có một số quốc gia hoàn nguyên DST trong ramadan. Bên cạnh đó, định nghĩa ECMAScript cho Ngày bị hỏng và việc xử lý biến môi trường TZ cũng bị phá vỡ trong một số triển khai. Tất cả kết hợp này làm cho phương pháp này không đáng tin cậy. Bạn nên sử dụng một thư viện không sử dụng Ngày, ví dụ: timezonecomplete
rogierschouten

5
Mã này không hoạt động ở các quốc gia không tuân thủ DST, như Nam Phi hoặc Iceland; có nghĩa là nếu bạn sử dụng nó để so sánh với các múi giờ khác ở các quốc gia đó, nó sẽ không hiển thị thời gian chính xác ở đó. Đề xuất sử dụng UTC mọi cách và kiểm tra thủ công xem giờ có nằm trong phạm vi DST nhất định không. Sau đó, vấn đề chỉ là thay đổi thời gian bù UTC bình thường bằng +1 để có DST.
Kebman

1
Làm thế nào điều này có thể đúng? Ví dụ, Đức đã nhập DST vào ngày 2016-10-30 trong khi Hoa Kỳ nhập một tuần sau đó vào ngày 2016-11-06. Thông tin xấu như thế này là nguyên nhân khiến những thứ như thế này xảy ra: macworld.co.uk/news/apple/iêu
Daniel F

22

Tạo hai ngày: một vào tháng Sáu, một vào tháng Một. So sánh các giá trị getTimezone Offerset () của chúng.

  • nếu bù tháng 1> bù tháng 6, khách hàng ở bắc bán cầu
  • Nếu bù tháng 1 <bù tháng 6, khách hàng ở Nam bán cầu
  • nếu không có sự khác biệt, múi giờ của khách hàng không tuân theo DST

Bây giờ hãy kiểm tra getTimezone Offerset () của ngày hiện tại.

  • nếu bằng tháng 6, bắc bán cầu, thì múi giờ hiện tại là DST (+1 giờ)
  • nếu bằng tháng 1, nam bán cầu, thì múi giờ hiện tại là DST (+1 giờ)

Tại sao bạn cần bán cầu? sẽ không đủ để nói rằng nếu getTimezone Offerset () cho ngày hiện tại bằng với nhỏ hơn trong hai getTimezone Offerset () thì DST của nó? [và phần bù là sự khác biệt giữa hai?]
epeleg

Bạn không cần bán cầu như câu trả lời được chấp nhận thể hiện rõ ràng :)
Jon Nylander

Điều này sẽ không làm việc. Điều tốt nhất để làm là đảm bảo bạn sử dụng thời gian UTC và đặt thủ công bù cho khu vực bạn muốn. Sau đó, tìm thủ công bắt đầu và kết thúc cho DST cho cùng một khu vực (nếu có). Sau đó, bạn muốn kiểm tra xem thời gian cho vùng đó có nằm trong phạm vi DST hay không, sau đó cập nhật phần bù tương ứng với +1. Điều này cho phép so sánh các quốc gia quan sát DST và các quốc gia không quan sát.
Kebman

Câu hỏi đặt ra là làm thế nào để xác định liệu DST có hiệu lực tại thời điểm trong múi giờ của máy khách Kebman hay không, không phải cách hiển thị ngày, các máy khách web đã xử lý việc đó cho bạn.
Jon Nylander

Bạn nên kiểm tra giữa tháng 1 và tháng 7 (hoặc tháng 2 và tháng 8, tháng 3 và tháng 9, v.v.) vì chúng cách nhau 6 tháng.
kpull1

17

Câu trả lời này khá giống với câu trả lời được chấp nhận, nhưng không ghi đè lên Datenguyên mẫu và chỉ sử dụng một lệnh gọi chức năng để kiểm tra xem Giờ tiết kiệm ánh sáng có hiệu lực hay không, thay vì hai.


Ý tưởng là, vì không có quốc gia nào quan sát DST tồn tại trong 7 tháng [1] , trong một khu vực quan sát DST, phần bù từ thời gian UTC vào tháng 1 sẽ khác với tháng 7.

Trong khi Giờ tiết kiệm ánh sáng di chuyển đồng hồ về phía trước , JavaScript luôn trả về giá trị lớn hơn trong Giờ chuẩn. Do đó, nhận được mức bù tối thiểu giữa tháng 1 và tháng 7 sẽ có được mức bù múi giờ trong DST.

Sau đó chúng tôi kiểm tra xem múi giờ ngày có bằng giá trị tối thiểu đó không. Nếu có, thì chúng ta đang ở trong DST; nếu không thì không.

Hàm sau sử dụng thuật toán này. Nó lấy một đối tượng ngày dvà trả về truenếu thời gian tiết kiệm ánh sáng ban ngày có hiệu lực cho ngày đó và falsenếu nó không:

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

1
Điều này hoạt động, nhưng nếu không có DST trong TimeZone hiện tại thì nó cũng sẽ có kết quả đúng, điều đó không đúng. Nếu bạn chuyển nó sang Math.max(...) != d.get...(), nó sẽ trả về DST đúng iST được quan sát trong múi giờ nhất định VÀ ngày hiện tại trong DST. Nếu DST không được quan sát hoặc ngày khớp với offset tiêu chuẩn, nó sẽ trả về sai.
GreySage

12

Tôi đã phải đối mặt với cùng một vấn đề ngày hôm nay nhưng vì việc tiết kiệm ánh sáng ban ngày của chúng tôi bắt đầu và dừng lại ở những thời điểm khác nhau từ Hoa Kỳ (ít nhất là từ sự hiểu biết của tôi), tôi đã sử dụng một tuyến đường hơi khác ..

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

Sau đó, bạn chỉ cần so sánh độ lệch múi giờ hiện tại với DST và nonDST để xem cái nào phù hợp.


Đây là cách chúng tôi làm điều đó là tốt. Đó là, tính toán thời gian trong năm mà DST thay đổi trong múi giờ mục tiêu của bạn và tính toán bù đắp cho ngày hiện tại và ngày thay đổi gần đây nhất. Chúng sẽ khác nhau một giờ hoặc bằng nhau (giả sử múi giờ trong câu hỏi là bù giờ).
Heather

Không cần tạo 365 giá trị, cách tiếp cận tìm kiếm nhị phân dừng lại ngay khi xác định thay đổi bù sẽ hiệu quả hơn rất nhiều, ngay cả khi không quan sát được việc tiết kiệm ánh sáng ban ngày. Tất cả các phương pháp tiếp cận này cho rằng các địa điểm quan sát tiết kiệm ánh sáng ban ngày hàng năm, điều này không nhất thiết đúng. Các địa điểm chấp nhận và từ bỏ việc tiết kiệm ánh sáng ban ngày theo thời gian (mặc dù ECMAScript giả định các quy tắc hiện tại, bất kể khu vực nào, luôn được áp dụng).
RobG

2
Rob - làm thế nào bạn có thể thực hiện việc này thông qua tìm kiếm nhị phân nếu bạn không biết nơi tìm kiếm (nghĩa là nơi bạn đang tìm kiếm ở trên hoặc dưới điểm kiểm tra của bạn?)
epeleg

9

Dựa trên nhận xét của Matt Johanson về giải pháp được cung cấp bởi Sheldon Griffin, tôi đã tạo ra đoạn mã sau:

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

Nó cố gắng để có được những điều tốt nhất trong tất cả các thế giới có tính đến tất cả các ý kiến ​​và câu trả lời được đề xuất trước đó và cụ thể là:

1) Lưu trữ kết quả cho mỗi năm stdTimezone Offerset để bạn không cần tính toán lại khi kiểm tra nhiều ngày trong cùng một năm.

2) Nó không cho rằng DST (nếu nó tồn tại) nhất thiết phải vào tháng 7, và sẽ hoạt động ngay cả khi nó sẽ ở một thời điểm nào đó và một số nơi sẽ là bất kỳ tháng nào. Tuy nhiên, Performance-khôn ngoan, nó sẽ hoạt động nhanh hơn nếu thực sự tháng 7 (hoặc gần theo tháng) thực sự là DST.

3) Trường hợp tệ hơn, nó sẽ so sánh getTimezone Offerset của lần đầu tiên mỗi tháng. [và làm điều đó Một lần mỗi năm thử nghiệm].

Giả định mà nó vẫn đưa ra là nếu có thời gian DST lớn hơn thì một tháng.

Nếu ai đó muốn loại bỏ giả định đó, anh ta có thể thay đổi vòng lặp thành một thứ giống như những gì trong solutin do Aaron Cole cung cấp - nhưng tôi vẫn sẽ nhảy lên trước nửa năm và thoát ra khỏi vòng lặp khi tìm thấy hai sự khác biệt]


4

Các moment.js thư viện cung cấp một .isDst()phương pháp trên các đối tượng thời gian của mình.

khoảnh khắc # isDST kiểm tra xem thời điểm hiện tại có trong thời gian tiết kiệm ánh sáng ban ngày không.

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

Tôi đã thử var khoảnh khắc = Yêu cầu ('khoảnh khắc'); this .logger.info (khoảnh khắc ([2011, 2, 12]). isDST ()); this .logger.info (khoảnh khắc ([2011, 2, 14]). isDST ()); cả hai đều sai
Logan_B

Ngày thay đổi DST khác nhau giữa các quốc gia , ngay cả giữa các tiểu bang trong cùng một quốc gia (tức là tiểu bang Arizona). Ở Hoa Kỳ, đó là vào ngày 2011/03/13, trong khi ở Đức là vào ngày 2011 / 03-31. Vì vậy, kết quả sẽ khác nhau tùy thuộc vào loại múi giờ nào được cấu hình để hoạt động.
Daniel F

1
Nó thậm chí còn thay đổi trong tiểu bang Arizona timeanddate.com/time/us/arizona-no-dst.html
Daniel F

3

Các getTimezoneOffset() phương pháp trong JavaScript, trong một trình duyệt, trả về số phút bù đắp từ vùng 00:00 thời gian. Ví dụ: múi giờ America / New_York trong Tiết kiệm ánh sáng ban ngày (DST) trả về số 300. 300 phút là 5 giờ chênh lệch từ 0. 300 phút chia cho 60 phút là 5 giờ. Mỗi múi giờ được so sánh với múi giờ bằng 0, thời gian: 00 / Etc / GMT / Greenwich.

Tài liệu web MDN

Điều tiếp theo mà bạn phải biết, đó là phần bù có dấu ngược lại với múi giờ thực tế.

Thông tin về múi giờ được duy trì bởi Cơ quan cấp số được gán Internet (iana)

múi giờ iana

Một bảng thời gian được định dạng độc đáo được cung cấp bởi joda.org

khu thời gian joda

Giờ: 00 hoặc Etc / GMT là giờ Greenwich

Tất cả các múi giờ được bù từ GIÁ: 00 / "Vv / GMT" / Giờ Greenwich

Thời gian tiết kiệm ánh sáng ban ngày luôn là thời gian sớm hơn thời gian "thông thường" vào mùa hè. Bạn đặt đồng hồ trở lại vào mùa thu. (Slogan "Fall Back" để nhớ những việc cần làm)

Vì vậy, giờ Mỹ / New_York trong Tiết kiệm ánh sáng ban ngày (mùa đông) là một giờ trước giờ thường lệ. Vì vậy, ví dụ, những gì thường là 5 giờ chiều vào buổi chiều ở thành phố New York vào mùa hè, bây giờ là 4 giờ chiều Mỹ / New_York trong Tiết kiệm ánh sáng ban ngày. Tên thời gian "America / New_York" là tên múi giờ "Định dạng dài". Bờ biển phía đông của Hoa Kỳ thường gọi múi giờ của họ là Giờ chuẩn miền đông (EST)

Nếu bạn muốn so sánh độ lệch múi giờ ngày hôm nay với độ lệch múi giờ của một số ngày khác, bạn cần biết rằng dấu toán học (+/- "Tích cực / tiêu cực") của độ lệch múi giờ ngược với múi giờ.

Nhìn vào bảng múi giờ tại joda.org và tìm múi giờ cho "America / New_York" Nó sẽ có dấu âm ở phía trước của Offset tiêu chuẩn.

Trái đất quay ngược chiều kim đồng hồ trên trục của nó. Một người ngắm mặt trời mọc ở Greenwich nhìn thấy mặt trời mọc 5 giờ trước khi ai đó ở thành phố New York sẽ thấy mặt trời mọc. Và ai đó ở Bờ Tây Hoa Kỳ sẽ thấy mặt trời mọc sau khi ai đó ở Bờ Đông Hoa Kỳ nhìn thấy mặt trời mọc.

Có một lý do tại sao bạn cần biết tất cả những điều này. Vì vậy, bạn sẽ có thể xác định một cách hợp lý xem một số mã JavaScript có nhận được trạng thái DST chính xác hay không, mà không cần phải kiểm tra mọi múi giờ vào các thời điểm khác nhau trong năm.

Hãy tưởng tượng rằng đó là tháng 11 ở thành phố New York và đồng hồ đã được đặt lại một giờ. Vào mùa hè ở thành phố New York, thời gian bù là 240 phút hoặc 4 giờ.

Bạn có thể kiểm tra điều này bằng cách tạo một ngày trong tháng 7 và sau đó lấy phần bù.

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

console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

Điều gì sẽ in ra nhật ký bảng điều khiển công cụ phát triển của trình duyệt?

Trả lời là: 240

Vì vậy, bây giờ bạn có thể tạo một ngày vào tháng 1 và xem những gì trình duyệt của bạn trả về cho phần bù múi giờ cho mùa đông.

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)

Trả lời là: 300

Rõ ràng 300 lớn hơn 240. Vậy, điều này có nghĩa là gì? Bạn có nên viết mã kiểm tra phần bù mùa đông lớn hơn phần bù mùa hè không? Hoặc bù mùa hè ít hơn bù mùa đông? Nếu có sự khác biệt giữa độ lệch múi giờ mùa hè và mùa đông, thì bạn có thể giả sử rằng DST đang được sử dụng cho múi giờ này. Nhưng điều đó không cho bạn biết nếu hôm nay đang sử dụng DST cho múi giờ của trình duyệt. Vì vậy, bạn sẽ cần lấy phần bù múi giờ cho ngày hôm nay.

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

console.log('todaysTimeZone : ' + todaysTimeZone)

Câu trả lời là: ? - Phụ thuộc vào thời gian trong năm

Nếu độ lệch múi giờ ngày nay và độ lệch múi giờ mùa hè là như nhau, độ lệch múi giờ mùa hè và mùa đông là khác nhau, thì bằng cách khấu trừ logic, hôm nay KHÔNG được ở DST.

Bạn có thể bỏ qua việc so sánh độ lệch múi giờ mùa hè và mùa đông, (Để biết liệu DST có được sử dụng cho múi giờ này không) và chỉ so sánh độ lệch múi giờ ngày nay với độ lệch TZ mùa hè và luôn có câu trả lời đúng?

today's TZ Offset !== Summer TZ Offset

Chà, hôm nay là mùa đông hay mùa hè? Nếu bạn biết điều đó thì bạn có thể áp dụng logic sau:

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

Nhưng vấn đề là, bạn không biết ngày hôm nay là vào mùa đông hay mùa hè. Mỗi múi giờ có thể có các quy tắc riêng khi DST bắt đầu và dừng. Bạn cần theo dõi các quy tắc của mọi múi giờ cho mọi múi giờ trên thế giới. Vì vậy, nếu có một cách tốt hơn và dễ dàng hơn thì bạn cũng có thể làm điều đó tốt hơn và dễ dàng hơn.

Những gì chúng tôi còn lại, là bạn cần biết nếu múi giờ này sử dụng DST, và sau đó so sánh bù múi giờ ngày nay với bù giờ múi giờ mùa hè. Điều đó sẽ luôn cung cấp cho bạn một câu trả lời đáng tin cậy.

Logic cuối cùng là:

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

Chức năng xác định xem múi giờ trong trình duyệt có sử dụng DST không:

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
}

Theo dateandtime.com DST bắt đầu từ ngày 10 tháng 3 năm 2019, và do đó là vào mùa hè, không phải mùa đông và bù DST của New York là -4, không phải -5.
jk7

Nếu một cải tiến hoặc sửa chữa cần phải được thực hiện cho câu trả lời xin vui lòng chỉnh sửa, và nó sẽ được xem xét.
Alan Wells

2

Sử dụng Moment.js ( https://momentjs.com/ )

moment().isDST(); sẽ cung cấp cho bạn nếu tiết kiệm ánh sáng ngày được quan sát.

Ngoài ra nó có chức năng trợ giúp để tính thời gian tương đối cho bạn. Bạn không cần phải tính toán thủ công, vdmoment("20200105", "YYYYMMDD").fromNow();


1

Bạn đang ở gần nhưng một chút tắt. Bạn không bao giờ cần tính thời gian của riêng bạn vì nó là kết quả của đồng hồ của riêng bạn. Nó có thể phát hiện nếu bạn đang sử dụng thời gian tiết kiệm ánh sáng ban ngày ở vị trí của mình nhưng không phải cho một vị trí từ xa do phần bù tạo ra:

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

Điều này vẫn sẽ sai và tắt một giờ nếu họ ở trong DST. Bạn cần có tài khoản thời gian từ xa nếu họ hiện đang ở trong DST của họ hay không và điều chỉnh cho phù hợp. hãy thử tính toán điều này và thay đổi đồng hồ của bạn thành - giả sử ngày 2/1/2015 và đặt lại đồng hồ trở lại một giờ như thể bên ngoài DST. Sau đó tính toán bù cho một nơi vẫn phải chậm hơn 2 giờ. Nó sẽ hiển thị một giờ trước cửa sổ hai giờ. Bạn vẫn sẽ cần tính đến giờ và điều chỉnh. Tôi đã làm điều đó cho NY và Denver và luôn đi không chính xác (giờ trước) ở Denver.


1

Tôi đã thấy rằng việc sử dụng thư viện Moment.js với một số khái niệm được mô tả ở đây (so sánh từ tháng 1 đến tháng 6) hoạt động rất tốt.

Chức năng đơn giản này sẽ trả về cho dù múi giờ mà người dùng đang quan sát Giờ tiết kiệm ánh sáng ban ngày:

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

Một cách đơn giản để kiểm tra xem điều này có hoạt động (trên Windows) là thay đổi múi giờ của bạn thành vùng không DST, ví dụ Arizona sẽ trả về false, trong khi EST hoặc PST sẽ trả về true.

nhập mô tả hình ảnh ở đây


1

Giải pháp trong tương lai hoạt động trong mọi khu vực

  1. Hãy xlà số mili giây dự kiến ​​trong năm quan tâm mà không cần bao thanh toán trong tiết kiệm ánh sáng ban ngày.
  2. Gọi ylà số mili giây kể từ Kỷ nguyên từ đầu năm của ngày quan tâm.
  3. Gọi zlà số mili giây kể từ Kỷ nguyên của ngày và thời gian quan tâm
  4. Hãy tlà phép trừ của cả hai xytừ z: z - y - x. Điều này mang lại sự bù đắp do DST.
  5. Nếu tbằng 0, thì DST không có hiệu lực. Nếu tkhông bằng 0, thì DST có hiệu lực.

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

Tôi tin rằng đoạn mã trên là vượt trội so với tất cả các câu trả lời khác được đăng ở đây vì nhiều lý do.

  • Câu trả lời này hoạt động trong tất cả các múi giờ, thậm chí cả Nam Cực / Casey .
  • Tiết kiệm ánh sáng ban ngày là rất nhiều để thay đổi. Có thể là 20 năm nữa, một số quốc gia có thể có 3 giai đoạn DST thay vì bình thường 2. Mã này xử lý trường hợp đó bằng cách trả lại bù DST tính bằng mili giây, không chỉ là DST có hiệu lực hay không có hiệu lực.
  • Kích thước của các tháng trong năm và cách mà Leap Years hoạt động hoàn toàn phù hợp để giữ thời gian của chúng ta theo dõi với mặt trời. Heck, nó hoạt động hoàn hảo đến mức tất cả những gì chúng ta từng làm chỉ là điều chỉnh chỉ vài giây ở đây và ở đó . Hệ thống năm nhuận hiện tại của chúng tôi đã có hiệu lực kể từ ngày 24 tháng 2 năm 1582 và có thể sẽ có hiệu lực trong tương lai gần.
  • Mã này hoạt động trong các múi giờ không sử dụng DST.
  • Mã này hoạt động trong thời kỳ lịch sử trước khi DST được triển khai (chẳng hạn như những năm 1900).
  • Mã này được tối ưu hóa số nguyên tối đa và sẽ không gây ra vấn đề gì nếu được gọi trong một vòng lặp chặt chẽ. Sau khi chạy đoạn mã ở trên, cuộn xuống dưới cùng của đầu ra để xem điểm chuẩn hiệu suất. Máy tính của tôi có thể xử lý 16384 ngày trong ~ 97ms trên Chrome.

Tuy nhiên, nếu bạn không chuẩn bị cho hơn 2 giai đoạn DST, thì đoạn mã dưới đây có thể được sử dụng để xác định xem DST có hiệu lực như một boolean hay không.

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

0

Gần đây tôi cần tạo một chuỗi ngày với UTC và DST, và dựa trên câu trả lời của Sheldon, tôi kết hợp chuỗi này với nhau:

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>


0

Có vấn đề gì khi sử dụng Date.toString().indexOf('Daylight Time') > -1

"" + new Date()

Thứ bảy ngày 1 tháng 1 năm 100050 00:00:00 GMT-0500 (Giờ chuẩn miền đông )

"" + new Date(...)

CN ngày 01 tháng 5 năm 100033 00:00:00 GMT-0400 ( Giờ ban ngày miền đông )

Điều này có vẻ tương thích với tất cả các trình duyệt.


Vâng, nó không hoạt động trên toàn thế giới. Vào mùa hè ở châu Âu, bạn nhận được"Thu Jul 02 2020 14:07:01 GMT+0200 (Central European Summer Time)"
Tadej Krevh

0

Phong cách ES6

Math.min(...[0, 6].map(v => new Date(95, v, 1).getTimezoneOffset() * -1));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.