รับเขตเวลาไคลเอ็นต์จากเบราว์เซอร์


139

มีวิธีที่เชื่อถือได้ในการรับเขตเวลาจากเบราว์เซอร์ไคลเอ็นต์หรือไม่ ฉันเห็นลิงค์ต่อไปนี้ แต่ฉันต้องการโซลูชันที่มีประสิทธิภาพมากขึ้น

ตรวจจับโซนเวลาโดยอัตโนมัติด้วย JavaScript

การตรวจจับเขตเวลาใน JavaScript



8
ฉันเขียน jsTimezoneDetect ว่าคุณลิงค์ไปด้านบนและสถานการณ์ของฉันก็คือมันใกล้เคียงที่สุดเท่าที่คุณจะทำได้ด้วยจาวาสคริปต์ข้ามเบราว์เซอร์แท้ๆ (โดยไม่ต้องระบุตำแหน่งทางภูมิศาสตร์และค้นหา IP)
Jon Nylander

1
ซ้ำซ้อนที่เป็นไปได้ในการรับเขตเวลาของลูกค้าใน JavaScript
Suma

คำตอบ:


87

ดูที่เก็บของเจดีย์นี้จะเป็นประโยชน์

ดาวน์โหลด jstz.min.js และเพิ่มฟังก์ชั่นในหน้า html ของคุณ

<script language="javascript">
    function getTimezoneName() {
        timezone = jstz.determine()
        return timezone.name();
    }
</script>

และเรียกใช้ฟังก์ชันนี้จากแท็กที่แสดงของคุณ


13
TL; DR ตอนนี้เราสามารถใช้Intl.DateTimeFormat().resolvedOptions().timeZone(ไม่ใช่ IE11) ตามที่ Wallace แนะนำ
Code4R7

195

ครึ่งทศวรรษต่อมาเรามีวิธีในตัวสำหรับมัน! สำหรับเบราว์เซอร์ที่ทันสมัยฉันจะใช้:

const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(tz);

ผลตอบแทนนี้สตริงเขต IANA แต่ไม่ชดเชย เรียนรู้เพิ่มเติมที่อ้างอิง MDN

ตารางความเข้ากันได้ - ณ เดือนมีนาคม 2562 ทำงานได้ 90% ของเบราว์เซอร์ที่ใช้งานทั่วโลก ไม่สามารถทำงานได้บน Internet Explorer


4
ไม่ทำงานใน firefox: Intl.DateTimeFormat().resolvedOptions().timeZone->undefined
Tomas Tomecek

3
Firefox และ IE ดูเหมือนจะไม่สนับสนุนคุณสมบัติ :( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Wallace

5
Intl.DateTimeFormat().resolvedOptions().timeZoneจะคืนค่าที่คาดหวังเริ่มต้นจาก Firefox 52: kangax.github.io/compat-table/esintl/…
julen

มีวิธีใช้แบบฟอร์มนี้อย่างไร? ในค่าที่ซ่อนอยู่ตามที่แนะนำบนdeveloper.mozilla.org/en-US/docs/Web/HTML/Element/input/… ?
hendry

4
ใช้งานได้ใน Firefox ตอนนี้
Dustin Michels

76

บ่อยครั้งที่ผู้คนกำลังมองหา "เขตเวลา" สิ่งที่พอเพียงคือ "UTC offset" เช่นเซิร์ฟเวอร์ของตนอยู่ใน UTC + 5 และพวกเขาต้องการที่จะรู้ว่าลูกค้าของพวกเขากำลังทำงานใน UTC-8


ในจาวาสคริปต์แบบธรรมดาธรรมดา(new Date()).getTimezoneOffset()/60จะคืนค่าจำนวนชั่วโมงปัจจุบันชดเชยจาก UTC

เป็นเรื่องที่ควรสังเกตว่า "gotcha" ที่เป็นไปได้ในสัญลักษณ์ของgetTimezoneOffset()ค่าส่งคืน(จากเอกสาร MDN) :

ออฟเซ็ตเขตเวลาคือความแตกต่างเป็นนาทีระหว่าง UTC กับเวลาท้องถิ่น โปรดทราบว่านี่หมายความว่าการชดเชยเป็นค่าบวกหากเขตเวลาท้องถิ่นอยู่หลัง UTC และลบหากอยู่ข้างหน้า ตัวอย่างเช่นสำหรับเขตเวลา UTC + 10: 00 (เวลามาตรฐานของออสเตรเลียตะวันออก, เวลาวลาดิวอสต็อก, เวลามาตรฐาน Chamorro), -600 จะถูกส่งกลับ


แต่ผมแนะนำให้คุณใช้day.jsเวลา / วันที่ที่เกี่ยวข้องกับรหัส Javascript ในกรณีนี้คุณจะได้รับออฟเซ็ต UTC 8601 รูปแบบ ISO ด้วยการรัน:

> dayjs().format("Z")
"-08:00"

เป็นไปได้ว่าลูกค้าอาจปลอมแปลงข้อมูลนี้ได้อย่างง่ายดาย

(หมายเหตุ: คำตอบนี้ แต่เดิมแนะนำhttps://momentjs.com/แต่ dayjs เป็นทางเลือกที่ทันสมัยและเล็กลง)


30
อาจเป็นเรื่องน่าสังเกตว่าออฟเซ็ตและเขตเวลาไม่จำเป็นต้องเหมือนกัน
เด็กซ์

9
คุณจะใช้ DST อย่างไรกับการชดเชยเท่านั้น? ในพื้นที่เหล่านั้นการชดเชยจะผิดครึ่งปี IMO เขตเวลามีความแม่นยำมากขึ้น
Savageman

4
DST เป็นส่วนหนึ่งของการชดเชยเวลาที่กำหนด เวลายุโรปตอนกลางในฤดูหนาวคือ UTC + 01: 00 อย่างไรก็ตามเมื่อ DST ถูกนำไปใช้ CET คือ UTC + 02: 00 เหมือนตอนนี้ในเดนมาร์กฉันอยู่ที่ไหน
Gert Sønderby

1
นี่คือสาเหตุที่ getTimezoneOffset () ต้องการวันที่ทำงาน - มันจะเพิ่มในเวลาที่มีผลบังคับใช้ในเวลานั้น
OsamaBinLogin

2
ชดเชยไม่ถูกต้องเมื่อพิจารณาการปรับเวลาตามฤดูกาล
เกร็กลิตร

48

สำหรับตอนนี้ทางออกที่ดีที่สุดอาจจะ jstz เป็นข้อเสนอแนะในคำตอบของ mbayloon

เพื่อความสมบูรณ์ก็ควรจะกล่าวว่ามีความเป็นมาตรฐานที่เป็นของทาง: สนามบินนานาชาติ คุณสามารถเห็นสิ่งนี้ใน Chrome แล้ว:

> Intl.DateTimeFormat().resolvedOptions().timeZone
"America/Los_Angeles"

(สิ่งนี้ไม่ได้เป็นไปตามมาตรฐานซึ่งเป็นอีกเหตุผลหนึ่งที่ควรยึดติดกับห้องสมุด)


1
Intl ดูเหมือนมั่นคงในทุกสิ่งยกเว้น Safari caniuse.com/#feat=internationalization
Michael Cole

2
@MichaelCole ที่สอดคล้องกับการใช้งานIntlควรจะกลับมาundefinedสำหรับคุณสมบัติถ้าคุณไม่ได้ด้วยตนเองระบุเขตเวลาในการก่อสร้างtimeZone DateTimeFormatChrome เบี่ยงเบนจากมาตรฐานโดยส่งคืนเขตเวลาของระบบแทน นั่นคือสิ่งที่คำตอบของโยฮันเนสหาประโยชน์ แต่ก็เป็นสาเหตุที่เขาพูดว่า "ไม่ปฏิบัติตามมาตรฐาน"
Chris Jester-Young

20
FYI - มาตรฐานตอนนี้เป็น Intl.DateTimeFormat (). modifiedOptions (). timeZone
Nederby


4

นี่คือjsfiddle

มันแสดงตัวย่อของเขตเวลาของผู้ใช้ปัจจุบัน

นี่คือตัวอย่างโค้ด

var tz = jstz.determine();
console.log(tz.name());
console.log(moment.tz.zone(tz.name()).abbr(new Date().getTime()));

1
เพื่อแสดงวันที่ตามที่ May 22 2015 03:45 PM CDT ฉันใช้ console.log(moment(now).format('MMM DD YYYY hh:mm A') + ' ' + moment.tz.zone(tz.name()).abbr(now.getTime()));
αƞjiβ

5
ซอของคุณไม่ทำงานอีกต่อไปและให้ข้อผิดพลาดในคอนโซล
Saumil

2

ฉันใช้วิธีการที่คล้ายกับวิธีที่Josh Fraser ใช้ซึ่งกำหนดเวลาเบราว์เซอร์จาก UTC และระบุว่ารู้จัก DST หรือไม่ (แต่ค่อนข้างง่ายจากรหัสของเขา):

var ClientTZ = {
    UTCoffset:  0,          // Browser time offset from UTC in minutes
    UTCoffsetT: '+0000S',   // Browser time offset from UTC in '±hhmmD' form
    hasDST:     false,      // Browser time observes DST

    // Determine browser's timezone and DST
    getBrowserTZ: function () {
        var self = ClientTZ;

        // Determine UTC time offset
        var now = new Date();
        var date1 = new Date(now.getFullYear(), 1-1, 1, 0, 0, 0, 0);    // Jan
        var diff1 = -date1.getTimezoneOffset();
        self.UTCoffset = diff1;

        // Determine DST use
        var date2 = new Date(now.getFullYear(), 6-1, 1, 0, 0, 0, 0);    // Jun
        var diff2 = -date2.getTimezoneOffset();
        if (diff1 != diff2) {
            self.hasDST = true;
            if (diff1 - diff2 >= 0)
                self.UTCoffset = diff2;     // East of GMT
        }

        // Convert UTC offset to ±hhmmD form
        diff2 = (diff1 < 0 ? -diff1 : diff1) / 60;
        var hr = Math.floor(diff2);
        var min = diff2 - hr;
        diff2 = hr * 100 + min * 60;
        self.UTCoffsetT = (diff1 < 0 ? '-' : '+') + (hr < 10 ? '0' : '') + diff2.toString() + (self.hasDST ? 'D' : 'S');

        return self.UTCoffset;
    }
};

// Onload
ClientTZ.getBrowserTZ();

เมื่อทำการโหลดClientTZ.getBrowserTZ()ฟังก์ชั่นจะถูกดำเนินการซึ่งตั้งค่า:

  • ClientTZ.UTCoffset ถึงเวลาเบราว์เซอร์ที่ชดเชยจาก UTC ในหน่วยนาที (เช่น CST คือ −360 นาทีซึ่งคือ .06.0 ชั่วโมงจาก UTC)
  • ClientTZ.UTCoffsetTเพื่อชดเชยในรูปแบบ'±hhmmD'(เช่น, '-0600D'), ที่ต่อท้ายเป็นDสำหรับ DST และSสำหรับมาตรฐาน (ไม่ใช่ -DST);
  • ClientTZ.hasDST (เป็นจริงหรือเท็จ)

ClientTZ.UTCoffsetมีให้ในนาทีแทนชั่วโมงเพราะเขตบางรายที่มีการชดเชยรายชั่วโมงเศษ (เช่น 0415)

ที่อยู่เบื้องหลังความตั้งใจClientTZ.UTCoffsetTที่จะใช้เป็นคีย์ลงในตารางของเขต (ไม่ได้ให้ที่นี่) เช่นสำหรับหล่นลง<select>รายการ


ดูเหมือนว่ามันจะกลับมาเสมอ 'D' ถ้าสังเกตการออมแสง และทำไมเพียงห้าเดือนที่แตกต่างกันอย่างไร แน่นอนว่ามกราคมและกรกฎาคมจะทำงานได้อย่างน่าเชื่อถือมากขึ้น?
แมตต์

@Matt - ใช่คุณสามารถใช้7-1สำหรับกรกฎาคมแทนมิถุนายน ฉันไม่แน่ใจว่ามันสร้างความแตกต่างอย่างแท้จริงหรือไม่เนื่องจากฉันสงสัยว่ามีแผนการ DST ระดับภูมิภาคซึ่งไม่รวมมิถุนายน
David R Tribble

-13

ไม่ไม่มีวิธีที่เชื่อถือได้เพียงอย่างเดียวและจะไม่มีทาง คุณคิดว่าคุณเชื่อถือลูกค้าได้หรือไม่?


23
ในการชี้แจง: นาฬิกาของลูกค้าอาจตั้งค่าไม่ถูกต้องหรืออาจพยายามหลอกคุณให้คิดว่าพวกเขาอยู่ในเขตเวลาที่แตกต่างจากของจริง หากคุณจะใช้เขตเวลาของลูกค้าอย่าทำเพื่อสิ่งใดที่สำคัญ
Ryan Kinal

7
-1 สำหรับการให้คำตอบที่อาจทำให้เข้าใจผิดและไม่ชี้แจง
Doug S

6
ใช่สำหรับใบสมัครของฉันฉันสามารถเชื่อถือลูกค้าได้ หากไคลเอนต์ได้รับการกำหนดค่าผิดพลาดหรือมีข้อผิดพลาดนั่นคือสิ่งที่ผู้ใช้ของฉัน
ไมเคิลโคล

3
ฉันเห็นด้วยกับ Florian วิธีการที่เชื่อถือได้? ชนิดของ ข้อมูลที่เชื่อถือได้? ไม่แน่นอน
Rob

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