วิธีปฏิบัติที่ดีที่สุดในการจัดเก็บ DateTime โดยใช้ TimeZone


16

การพัฒนาเว็บแอปพลิเคชันที่ควรอนุญาตให้ผู้ใช้กำหนดเวลาการนัดหมายตามโซนเวลาของพวกเขา และฉันกำลังจัดเก็บวันที่และเวลาที่ผู้ใช้กำหนดไว้เป็นวันที่เซิร์ฟเวอร์ลงในฐานข้อมูล ในขณะที่แสดงข้อมูลกำหนดการดึงค่าจากฐานข้อมูลและแปลงเป็นเขตเวลาผู้ใช้ กำลังประมวลผลในรหัสฐานฉันกำลังแปลง DateTime ตามเขตเวลาของผู้ใช้ กรุณาแนะนำว่าวิธีปฏิบัติที่ดีที่สุดนี้มีอยู่หรือไม่

คำตอบ:


33

ยินดีต้อนรับสู่หนึ่งในปัญหาที่ยากที่สุดในการเขียนโปรแกรมแบบไม่คำนวณ - แสดงวันที่และเวลาให้กับผู้ใช้อย่างถูกต้อง

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

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


1
+1 และมันมีความยืดหยุ่น การมีมาตรฐานอ้างอิงทั่วไปที่สม่ำเสมอและเป็นสากลทุกครั้งที่ "การอ้างอิง" นั้นจะทำอย่างถูกต้อง
Radarbob

ที่จริงแล้วการกำหนดเวลาการนัดหมายเป็นหนึ่งในไม่กี่ครั้งเมื่อคุณอาจไม่จัดเก็บเป็น UTC: หากการเปลี่ยนแปลงกฎ DST (หรือออฟเซ็ตจาก UTC) จะเกิดอะไรขึ้นกับเวลาการนัดหมาย ในกรณีส่วนใหญ่คุณต้องการให้เวลาในการนัดหมายเหมือนเดิมภายในเครื่องซึ่งหมายความว่าการเปลี่ยนแปลงค่า UTC คุณน่าจะต้องการเก็บค่าที่เป็นตัวแทนของ "TimeInTimeZone + TimeZone" ซึ่งคุณสามารถรับ UTC ได้อย่างง่ายดาย การจัดตารางเวลาข้ามเขต (เช่นสายการบิน) มีข้อ จำกัด ซึ่งอาจหมายถึงการใช้ทั้งสองอย่างร่วมกัน
ลาน-Muse

1
โอ้มันเลวร้ายยิ่งกว่านั้น ฉันมีการประชุมกับเพื่อนร่วมงานในประเทศอื่นเป็นประจำซึ่งกฎการเปลี่ยนแปลงเวลาแตกต่างจากของฉัน เมื่อเกิดอะไรขึ้นคำตอบที่ถูกต้องคืออะไร จริงๆแล้วไม่มีคอมพิวเตอร์รู้ :-(
Ross Patterson

3

วิธีที่ง่ายที่สุดในการจัดการกับข้อมูลวันที่ / เวลาขึ้นอยู่กับข้อกำหนดของใบสมัครของคุณ

หากวันที่และเวลาถูกป้อนโดยผู้ใช้และเซิร์ฟเวอร์ไม่มีการประมวลผลด้วยข้อมูลวันที่ / เวลานั้นนอกจากจะเก็บไว้ในฐานข้อมูลและไม่มีความคาดหวังว่าเวลาที่ป้อนจะถูกปรับให้เข้ากับตำแหน่งที่ดู (ตัวอย่างเช่น ผู้ใช้ป้อน "8:00 PM" และควรแสดงเป็น "8:00 PM" ไม่ว่าจะดูจากที่ไหนบนโลก) จากนั้นวิธีที่ง่ายที่สุดคือการจัดเก็บ DateTime เป็นเวลาท้องถิ่นโดยไม่มีข้อมูลเขตเวลาใด ๆ

ในทางกลับกันถ้าเซิร์ฟเวอร์ต้องใช้ DateTime ที่ป้อนเป็นตัวกระตุ้นให้ทำอะไรบางอย่างหรือหากควรปรับเวลาให้เหมาะสมกับเขตเวลาปัจจุบันตัวเลือกที่ดีที่สุดของคุณคือการเก็บ DateTime เป็นเวลา UTC และปรับเป็น Local เวลา (สำหรับตำแหน่งปัจจุบันของผู้ใช้) ทุกครั้งที่คุณอ่านจากฐานข้อมูล


-1 สำหรับ "เก็บไว้ในเวลาท้องถิ่น", +1 สำหรับ "เก็บไว้ใน UTC"
Ross Patterson

@RossPatterson: คุณสามารถอธิบาย '-1 สำหรับ "เก็บไว้ในเวลาท้องถิ่น"' ได้หรือไม่? ฉันอยากรู้ว่าทำไมมันควรจะเป็นความคิดที่ไม่ดีกำหนดเงื่อนไขที่ฉันให้กับมัน
Bart van Ingen Schenau

1
ตัวอย่างเช่นการใช้เวลาท้องถิ่นของผู้ใช้หมายความว่าทุกค่ามีประสิทธิภาพหนึ่งในหลาย ๆ ชนิดของข้อมูลที่แตกต่างกัน ซึ่งหมายความว่าคุณไม่สามารถดำเนินการกับฐานข้อมูลได้อย่างน่าสนใจเช่น "TIMESTAMP> '2013-08-27T12: 00: 00'" นั่นหมายความว่าคุณไม่สามารถทราบได้ว่าจะใช้การแปลงเวลาตามฤดูกาลหรือไม่และเมื่อใด
Ross Patterson

@RossPatterson: ขอบคุณ ฉันยอมรับว่าเวลาท้องถิ่นไม่ใช่ทางออกที่ถูกต้องในกรณีส่วนใหญ่
Bart van Ingen Schenau

2

มันเป็นสิ่งสำคัญที่คุณไม่ต้องพูดคุยสองแนวคิดที่เกี่ยวข้อง

หากคุณกำลังจัดการกับจุดที่เกิดขึ้นจริงในเวลานั่นคือเวลาที่เฉพาะเจาะจงในวันที่ระบุจากนั้นวิธีเดียวที่จะทำเช่นนี้คือการใช้ค่าเวลา UTC สากล อย่าพยายามจัดเก็บสิ่งนี้เป็นค่าที่เกี่ยวข้องกับเขตเวลา เมื่อแสดงค่าเวลานี้เป็นผู้ใช้ให้แปลงเป็นเขตเวลาของผู้ใช้ในเวลานั้นเสมอ (และอย่าลืมทั้งเวลาและวันที่ขึ้นอยู่กับเขตเวลา)

อีกแนวคิดคือ "การแสดงออกทางเวลา" เช่น "8:00 PM ทุกวันอังคาร" คุณกล่าวถึงเป็นการเฉพาะที่อนุญาตให้บุคคลกำหนดเวลาการนัดหมายและหากคุณมีการนัดหมายซ้ำคุณต้องมีการแสดงออกเช่นนั้น ฉันไม่รู้ภาษานิพจน์มาตรฐานใด ๆ แต่สิ่งที่คุณใช้มันจะสัมพันธ์กับเขตเวลาของบุคคลที่ระบุ มันจะเป็นการดีที่สุดที่จะทำให้ชัดเจนเช่น "8:00 PM ทุกวันอังคารในโซนเวลาแปซิฟิก" ในกรณีของนิพจน์เวลาคุณเก็บสิ่งนี้เป็นสตริงเสมอและไม่เกี่ยวข้องกับรูปแบบเวลาระบบใด ๆ

ดูการสนทนาเพิ่มเติมนี้ในบล็อกของฉัน


1

คำตอบมากมายที่นี่บ่งบอกว่าการจัดเก็บเป็น UTC แต่ระวังให้ดีด้วย ตัวอย่างเช่นหากคุณกำหนดเวลาการนัดหมายเวลา 12.00 น. แต่การนัดหมายเกิดขึ้นหลังจากการเปลี่ยนเป็นการปรับเวลาตามฤดูกาลจะเกิดอะไรขึ้น UTC จะไม่เก็บข้อมูลใด ๆ ว่า dst ทำงานอยู่หรือไม่เมื่อมีการจัดเก็บการนัดหมาย ระบบที่มีชื่อเสียงขนาดใหญ่จำนวนมากได้ทำข้อผิดพลาดนี้ซึ่งผู้ใช้ส่งอีเมลเวลา 9.00 น. ในฤดูร้อนและในฤดูหนาวเวลาที่ส่งจะแสดงเวลา 8:00 น. เนื่องจากการคำนวณย้อนกลับจาก UTC ขึ้นอยู่กับเวลาที่คุณดูเวลา ไม่เปิดเมื่อบันทึกวันที่และเวลา

ดีกว่ามากคือการถือว่าผู้ใช้ของคุณต้องการมีเวลาที่เขาเลือกเสมอ ไม่มีการแปลง UTC ไม่มีการแปลงเวลาไม่มีข้อมูลเขตเวลาไม่มีอะไร การนัดหมายเวลา 08:00 น. - 12:00 น. ในวันที่ 21 มีนาคม 2559 เป็นเพียงแค่นั้น อย่าใช้เวลาท้องถิ่นหรือเวลา UTC แต่ไม่ได้ระบุเวลา (ใน json สิ่งนี้ไม่มีทั้ง z หรือ + โดยทั่วไปใน. NET สิ่งนี้มี DateTime.Kind = DateTimeKind.Unspecified)

แน่นอนถ้ากรณีการใช้งานของคุณคือคุณเป็น บริษัท ที่จัดการประชุมกับใครบางคนจากเขตเวลาที่แตกต่างกันและคุณต้องการดูข้อมูลนี้ในปฏิทินของ บริษัท แต่ให้ผู้ใช้เห็นเวลาที่อยู่ในเขตเวลาของพวกเขา ซับซ้อนมากขึ้น เวลาจะต้องถูกต้องสำหรับคนที่แตกต่างกันในเขตเวลาที่ต่างกัน (ซัพพลายเออร์และลูกค้า)

ในกรณีเหล่านั้นคุณอาจต้องการบันทึกเมื่อการนัดหมายถูกบันทึกลงในฐานข้อมูลในเขตเวลาใดและหากรวม dst หรือไม่ ด้วยวิธีนี้คุณสามารถคำนวณเวลาท้องถิ่นกลับไปหาสิ่งอื่น ๆ ได้ไม่ว่าจะเป็นตอนนี้หรือสิ่งที่ตั้งใจจะเป็นในอดีต เนื่องจากเขตเวลาไม่คงที่ทำให้สิ่งต่าง ๆ มีความซับซ้อนมากยิ่งขึ้น

โชคดีที่นี้เป็นที่ที่ห้องสมุดเช่นhttp://nodatime.org/มาและจะขอแนะนำ พวกเขาทำงานกับวันที่อย่างต่อเนื่องมากขึ้น ถึงอย่างนั้นฉันก็ขอแนะนำให้คุณใช้ตัวแปรและตรรกะทั้งหมดในชุดข้อมูลของคุณในอินเทอร์เฟซของคุณเองโดยใช้อินเทอร์เฟซเพื่อให้สามารถเย้ยหยันได้แล้วคุณยังสามารถสลับตรรกะในภายหลังได้


ฉันไม่เห็นด้วยกับข้อสรุปของคุณมากนัก แต่การประชุมตอนเที่ยงที่กำหนดไว้สำหรับการเปลี่ยนการออมในเวลากลางวันเป็นความท้าทายพิเศษเช่นเดียวกับการประชุมประจำสัปดาห์ตอนเที่ยงที่ถูกจองไปหลายปีในอนาคต
Bent

" แน่นอนถ้ากรณีการใช้งานของคุณคือคุณเป็น บริษัท ที่จัดการประชุมกับใครบางคนจากเขตเวลาที่แตกต่างกันและคุณต้องการดูข้อมูลนี้ในปฏิทินของ บริษัท แต่ให้ผู้ใช้เห็นเวลาที่อยู่ในเขตเวลาของพวกเขา มันซับซ้อนมากขึ้น "- นั่นก็คือทุก บริษัท มี บริษัท น้อยมากที่อยู่นอกประเทศจีนและอินเดียที่สามารถเพิกเฉยต่อการนัดหมายข้ามช่วงเวลาได้
รอสส์แพตเตอร์สัน

" ด้วยวิธีนี้คุณสามารถคำนวณเวลาท้องถิ่นกลับไปหาสิ่งอื่น ๆ ได้ไม่ว่าจะเป็นตอนนี้หรือสิ่งที่ตั้งใจจะเป็นในอดีตเพราะเขตเวลาไม่คงที่มากทำให้สิ่งต่าง ๆ มีความซับซ้อนมากขึ้น " - ครั้งเดียว คุณยอมรับว่าคุณกำลังจะทำให้การคำนวณคุณจริงๆต้องเลือกเป็นตัวแทนเพียงหนึ่งเดียวสำหรับเวลา UTC, EST (แต่ไม่ใช่ EST5EDT), IST, อะไรก็ตาม แต่คุณไม่สามารถมีค่าตามเขตเวลาหลายเขตในเขตข้อมูลเดียวกันและทำการประมวลผลรวมที่ถูกต้องตามกฎหมายในเขตดังกล่าว แสดงผลการประมวลผลแน่นอน แต่นั่นเป็นส่วนที่ง่าย
Ross Patterson

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