จะตรวจสอบได้อย่างไรว่า DST (Daylight Saving Time) มีผลบังคับใช้หรือไม่และมีการชดเชยหรือไม่


154

นี่เป็นรหัส 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);

ฉันต้องการรับ datetime ใน "ที่ผ่านมา" แต่ถ้า DST ถูกใช้งานแล้ววันที่จะถูกปิดโดย 1 ชั่วโมง ฉันไม่ทราบวิธีตรวจสอบว่า DST มีผลบังคับใช้หรือไม่

ฉันจะรู้ได้อย่างไรว่าการเลื่อนเวลากลางวันเริ่มต้นและสิ้นสุดลงอย่างไร

คำตอบ:


313

รหัสนี้ใช้ความจริงที่getTimezoneOffsetส่งกลับค่าที่มากขึ้นในช่วงเวลามาตรฐานเมื่อเทียบกับเวลาออมแสง (DST) ดังนั้นมันจึงกำหนดเอาท์พุทคาดว่าในช่วงเวลามาตรฐานและเปรียบเทียบว่าการส่งออกของวันที่ที่ระบุเดียวกัน (มาตรฐาน) หรือน้อยกว่า (DST)

โปรดทราบว่าgetTimezoneOffsetจะส่งกลับจำนวนนาทีที่เป็นบวกสำหรับโซนทางตะวันตกของ UTC ซึ่งโดยปกติจะระบุว่าเป็นชั่วโมงลบ (เนื่องจาก "อยู่ด้านหลัง" UTC) ตัวอย่างเช่น Los Angeles คือUTC – 8h Standard, UTC-7h DST getTimezoneOffsetผลตอบแทน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!");
}

28
ฉันสามารถตรวจสอบได้ว่ามันใช้งานได้ในระดับสากล ขณะนี้ไม่มีโซนเวลาที่ใช้ DST ในรูปแบบใด ๆ โดยที่ทั้ง 1 มกราคมและ 1 กรกฎาคมจะเป็นทั้งในและนอกช่วงเวลา DST นอกจากนี้ในเขตเวลาทั้งหมดใน TZDB ( ด้วยข้อยกเว้นเล็ก ๆ น้อย ๆ ) การออฟเซ็ตที่ใหญ่กว่าสองรายการคือ DST offset เนื่องจาก JavaScript getTimezoneOffsetส่งคืนค่าผกผันดังนั้นMath.maxจึงส่งคืนออฟเซ็ตมาตรฐาน รหัสถูกต้อง
Matt Johnson-Pint

7
อย่างไรก็ตามหากเขตเวลาใด ๆ เปลี่ยนคำจำกัดความของตนเช่นที่ 1 มกราคมและ 1 กรกฎาคมมีทั้งใน DST หรือทั้งสองไม่ได้อยู่ใน DST (และยังคงใช้ DST) รหัสนี้จะไม่ทำงานในโซนนั้น
Matt Johnson-Pint

9
สิ่งนี้ไม่ทำงานโดยทั่วไปเช่นมีหลายประเทศที่ไม่ได้สังเกต DST ในบางปีและบางประเทศกลับ DST ในช่วงรอมฎอน ถัดจากนั้นคำจำกัดความ ECMAScript สำหรับ Date จะใช้งานไม่ได้และการจัดการตัวแปรสภาพแวดล้อม TZ จะใช้งานไม่ได้ในการใช้งานบางอย่าง การรวมกันทั้งหมดทำให้วิธีนี้ไม่น่าเชื่อถือ คุณควรใช้ห้องสมุดที่ไม่ใช้ Date เช่น timezonecomplete
rogierschouten

5
รหัสนี้ใช้ไม่ได้กับประเทศที่ไม่ได้สังเกต DST เช่นแอฟริกาใต้หรือไอซ์แลนด์ ความหมายถ้าคุณใช้เพื่อเปรียบเทียบกับโซนเวลาอื่นในประเทศเหล่านั้นมันจะไม่แสดงเวลาที่ถูกต้องตรงนั้น แนะนำให้ใช้ UTC ตลอดเวลาและตรวจสอบด้วยตนเองว่าเวลานี้อยู่ในช่วง DST หรือไม่ จากนั้นเป็นเพียงเรื่องของการเปลี่ยนแปลงเวลา UTC ปกติชดเชย +1 เพื่อรับ DST
Kebman

1
สิ่งนี้จะถูกต้องได้อย่างไร ตัวอย่างเช่นเยอรมนีเข้าสู่ DST เมื่อวันที่ 2016-10-30 ในขณะที่สหรัฐอเมริกาเข้าสู่อีกหนึ่งสัปดาห์ต่อมาในวันที่ 2016-11-06 ข้อมูลที่ไม่ถูกต้องเช่นนี้คือสิ่งที่ทำให้สิ่งนี้เกิดขึ้น: macworld.co.uk/news/apple/…
Daniel F

22

สร้างสองวัน: หนึ่งในเดือนมิถุนายนหนึ่งในเดือนมกราคม เปรียบเทียบค่า getTimezoneOffset () ของพวกเขา

  • ถ้า January offset> June offset ลูกค้าอยู่ในซีกโลกเหนือ
  • ถ้า January offset <June offset ลูกค้าอยู่ในซีกโลกใต้
  • หากไม่มีความแตกต่างเขตเวลาของไคลเอ็นต์จะไม่สังเกต DST

ตรวจสอบ getTimezoneOffset () ของวันที่ปัจจุบัน

  • ถ้าเท่ากับมิถุนายนซีกโลกเหนือเขตเวลาปัจจุบันคือ DST (+1 ชั่วโมง)
  • ถ้าเท่ากับมกราคมซีกโลกใต้เขตเวลาปัจจุบันคือ DST (+1 ชั่วโมง)

ทำไมคุณต้องติดเก้ง มันจะไม่เพียงพอที่จะบอกว่าถ้า getTimezoneOffset () สำหรับวันที่ปัจจุบันเท่ากับเล็กกว่าสอง getTimezoneOffset () แล้ว DST ของมัน? [และค่าชดเชยคือความแตกต่างระหว่างสอง?]
epeleg

คุณไม่จำเป็นต้องติดเก้งในขณะที่คำตอบที่ได้รับการยอมรับแสดงให้เห็นอย่างชัดเจน :)
Jon Nylander

สิ่งนี้ใช้ไม่ได้ สิ่งที่ดีที่สุดที่จะทำคือให้แน่ใจว่าคุณใช้เวลา UTC และตั้งค่าออฟเซ็ตสำหรับภูมิภาคที่คุณต้องการด้วยตนเอง จากนั้นค้นหาจุดเริ่มต้นและสิ้นสุดด้วยตนเองสำหรับ DST สำหรับพื้นที่เดียวกัน (ถ้ามี) จากนั้นคุณต้องการตรวจสอบว่าเวลาสำหรับภูมิภาคนั้นอยู่ในช่วง DST หรือไม่จากนั้นอัปเดตออฟเซ็ตให้สอดคล้องกับ +1 สิ่งนี้ทำให้สามารถเปรียบเทียบประเทศที่สังเกต DST และประเทศที่ไม่ได้ทำ
Kebman

คำถามคือวิธีการตรวจสอบว่า DST มีผลบังคับใช้ในขณะนี้ในเขตเวลาของเครื่องไคลเอนต์ Kebman ไม่ใช่วิธีแสดงวันที่หรือไม่เว็บไคลเอนต์จัดการกับปัญหานั้นให้คุณแล้ว
Jon Nylander

คุณตรวจสอบระหว่างเดือนมกราคมถึงเดือนกรกฎาคม (หรือกุมภาพันธ์และสิงหาคม, มีนาคมและกันยายน, ฯลฯ ) เพราะกัน 6 เดือน
kpull1

17

คำตอบนี้ค่อนข้างคล้ายกับคำตอบที่ยอมรับ แต่ไม่ได้แทนที่Dateต้นแบบและใช้การเรียกใช้ฟังก์ชันเดียวเพื่อตรวจสอบว่า Daylight Saving Time มีผลใช้งานหรือไม่


แนวคิดก็คือเนื่องจากไม่มีประเทศใดสังเกตว่า DST ที่กินเวลานาน 7 เดือน[1]ในพื้นที่ที่สังเกต DST ค่าชดเชยจากเวลา UTC ในเดือนมกราคมจะแตกต่างจากในเดือนกรกฎาคม

ในขณะที่เวลาออมแสงเลื่อนนาฬิกาไปข้างหน้า JavaScript จะส่งคืนค่าที่มากขึ้นในระหว่างเวลามาตรฐาน ดังนั้นการได้รับการชดเชยขั้นต่ำระหว่างเดือนมกราคมถึงเดือนกรกฎาคมจะได้รับการชดเชยเขตเวลาระหว่าง 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(); 
}

1
วิธีนี้ใช้ได้ผล แต่ถ้าไม่มี DST ในเขตเวลาปัจจุบันก็จะส่งผลให้เป็นจริงซึ่งไม่ถูกต้อง หากคุณเปลี่ยนเป็นMath.max(...) != d.get...()มันจะคืนค่าจริงถ้าพบว่า DST ในเขตเวลาที่กำหนดและวันที่ปัจจุบันเป็น DST หากไม่พบ DST หรือวันที่ตรงกับออฟเซ็ตมาตรฐานจะส่งคืนค่าเท็จ
GreySage

12

ฉันต้องเผชิญกับปัญหาเดียวกันนี้ในวันนี้ แต่เนื่องจากการประหยัดเวลากลางวันเริ่มและหยุดในเวลาที่แตกต่างจากสหรัฐอเมริกา (อย่างน้อยจากความเข้าใจของฉัน) ฉันใช้เส้นทางที่แตกต่างกันเล็กน้อย ..

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 และ nonDST เพื่อดูว่าตรงกันหรือไม่


นี่คือวิธีที่เราทำเช่นกัน นั่นคือคำนวณเวลาของปีที่การเปลี่ยนแปลง DST ในโซนเวลาเป้าหมายของคุณและคำนวณการชดเชยสำหรับวันปัจจุบันและวันที่เปลี่ยนแปลงล่าสุด พวกเขาอาจแตกต่างกันไปตามชั่วโมงหรือเท่ากัน (สมมติว่าเขตเวลาที่มีปัญหาคือเวลาหนึ่งชั่วโมง)
Heather

ไม่จำเป็นต้องสร้างค่า 365 วิธีการค้นหาแบบไบนารีที่หยุดทันทีที่มีการพิจารณาการเปลี่ยนแปลงออฟเซ็ตควรมีประสิทธิภาพมากขึ้นแม้ว่าจะไม่ได้สังเกตการปรับเวลาตามฤดูกาล วิธีการทั้งหมดเหล่านี้สมมติว่าสถานที่ปฏิบัติตามการปรับเวลาตามฤดูกาลทุกปีซึ่งไม่จำเป็นต้องเป็นจริง สถานที่นำมาใช้และละทิ้งการปรับเวลาตามฤดูกาลเป็นครั้งคราว (แม้ว่า ECMAScript จะถือว่ากฎปัจจุบันไม่ว่าจะมีการปรับใช้พื้นที่ใดก็ตาม)
RobG

2
Rob - คุณสามารถทำสิ่งนี้ผ่านการค้นหาแบบไบนารีถ้าคุณไม่รู้ว่าจะค้นหาที่ไหน (เช่นสถานที่ที่คุณกำลังค้นหาอยู่เหนือหรือใต้จุดทดสอบของคุณ?)
epeleg

9

จากความคิดเห็นของ 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) มันไม่คิดว่า DST (ถ้ามีอยู่ทั้งหมด) จำเป็นต้องใช้ในเดือนกรกฎาคมและจะทำงานแม้ว่ามันจะอยู่ในบางจุดและบางแห่งจะเป็นเดือนใดก็ได้ อย่างไรก็ตามประสิทธิภาพที่ชาญฉลาดมันจะทำงานได้เร็วขึ้นหากจริง ๆ แล้วกรกฎาคม (หรือใกล้เคียงกับเดือน) เป็น DST แน่นอน

3) กรณีแย่กว่านั้นมันจะเปรียบเทียบ getTimezoneOffset ของวันแรกของแต่ละเดือน [และทำอย่างนั้นปีละครั้งที่ผ่านการทดสอบ]

ข้อสันนิษฐานที่มันยังคงทำอยู่คือถ้ามีช่วงเวลา DST มากกว่าเดือนเดียว

หากมีคนต้องการลบข้อสันนิษฐานนั้นเขาสามารถเปลี่ยนลูปเป็นอะไรที่คล้ายกับโซลูตินที่อารอนโคลให้ไว้ - แต่ฉันจะกระโดดครึ่งปีข้างหน้าและแยกออกจากลูปเมื่อพบออฟเซ็ตที่แตกต่างกันสองอัน]


4

moment.jsห้องสมุดให้เป็น.isDst()วิธีการที่วัตถุเวลา

ครู่ # 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 ครู่ = ต้องการ ('ช่วงเวลา'); this.logger.info (ช่วงเวลา ([2011, 2, 12]). isDST ()); this.logger.info (ช่วงเวลา ([2011, 2, 14]). isDST ()); ทั้งคู่เป็นเท็จ
Logan_B

วันที่เปลี่ยน DST นั้นแตกต่างกันไปในแต่ละประเทศแม้แต่ในรัฐในประเทศเดียวกัน (เช่นรัฐแอริโซนา) ในสหรัฐอเมริกามันเป็นวันที่ 2011-03-13 ในขณะที่ในประเทศเยอรมนีมันเป็นวันที่ 2011-03-31 ดังนั้นผลลัพธ์จะแตกต่างกันขึ้นอยู่กับช่วงเวลาที่ time.js ถูกกำหนดค่าให้ทำงานระบบ
Daniel F

1
มันยังแตกต่างกันภายในมลรัฐแอริโซนาtimeanddate.com/time/us/arizona-no-dst.html
Daniel F

3

getTimezoneOffset()วิธีการใน JavaScript ในเบราว์เซอร์จะส่งกลับจำนวนนาทีชดเชยจากโซนเวลา 00:00 ตัวอย่างเช่นเขตเวลา America / New_York ใน Daylight Savings (DST) จะส่งกลับหมายเลข 300 300 นาทีแตกต่างจากศูนย์ 5 ชั่วโมง 300 นาทีหารด้วย 60 นาทีคือ 5 ชั่วโมง ทุกเขตเวลาจะถูกเปรียบเทียบกับโซนเวลาเป็นศูนย์เวลา +00: 00 / Etc / GMT / Greenwich

เอกสาร MDN เว็บ

สิ่งต่อไปที่คุณต้องรู้คือออฟเซ็ตมีเครื่องหมายตรงข้ามของเขตเวลาจริง

ข้อมูลเกี่ยวกับเขตเวลาได้รับการดูแลโดยหน่วยงานที่กำหนดหมายเลขอินเทอร์เน็ต (iana)

เขตเวลาของ Iana

ตารางเวลาที่จัดรูปแบบเป็นอย่างดีจัดทำโดย joda.org

เขตเวลา joda

+00: 00 หรือ Etc / GMT เป็นเวลาของ Greenwich

เขตเวลาทั้งหมดถูกชดเชยจาก +00: 00 / "Etc / GMT" / เวลา Greenwich

เวลาออมแสงมักจะเร็วกว่าเวลา "ปกติ" ในฤดูร้อนเสมอ คุณตั้งนาฬิกาของคุณกลับมาในฤดูใบไม้ร่วง ("ถอยกลับ" สโลแกนเพื่อระลึกถึงสิ่งที่ต้องทำ)

ดังนั้นเวลาอเมริกา / New_York ใน Daylight Saving (ฤดูหนาว) คือหนึ่งชั่วโมงก่อนเวลาปกติ ตัวอย่างเช่นสิ่งที่ปกติคือ 5 โมงเย็นในเมืองนิวยอร์กในฤดูร้อนตอนนี้เป็นเวลา 4 โมงเย็นอเมริกา / นิวยอร์กเวลาออมแสงตามฤดูกาล ชื่อ "America / New_York" เวลาเป็นชื่อโซน "Long Format" ชายฝั่งตะวันออกของสหรัฐอเมริกามักจะเรียกเขตเวลาของพวกเขาเวลามาตรฐานตะวันออก (EST)

หากคุณต้องการเปรียบเทียบการชดเชยเขตเวลาของวันนี้กับการชดเชยเขตเวลาของวันที่อื่นคุณต้องทราบว่าเครื่องหมายทางคณิตศาสตร์ (+/- "ค่าบวก / ค่าลบ") ของการชดเชยเขตเวลาตรงข้ามกับเขตเวลา

ดูตารางโซนเวลาที่ joda.org และค้นหาโซนเวลาสำหรับ "America / New_York" โดยจะมีเครื่องหมายลบหน้า Standard Offset

โลกหมุนทวนเข็มนาฬิกาบนแกนของมัน คนดูพระอาทิตย์ขึ้นในกรีนนิชเห็นพระอาทิตย์ขึ้น 5 ชั่วโมงก่อนที่ใครบางคนในนิวยอร์กซิตี้จะเห็นพระอาทิตย์ขึ้น และใครบางคนบนชายฝั่งตะวันตกของสหรัฐอเมริกาจะเห็นพระอาทิตย์ขึ้นหลังจากที่ใครบางคนบนชายฝั่งตะวันออกของสหรัฐอเมริกาเห็นพระอาทิตย์ขึ้น

มีเหตุผลที่คุณต้องรู้ทั้งหมดนี้ เพื่อที่คุณจะสามารถทราบได้อย่างมีเหตุผลว่ารหัส JavaScript บางอย่างกำลังได้รับสถานะ DST อย่างถูกต้องหรือไม่โดยไม่จำเป็นต้องทดสอบทุกโซนเวลาในช่วงเวลาต่างๆของปี

ลองนึกภาพว่ามันคือเดือนพฤศจิกายนในนิวยอร์กซิตี้และนาฬิกาตั้งเวลาไว้หนึ่งชั่วโมง ในฤดูร้อนในมหานครนิวยอร์กค่าชดเชยคือ 240 นาทีหรือ 4 ชั่วโมง

คุณสามารถทดสอบสิ่งนี้ได้โดยการสร้างวันที่ในเดือนกรกฎาคมและได้รับการชดเชย

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

console.log('july_Timezone_OffSet: ' + july_Timezone_OffSet)

สิ่งที่จะพิมพ์ไปยังบันทึกคอนโซลเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์

คำตอบคือ: 240

ดังนั้นตอนนี้คุณสามารถสร้างวันที่ในเดือนมกราคมและดูว่าเบราว์เซอร์ของคุณส่งคืนอะไรในเขตเวลาชดเชยในฤดูหนาว

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)

คำตอบคือ:? - ขึ้นอยู่กับช่วงเวลาของปี

หากการชดเชยเขตเวลาของวันนี้และการชดเชยเขตเวลาในฤดูร้อนเหมือนกันและการชดเชยโซนฤดูร้อนและฤดูหนาวจะแตกต่างกันดังนั้นการหักลอจิคัลจะต้องไม่เป็น DST

คุณสามารถละเว้นการเปรียบเทียบออฟเซ็ตเขตเวลาฤดูร้อนและฤดูหนาว (หากต้องการทราบว่าใช้ 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;
}

ฟังก์ชั่นเพื่อตรวจสอบว่าเขตเวลาในเบราว์เซอร์ใช้ DST หรือไม่:

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
}

1
ตาม dateandtime.com DST เริ่มวันที่ 10 มีนาคมในปี 2019 และดังนั้นจึงอยู่ในฤดูร้อนไม่ใช่ฤดูหนาวและค่า DST ของนิวยอร์กอยู่ที่ -4 ไม่ใช่ -5
jk7

หากจำเป็นต้องทำการปรับปรุงหรือแก้ไขคำตอบโปรดทำการแก้ไขและจะได้รับการตรวจสอบ
Alan Wells

2

ใช้ Moment.js ( https://momentjs.com/ )

moment().isDST(); จะให้คุณถ้าสังเกตการออมแสง

นอกจากนี้ยังมีฟังก์ชั่นผู้ช่วยในการคำนวณเวลาที่เกี่ยวข้องสำหรับคุณ คุณไม่จำเป็นต้องทำการคำนวณด้วยตนเองเช่นmoment("20200105", "YYYYMMDD").fromNow();


1

คุณใกล้แค่นิดเดียว คุณไม่จำเป็นต้องคำนวณเวลาของคุณเองเพราะมันเป็นผลมาจากนาฬิกาของคุณเอง มันสามารถตรวจจับได้ว่าคุณกำลังใช้การปรับเวลาตามฤดูกาลในตำแหน่งของคุณหรือไม่ แต่ไม่ใช่สำหรับสถานที่ห่างไกลที่ผลิตโดยออฟเซ็ต:

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

สิ่งนี้จะยังคงผิดและปิดหนึ่งชั่วโมงหากพวกเขาอยู่ใน DST คุณต้องการบัญชีเวลาระยะไกลหากพวกเขาอยู่ใน DST หรือไม่และปรับตาม ลองคำนวณสิ่งนี้และเปลี่ยนนาฬิกาของคุณเป็น - ให้บอกว่าวันที่ 2/1/2558 และรีเซ็ตนาฬิกาเป็นเวลาหนึ่งชั่วโมงราวกับว่าอยู่นอก DST จากนั้นคำนวณหาค่าชดเชยสำหรับสถานที่ที่ควรใช้เวลา 2 ชั่วโมง มันจะแสดงหนึ่งชั่วโมงข้างหน้าหน้าต่างสองชั่วโมง คุณยังจะต้องคิดเป็นชั่วโมงและปรับ ฉันทำเพื่อนิวยอร์กและเดนเวอร์และมักจะไปที่ไม่ถูกต้อง (ข้างหน้าชั่วโมง) ในเดนเวอร์


1

ฉันพบว่าการใช้ห้องสมุดMoment.jsกับแนวคิดบางอย่างที่อธิบายไว้ที่นี่ (เปรียบเทียบระหว่างมกราคมถึงมิถุนายน) ทำงานได้ดีมาก

ฟังก์ชั่นที่เรียบง่ายนี้จะกลับมาว่าเขตเวลาที่ผู้ใช้อยู่ในการสังเกตเวลาออมแสงหรือไม่:

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

วิธีง่ายๆในการตรวจสอบว่างานนี้ (บน Windows) คือการเปลี่ยนเขตเวลาของคุณเป็นโซนที่ไม่ใช่เวลาเช่นแอริโซนาจะกลับเท็จในขณะที่ EST หรือ PST จะกลับมาจริง

ป้อนคำอธิบายรูปภาพที่นี่


1

โซลูชั่นที่รองรับอนาคตที่ใช้งานได้ในทุกโซน

  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 นั้นจะมีผลหรือไม่มีผล
  • ขนาดของเดือนของปีและวิธีการที่ Leap ปีทำงานอย่างสมบูรณ์แบบในการติดตามเวลาของเรากับดวงอาทิตย์ เฮคมันทำงานได้อย่างสมบูรณ์แบบมากที่สุดเท่าที่เราเคยทำเพียงแค่ปรับวินาทีที่นี่และตรงนั้น ระบบปีอธิกสุรทินปัจจุบันของเรามีผลบังคับใช้ตั้งแต่วันที่ 24 กุมภาพันธ์ 1582และจะมีผลบังคับใช้สำหรับอนาคตอันใกล้
  • รหัสนี้ทำงานในเขตเวลาที่ไม่ได้ใช้ DST
  • รหัสนี้ใช้งานได้ในประวัติศาสตร์ครั้งก่อนเมื่อมีการใช้งาน DST (เช่น 1900)
  • รหัสนี้เป็นจำนวนเต็มที่ปรับให้เหมาะสมที่สุดและจะทำให้คุณไม่มีปัญหาถ้าเรียกในวงแน่น หลังจากเรียกใช้ข้อมูลโค้ดด้านบนเลื่อนลงไปที่ด้านล่างของผลลัพธ์เพื่อดูเกณฑ์มาตรฐานประสิทธิภาพ คอมพิวเตอร์ของฉันสามารถประมวลผลวันที่ 16384 ใน ~ 97ms บน Chrome

อย่างไรก็ตามหากคุณไม่ได้เตรียมการมานานกว่า 2 ช่วงเวลาคุณสามารถใช้โค้ดด้านล่างเพื่อกำหนดว่า DST มีผลบังคับใช้เป็นบูลีนหรือไม่

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

0

เมื่อเร็ว ๆ นี้ฉันต้องการสร้างสตริงวันที่ด้วย 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>


0

มีปัญหาในการใช้ Date.toString().indexOf('Daylight Time') > -1

"" + new Date()

ส. ค. 01 100050 00:00:00 GMT-0500 ( เวลามาตรฐานตะวันออก)

"" + new Date(...)

อาทิตย์พฤษภาคม 01 1,00033 00:00:00 GMT-0400 ( เวลาตามฤดูกาลของภาคตะวันออก)

ดูเหมือนว่าจะเข้ากันได้กับเบราว์เซอร์ทั้งหมด


ใช่มันไม่สามารถใช้ได้ทั่วโลก ในฤดูร้อนในยุโรปคุณจะได้รับ"Thu Jul 02 2020 14:07:01 GMT+0200 (Central European Summer Time)"
Tadej Krevh

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.