คู่มือฉบับสมบูรณ์สำหรับการจัดการ DateTime
เผยแพร่แล้ว: 2022-03-11ในฐานะนักพัฒนาซอฟต์แวร์ คุณไม่สามารถหลีกเลี่ยงการจัดการวันที่ได้ เกือบทุกแอพที่นักพัฒนาสร้างจะมีองค์ประกอบบางอย่างซึ่งจำเป็นต้องได้รับวันที่/เวลาจากผู้ใช้ เก็บไว้ในฐานข้อมูล และแสดงกลับไปยังผู้ใช้
ถามโปรแกรมเมอร์เกี่ยวกับประสบการณ์ในการจัดการวันที่และเขตเวลา และพวกเขาอาจจะแบ่งปันเรื่องราวเกี่ยวกับสงคราม การจัดการฟิลด์วันที่และเวลาไม่ใช่วิทยาศาสตร์จรวดอย่างแน่นอน แต่มักจะเป็นเรื่องที่น่าเบื่อหน่ายและเกิดข้อผิดพลาดได้ง่าย
มีบทความหลายร้อยบทความในหัวข้อนี้ อย่างไรก็ตาม ส่วนใหญ่มีความเป็นวิชาการเกินไป โดยเน้นที่รายละเอียดที่มีเนื้อหาสาระ หรือเป็นหย่อมๆ เกินไป โดยให้ตัวอย่างโค้ดสั้นๆ โดยไม่มีคำอธิบายประกอบมากนัก คู่มือเชิงลึกเกี่ยวกับการจัดการ DateTime จะช่วยให้คุณเข้าใจแนวคิดการเขียนโปรแกรมและแนวทางปฏิบัติที่ดีที่สุดที่เกี่ยวข้องกับเวลาและวันที่โดยไม่ต้องเรียกดูข้อมูลจำนวนมากในหัวข้อนี้
ในบทความนี้ ฉันจะช่วยให้คุณคิดอย่างชัดเจนเกี่ยวกับฟิลด์วันที่และเวลา และแนะนำแนวทางปฏิบัติที่ดีที่สุดที่สามารถช่วยให้คุณหลีกเลี่ยงเรื่องวันที่/เวลาได้ เราจะสำรวจแนวคิดหลักบางอย่างที่จำเป็นสำหรับการจัดการค่าวันที่และเวลาอย่างถูกต้อง รูปแบบที่สะดวกสำหรับการจัดเก็บค่า DateTime และถ่ายโอนผ่าน API และอื่นๆ
สำหรับผู้เริ่มต้น คำตอบที่ถูกต้องสำหรับรหัสการผลิตคือการใช้ไลบรารีที่เหมาะสมเกือบทุกครั้ง แทนที่จะใช้ไลบรารีของคุณเอง ปัญหาที่อาจเกิดขึ้นกับการคำนวณ DateTime ที่กล่าวถึงในบทความนี้เป็นเพียงส่วนเล็กๆ ของภูเขาน้ำแข็ง แต่ก็ยังมีประโยชน์ที่จะทราบ ไม่ว่าจะมีหรือไม่มีห้องสมุดก็ตาม
ไลบรารี DateTime ช่วยคุณได้หากคุณเข้าใจอย่างถูกต้อง
ไลบรารีวันที่ช่วยทำให้ชีวิตของคุณง่ายขึ้นในหลายๆ ทาง ซึ่งช่วยลดความยุ่งยากในการแยกวิเคราะห์วันที่ การคำนวณวันที่และการดำเนินการทางตรรกะ และการจัดรูปแบบวันที่ คุณสามารถค้นหาไลบรารีวันที่ที่เชื่อถือได้สำหรับทั้งส่วนหน้าและส่วนหลังเพื่อจัดการงานหนักส่วนใหญ่ให้คุณ
อย่างไรก็ตาม เรามักใช้ไลบรารีวันที่โดยไม่ได้คิดว่าวันที่/เวลาทำงานจริงอย่างไร วันที่/เวลาเป็นแนวคิดที่ซับซ้อน บั๊กที่เกิดขึ้นจากความเข้าใจที่ไม่ถูกต้องนั้นสามารถเข้าใจและแก้ไขได้ยากอย่างยิ่ง แม้จะต้องใช้ไลบรารี่วันที่ ในฐานะโปรแกรมเมอร์ คุณต้องเข้าใจพื้นฐานและสามารถชื่นชมปัญหาที่ไลบรารีวันที่แก้ไขเพื่อใช้ประโยชน์สูงสุดจากปัญหาเหล่านั้น
นอกจากนี้ ไลบรารีวันที่/เวลาสามารถพาคุณไปได้ไกลเท่านั้น ไลบรารีวันที่ทั้งหมดทำงานโดยให้คุณเข้าถึงโครงสร้างข้อมูลที่สะดวกเพื่อแสดง DateTime หากคุณกำลังส่งและรับข้อมูลผ่าน REST API ในที่สุดคุณจะต้องแปลงวันที่เป็นสตริง และในทางกลับกัน เนื่องจาก JSON ไม่มีโครงสร้างข้อมูลดั้งเดิมเพื่อแสดงถึง DateTime แนวคิดที่ฉันได้สรุปไว้ที่นี่จะช่วยให้คุณหลีกเลี่ยงปัญหาทั่วไปที่อาจเกิดขึ้นเมื่อทำการแปลงวันที่เป็นสตริงและการแปลงสตริงเป็นวันที่
หมายเหตุ: แม้ว่าฉันจะใช้ JavaScript เป็นภาษาการเขียนโปรแกรมที่กล่าวถึงในบทความนี้ แต่สิ่งเหล่านี้เป็นแนวคิดทั่วไปที่นำไปใช้กับภาษาการเขียนโปรแกรมเกือบทั้งหมดและไลบรารีวันที่ในระดับสูง ดังนั้น แม้ว่าคุณจะไม่เคยเขียน JavaScript สักบรรทัดมาก่อน โปรดอ่านต่อไปเพราะฉันแทบไม่มีความรู้เกี่ยวกับ JavaScript มาก่อนในบทความ
การทำให้เวลาเป็นมาตรฐาน
DateTime เป็นจุดที่เฉพาะเจาะจงมากในเวลา ลองคิดดู ขณะที่ฉันเขียนบทความนี้ นาฬิกาบนแล็ปท็อปของฉันจะแสดงวันที่ 21 กรกฎาคม 13:29 น. นี่คือสิ่งที่เราเรียกว่า "เวลาท้องถิ่น" เวลาที่ฉันเห็นบนนาฬิกาแขวนผนังรอบตัวฉันและบนนาฬิกาข้อมือ
ให้เวลาหรือใช้เวลาสักครู่ ถ้าฉันขอให้เพื่อนไปพบฉันที่ร้านกาแฟใกล้ๆ เวลา 15.00 น. ฉันสามารถคาดหวังได้ว่าจะพบเธอที่นั่นในช่วงเวลานั้นโดยประมาณ ในทำนองเดียวกัน จะไม่เกิดความสับสนใดๆ ถ้าฉันพูดแทน เช่น "อีกหนึ่งชั่วโมงครึ่งเจอกัน" เรามักพูดถึงเวลาแบบนี้กับคนที่อาศัยอยู่ในเมืองหรือเขตเวลาเดียวกัน
ลองนึกถึงสถานการณ์อื่น: ฉันต้องการบอกเพื่อนที่อาศัยอยู่ในอุปซอลา ประเทศสวีเดน ว่าฉันต้องการคุยกับเขาตอน 5 โมงเย็น ฉันส่งข้อความหาเขาว่า "เฮ้ แอนตัน คุยกันตอน 5 โมงเย็น" ฉันได้รับคำตอบทันทีว่า “เวลาของคุณหรือเวลาของฉัน”
Anton บอกฉันว่าเขาอาศัยอยู่ในเขตเวลายุโรปกลาง ซึ่งก็คือ UTC+01:00 ฉันอาศัยอยู่ที่ UTC+05:45 ซึ่งหมายความว่าเวลา 17.00 น. ที่ฉันอาศัยอยู่คือ 17.00 น. - 05:45 น. = 11:15 น. UTC ซึ่งแปลเป็น 11:15 น. UTC + 01:00 = 12:15 น. ในอุปซอลา เหมาะสำหรับทั้งคู่ ของเรา.
นอกจากนี้ พึงระวังความแตกต่างระหว่างเขตเวลา (เวลายุโรปกลาง) และเขตเวลาชดเชย (UTC+05:45) ประเทศต่างๆ สามารถตัดสินใจเปลี่ยนการชดเชยเขตเวลาสำหรับเวลาออมแสงได้ด้วยเหตุผลทางการเมืองเช่นกัน เกือบทุกปีมีการเปลี่ยนแปลงกฎในอย่างน้อยหนึ่งประเทศ ซึ่งหมายความว่าโค้ดใดๆ ที่มีกฎเหล่านี้ที่ฝังอยู่ในนั้นจะต้องได้รับการอัปเดตอยู่เสมอ ควรพิจารณาว่าฐานโค้ดของคุณขึ้นอยู่กับสิ่งนี้ในแต่ละระดับของแอปอย่างไร
นั่นเป็นอีกเหตุผลที่ดีที่เราจะแนะนำว่าในกรณีส่วนใหญ่ส่วนหน้าเท่านั้นที่เกี่ยวข้องกับเขตเวลา เมื่อไม่เป็นเช่นนั้น จะเกิดอะไรขึ้นเมื่อกฎที่กลไกฐานข้อมูลของคุณใช้ไม่ตรงกับกฎส่วนหน้าหรือส่วนหลังของคุณ
ปัญหานี้ในการจัดการเวลาสองเวอร์ชันที่แตกต่างกัน ซึ่งสัมพันธ์กับผู้ใช้และเทียบกับมาตรฐานที่ยอมรับในระดับสากล เป็นเรื่องยาก ยิ่งกว่านั้นในโลกของการเขียนโปรแกรมที่ความแม่นยำเป็นกุญแจสำคัญ และแม้แต่วินาทีเดียวก็สามารถสร้างความแตกต่างได้อย่างมาก ขั้นตอนแรกในการแก้ปัญหาเหล่านี้คือการจัดเก็บ DateTime ไว้ใน UTC
การปรับรูปแบบให้เป็นมาตรฐาน
การปรับเวลาให้เป็นมาตรฐานเป็นสิ่งที่ยอดเยี่ยม เพราะฉันต้องจัดเก็บเวลา UTC เท่านั้น และตราบใดที่ฉันรู้เขตเวลาของผู้ใช้ ฉันก็แปลงเป็นเวลาของพวกเขาได้เสมอ ในทางกลับกัน หากฉันรู้เวลาท้องถิ่นของผู้ใช้และรู้เขตเวลาของพวกเขา ฉันสามารถแปลงเป็น UTC ได้
แต่สามารถระบุวันที่และเวลาได้หลายรูปแบบ สำหรับวันที่ คุณสามารถเขียนว่า “30 กรกฎาคม” หรือ “30 กรกฎาคม” หรือ “7/30” (หรือ 30/7 ขึ้นอยู่กับที่คุณอาศัยอยู่) สำหรับช่วงเวลานั้น คุณสามารถเขียนว่า “21:30 PM” หรือ “2130”
นักวิทยาศาสตร์ทั่วโลกมารวมตัวกันเพื่อแก้ไขปัญหานี้ และตัดสินใจเลือกรูปแบบเพื่ออธิบายเวลาที่โปรแกรมเมอร์ชอบจริงๆ เพราะมันสั้นและแม่นยำ เราชอบเรียกมันว่า "รูปแบบวันที่ ISO" ซึ่งเป็นเวอร์ชันย่อของรูปแบบขยาย ISO-8601 และมีลักษณะดังนี้:
สำหรับ 00:00 น. หรือ UTC เราใช้ “Z” แทน ซึ่งหมายถึงเวลาซูลู ซึ่งเป็นชื่ออื่นสำหรับ UTC
การจัดการวันที่และเลขคณิตใน JavaScript
ก่อนที่เราจะเริ่มต้นด้วยแนวทางปฏิบัติที่ดีที่สุด เราจะเรียนรู้เกี่ยวกับการจัดการวันที่โดยใช้ JavaScript เพื่อทำความเข้าใจไวยากรณ์และแนวคิดทั่วไป แม้ว่าเราจะใช้ JavaScript คุณสามารถปรับข้อมูลนี้ให้เข้ากับภาษาการเขียนโปรแกรมที่คุณชื่นชอบได้อย่างง่ายดาย
เราจะใช้เลขคณิตวันที่เพื่อแก้ปัญหาทั่วไปเกี่ยวกับวันที่ที่นักพัฒนาส่วนใหญ่พบเจอ
เป้าหมายของฉันคือการทำให้คุณสบายใจที่จะสร้างวัตถุวันที่จากสตริงและแยกส่วนประกอบออกจากหนึ่ง นี่คือสิ่งที่ห้องสมุดวันที่สามารถช่วยคุณได้ แต่จะดีกว่าเสมอที่จะเข้าใจวิธีการทำเบื้องหลัง
เมื่อเราจัดการกับวันที่/เวลาแล้ว เราก็จะนึกถึงปัญหาที่เราเผชิญ ดึงแนวทางปฏิบัติที่ดีที่สุด และเดินหน้าต่อไปได้ง่ายขึ้น หากคุณต้องการข้ามไปยังแนวทางปฏิบัติที่ดีที่สุด อย่าลังเลที่จะทำเช่นนั้น แต่ฉันขอแนะนำอย่างยิ่งให้คุณอ่านอย่างน้อยผ่านส่วนวันที่-เลขคณิตด้านล่าง
วัตถุวันที่ JavaScript
ภาษาโปรแกรมมีโครงสร้างที่เป็นประโยชน์เพื่อทำให้ชีวิตของเราง่ายขึ้น ออบเจ็กต์ JavaScript Date
เป็นสิ่งหนึ่ง มีวิธีการที่สะดวกในการรับวันที่และเวลาปัจจุบัน จัดเก็บวันที่ในตัวแปร คำนวณวันที่ และจัดรูปแบบวันที่ตามตำแหน่งที่ตั้งของผู้ใช้
เนื่องจากความแตกต่างระหว่างการใช้งานเบราว์เซอร์และการจัดการเวลาออมแสง (DST) ที่ไม่ถูกต้อง) ไม่แนะนำให้ใช้ออบเจ็กต์ Date สำหรับแอปพลิเคชันที่มีความสำคัญต่อภารกิจ และคุณควรใช้ไลบรารี DateTime เช่น Luxon, date-fns หรือ dayjs (ไม่ว่าคุณจะใช้อะไรก็ตาม ให้หลีกเลี่ยง Moment.js ที่เคยโด่งดัง—ซึ่งมักเรียกง่ายๆ ว่า moment
ตามที่ปรากฏในโค้ด—เนื่องจากตอนนี้เลิกใช้แล้ว)
แต่เพื่อวัตถุประสงค์ทางการศึกษา เราจะใช้วิธีการที่อ็อบเจ็กต์ Date() มีให้เพื่อเรียนรู้วิธีที่ JavaScript จัดการกับ DateTime
รับวันที่ปัจจุบัน
const currentDate = new Date();
ถ้าคุณไม่ส่งต่อสิ่งใดไปยังตัวสร้างวันที่ ออบเจ็กต์วันที่ที่ส่งคืนจะมีวันที่และเวลาปัจจุบัน
จากนั้นคุณสามารถจัดรูปแบบเพื่อแยกเฉพาะส่วนของวันที่ดังต่อไปนี้:
const currentDate = new Date(); const currentDayOfMonth = currentDate.getDate(); const currentMonth = currentDate.getMonth(); // Be careful! January is 0, not 1 const currentYear = currentDate.getFullYear(); const dateString = currentDayOfMonth + "-" + (currentMonth + 1) + "-" + currentYear; // "27-11-2020"
หมายเหตุ: หลุมพราง “มกราคมคือ 0” เป็นเรื่องปกติ แต่ไม่เป็นสากล ควรตรวจสอบเอกสารของภาษาใดๆ อีกครั้ง (หรือรูปแบบการกำหนดค่า: เช่น cron เป็นแบบ 1 ที่โดดเด่น) ก่อนที่คุณจะเริ่มใช้งาน
รับการประทับเวลาปัจจุบัน
หากคุณต้องการรับการประทับเวลาปัจจุบัน คุณสามารถสร้างวัตถุ Date ใหม่และใช้วิธี getTime()
const currentDate = new Date(); const timestamp = currentDate.getTime();
ใน JavaScript การประทับเวลาคือจำนวนมิลลิวินาทีที่ผ่านไปตั้งแต่วันที่ 1 มกราคม 1970
หากคุณไม่ต้องการรองรับ <IE8 คุณสามารถใช้ Date.now()
เพื่อรับการประทับเวลาโดยตรงโดยไม่ต้องสร้างวัตถุ Date ใหม่
การแยกวันที่
การแปลงสตริงเป็นวัตถุวันที่ของ JavaScript ทำได้หลายวิธี
ตัวสร้างของวัตถุ Date ยอมรับรูปแบบวันที่ที่หลากหลาย:
const date1 = new Date("Wed, 27 July 2016 13:30:00"); const date2 = new Date("Wed, 27 July 2016 07:45:00 UTC"); const date3 = new Date("27 July 2016 13:30:00 UTC+05:45");
โปรดทราบว่าคุณไม่จำเป็นต้องรวมวันในสัปดาห์เนื่องจาก JS สามารถกำหนดวันในสัปดาห์สำหรับวันที่ใดๆ ได้
คุณยังสามารถส่งผ่านปี เดือน วัน ชั่วโมง นาที และวินาทีเป็นอาร์กิวเมนต์แยกกันได้:
const date = new Date(2016, 6, 27, 13, 30, 0);
แน่นอน คุณสามารถใช้รูปแบบวันที่ ISO ได้เสมอ:
const date = new Date("2016-07-27T07:45:00Z");
อย่างไรก็ตาม คุณสามารถประสบปัญหาได้หากคุณไม่ได้ระบุเขตเวลาอย่างชัดเจน!
const date1 = new Date("25 July 2016"); const date2 = new Date("July 25, 2016");
สิ่งเหล่านี้จะให้เวลาคุณ 25 กรกฎาคม 2016 00:00:00 น. ตามเวลาท้องถิ่น
หากคุณใช้รูปแบบ ISO แม้ว่าคุณจะระบุเฉพาะวันที่ไม่ใช่เวลาและเขตเวลา ระบบจะยอมรับเขตเวลาเป็น UTC โดยอัตโนมัติ
ซึ่งหมายความว่า:
new Date("25 July 2016").getTime() !== new Date("2016-07-25").getTime() new Date("2016-07-25").getTime() === new Date("2016-07-25T00:00:00Z").getTime()
การจัดรูปแบบวันที่
โชคดีที่ JavaScript สมัยใหม่มีฟังก์ชันการทำให้เป็นสากลที่สะดวกสบายซึ่งสร้างขึ้นในเนมสเปซ Intl
มาตรฐานซึ่งทำให้การจัดรูปแบบวันที่ตรงไปตรงมา
สำหรับสิ่งนี้ เราจะต้องมีสองอ็อบเจ็กต์: Date
และ Intl.DateTimeFormat
ที่เริ่มต้นด้วยการตั้งค่าเอาต์พุตของเรา สมมติว่าเราต้องการใช้รูปแบบอเมริกัน (M/D/YYYY) จะมีลักษณะดังนี้:
const firstValentineOfTheDecade = new Date(2020, 1, 14); // 1 for February const enUSFormatter = new Intl.DateTimeFormat('en-US'); console.log(enUSFormatter.format(firstValentineOfTheDecade)); // 2/14/2020
หากเราต้องการรูปแบบดัตช์ (D/M/YYYY) เราก็จะส่งรหัสวัฒนธรรมอื่นไปยังตัวสร้าง DateTimeFormat
:
const nlBEFormatter = new Intl.DateTimeFormat('nl-BE'); console.log(nlBEFormatter.format(firstValentineOfTheDecade)); // 14/2/2020
หรือรูปแบบที่ยาวกว่าของรูปแบบอเมริกัน โดยระบุชื่อเดือน:
const longEnUSFormatter = new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric', }); console.log(longEnUSFormatter.format(firstValentineOfTheDecade)); // February 14, 2020
ทีนี้ ถ้าเราต้องการรูปแบบลำดับที่ถูกต้องในวันที่ของเดือน—นั่นคือ “วันที่ 14” แทนที่จะเป็นเพียง “14”— น่าเสียดายที่ต้องมีวิธีแก้ปัญหาเล็กน้อย เนื่องจากค่าที่ถูกต้องของ day
เท่านั้น ณ วันที่เขียนนี้คือ "numeric"
หรือ "2-digit"
การยืมรหัส Mathias Bynens เวอร์ชันของ Flavio Copes เพื่อใช้ประโยชน์จากส่วนอื่นของ Intl
สำหรับสิ่งนี้ เราสามารถปรับแต่งวันของเดือนที่ส่งออกผ่าน formatToParts()
:
const pluralRules = new Intl.PluralRules('en-US', { type: 'ordinal' }) const suffixes = { 'one': 'st', 'two': 'nd', 'few': 'rd', 'other': 'th' } const convertToOrdinal = (number) => `${number}${suffixes[pluralRules.select(number)]}` // At this point: // convertToOrdinal("1") === "1st" // convertToOrdinal("2") === "2nd" // etc. const extractValueAndCustomizeDayOfMonth = (part) => { if (part.type === "day") { return convertToOrdinal(part.value); } return part.value; }; console.log( longEnUSFormatter.formatToParts(firstValentineOfTheDecade) .map(extractValueAndCustomizeDayOfMonth) .join("") ); // February 14th, 2020
น่าเสียดายที่ Internet Explorer (IE) ไม่รองรับ formatToParts
เลยในขณะที่เขียนบทความนี้ แต่เทคโนโลยีเดสก์ท็อป มือถือ และแบ็กเอนด์ (เช่น Node.js) อื่นๆ ทั้งหมดได้รับการสนับสนุน สำหรับผู้ที่ต้องการสนับสนุน IE และต้องการลำดับขั้นจริงๆ โน้ตข้างใต้ (หรือดีกว่าคือ ไลบรารีวันที่ที่เหมาะสม) จะให้คำตอบ
หากคุณต้องการสนับสนุนเบราว์เซอร์รุ่นเก่า เช่น IE ก่อนเวอร์ชัน 11 การจัดรูปแบบวันที่ใน JavaScript จะยากขึ้น เนื่องจากไม่มีฟังก์ชันการจัดรูปแบบวันที่มาตรฐาน เช่น strftime
ใน Python หรือ PHP
ตัวอย่างเช่นใน PHP ฟังก์ชัน strftime("Today is %b %d %Y %X", mktime(5,10,0,12,30,99))
ให้ Today is Dec 30 1999 05:10:00
น.
คุณสามารถใช้ตัวอักษรผสมกันที่นำหน้าด้วย %
เพื่อรับวันที่ในรูปแบบต่างๆ ได้ (โปรดระวัง ไม่ใช่ว่าทุกภาษาจะกำหนดความหมายเดียวกันให้กับตัวอักษรแต่ละตัว โดยเฉพาะอย่างยิ่ง 'M' และ 'm' อาจสลับกันเป็นนาทีและเดือน)
หากคุณแน่ใจว่าต้องการใช้รูปแบบใด วิธีที่ดีที่สุดคือการแยกแต่ละบิตโดยใช้ฟังก์ชัน JavaScript ที่เรากล่าวถึงข้างต้น และสร้างสตริงด้วยตัวคุณเอง
var currentDate = new Date (); var date = currentDate.getDate(); var month = currentDate.getMonth(); var year = currentDate.getFullYear();
เราจะได้วันที่ในรูปแบบ ดด/วว/ปปปป เป็น
var monthDateYear = (month+ 1 ) + "/" + date + "/" + year;
ปัญหาของวิธีแก้ปัญหานี้คือสามารถให้วันที่มีความยาวไม่สอดคล้องกัน เนื่องจากบางเดือนและวันของเดือนเป็นตัวเลขหลักเดียวและบางวันเป็นตัวเลขสองหลัก นี่อาจเป็นปัญหาได้ ตัวอย่างเช่น หากคุณกำลังแสดงวันที่ในคอลัมน์ตาราง เนื่องจากวันที่ไม่เรียงกัน
เราสามารถแก้ไขปัญหานี้ได้โดยใช้ฟังก์ชัน "pad" ที่เพิ่ม 0 นำหน้า
function pad ( n ) { return n< 10 ? '0' +n : n; }
ตอนนี้ เราได้รับวันที่ที่ถูกต้องในรูปแบบ ดด/วว/ปปปป โดยใช้:
var mmddyyyy = pad(month + 1 ) + "/" + pad(date) + "/" + year;
หากเราต้องการ DD-MM-YYYY แทน กระบวนการจะคล้ายกัน:
var ddmmyyyy = pad(date) + "-" + pad(month + 1 ) + "-" + year;
ลองใส่ ante แล้วลองพิมพ์วันที่ในรูปแบบ "เดือน, ปี" เราจะต้องมีการแมปดัชนีเดือนกับชื่อ:
var monthNames = [ "January" , "February" , "March" , "April" , "May" , "June" , "July" , "August" , "September" , "October" , "November" , "December" ]; var dateWithFullMonthName = monthNames[month] + " " + pad(date) + ", " + year;
บางคนชอบแสดงวันที่เป็น 1 มกราคม 2013 ไม่มีปัญหา เราต้องการแค่ฟังก์ชันผู้ ordinal
ที่ส่งกลับค่าที่ 1 สำหรับ 1, 12 สำหรับ 12 และ 103 สำหรับ 103 เป็นต้น และที่เหลือก็ง่ายๆ:
var ordinalDate = ordinal(date) + " " + monthNames[month] + ", " + year;
การระบุวันในสัปดาห์จากออบเจ็กต์วันที่เป็นเรื่องง่าย ให้เพิ่มใน:
var daysOfWeek = [ "Sun" , "Mon" , "Tue" , "Wed" , "Thu" , "Fri" , "Sat" ]; ordinalDateWithDayOfWeek = daysOfWeek[currentDate.getDay()] + ", " + ordinalDate;
จุดที่ใหญ่กว่านี้คือ เมื่อคุณดึงตัวเลขจากวันที่ได้แล้ว การจัดรูปแบบส่วนใหญ่เกี่ยวข้องกับสตริง
การเปลี่ยนรูปแบบวันที่
เมื่อคุณรู้วิธีแยกวิเคราะห์วันที่และจัดรูปแบบแล้ว การเปลี่ยนวันที่จากรูปแบบหนึ่งเป็นอีกรูปแบบหนึ่งเป็นเพียงเรื่องของการรวมทั้งสองเข้าด้วยกัน
ตัวอย่างเช่น หากคุณมีวันที่ในรูปแบบ 21 กรกฎาคม 2013 และต้องการเปลี่ยนรูปแบบเป็น 21-07-2013 สามารถทำได้ดังนี้:
const myDate = new Date("Jul 21, 2013"); const dayOfMonth = myDate.getDate(); const month = myDate.getMonth(); const year = myDate.getFullYear(); function pad(n) { return n<10 ? '0'+n : n } const ddmmyyyy = pad(dayOfMonth) + "-" + pad(month + 1) + "-" + year; // "21-07-2013"
การใช้ฟังก์ชันการแปลของออบเจ็กต์วันที่ของ JavaScript
วิธีการจัดรูปแบบวันที่ที่เรากล่าวถึงข้างต้นควรใช้ได้กับแอปพลิเคชันส่วนใหญ่ แต่ถ้าคุณต้องการแปลการจัดรูปแบบของวันที่จริงๆ ฉันขอแนะนำให้คุณใช้เมธอด toLocaleDateString()
ของออบเจ็กต์ Date
:
const today = new Date().toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric', });
…ให้อะไรกับเราบ้าง เช่น 26 Jul 2016
.

การเปลี่ยนโลแคลเป็น 'en-US' จะให้ "Jul 26, 2016" แทน สังเกตว่าการจัดรูปแบบเปลี่ยนไปอย่างไร แต่ตัวเลือกการแสดงผลยังคงเหมือนเดิม ซึ่งเป็นคุณลักษณะที่มีประโยชน์มาก ตามที่แสดงในส่วนก่อนหน้า เทคนิคที่ใช้ Intl.DateTimeFormat
ที่ใหม่กว่านั้นทำงานคล้ายกันมาก แต่ให้คุณนำออบเจ็กต์ตัวจัดรูปแบบกลับมาใช้ใหม่ได้ คุณจึงจำเป็นต้องตั้งค่าตัวเลือกเพียงครั้งเดียว
ด้วย toLocaleDateString()
คุณควรส่งตัวเลือกการจัดรูปแบบเสมอ แม้ว่าผลลัพธ์จะออกมาดูดีบนคอมพิวเตอร์ของคุณก็ตาม สิ่งนี้สามารถป้องกัน UI ไม่ให้แตกในสถานที่ที่ไม่คาดคิดด้วยชื่อเดือนที่ยาวมากหรือดูอึดอัดเพราะชื่อสั้น
ถ้าฉันต้องการเดือนเต็ม "กรกฎาคม" แทน ทั้งหมดที่ฉันทำคือเปลี่ยนพารามิเตอร์เดือนในตัวเลือกเป็น "ยาว" JavaScript จัดการทุกอย่างให้ฉัน สำหรับ en-US ตอนนี้ฉันได้รับ 26 กรกฎาคม 2016
หมายเหตุ: หากคุณต้องการให้เบราว์เซอร์ใช้ตำแหน่งที่ตั้งของผู้ใช้โดยอัตโนมัติ คุณสามารถส่งผ่าน “undefined” เป็นพารามิเตอร์แรกได้
หากคุณต้องการแสดงวันที่ในรูปแบบตัวเลขและไม่ต้องการยุ่งกับ MM/DD/YYYY กับ DD/MM/YYYY สำหรับสถานที่ต่างๆ ฉันขอแนะนำวิธีแก้ปัญหาง่ายๆ ต่อไปนี้:
const today = new Date().toLocaleDateString(undefined, { day: 'numeric', month: 'numeric', year: 'numeric', });
บนคอมพิวเตอร์ของฉัน ผลลัพธ์นี้จะออกมา 7/26/2016
หากคุณต้องการตรวจสอบให้แน่ใจว่าเดือนและวันที่มีสองหลัก เพียงเปลี่ยนตัวเลือก:
const today = new Date().toLocaleDateString(undefined, { day: '2-digit', month: '2-digit', year: 'numeric', });
ผลลัพธ์นี้ 07/26/2016
สิ่งที่เราต้องการ!
คุณยังสามารถใช้ฟังก์ชันที่เกี่ยวข้องอื่นๆ เพื่อกำหนดวิธีการแสดงทั้งเวลาและวันที่:
รหัส | เอาท์พุต | คำอธิบาย |
---|---|---|
| "4:21:38 น." | แสดงเวอร์ชันที่แปลแล้วของเวลาเท่านั้น |
| "04:21:38 น." | แสดงเวลาท้องถิ่นตามตัวเลือกที่มีให้ |
| "7/22/2016, 04:21:38 น." | แสดงวันที่และเวลาสำหรับสถานที่ของผู้ใช้ |
| "22/2/2559 04:21 น." | แสดงวันที่และเวลาที่แปลตามตัวเลือกที่มีให้ |
การคำนวณวันที่และเวลาสัมพัทธ์
ต่อไปนี้คือตัวอย่างการเพิ่ม 20 วันให้กับวันที่ JavaScript (เช่น การหาวันที่ 20 วันหลังจากวันที่ที่ทราบ):
const myDate = new Date("July 20, 2016 15:00:00"); const nextDayOfMonth = myDate.getDate() + 20; myDate.setDate(nextDayOfMonth); const newDate = myDate.toLocaleString();
ออบเจ็กต์วันที่ดั้งเดิมตอนนี้แสดงวันที่ 20 วันหลังจากวันที่ 20 กรกฎาคม และ newDate
มีสตริงที่แปลแล้วซึ่งแสดงถึงวันที่นั้น บนเบราว์เซอร์ของฉัน newDate
ประกอบด้วย “8/9/2016, 15:00:00 PM”
ในการคำนวณการประทับเวลาสัมพัทธ์โดยมีค่าความแตกต่างที่แม่นยำกว่าทั้งวัน คุณสามารถใช้ Date.getTime()
และ Date.setTime()
เพื่อทำงานกับจำนวนเต็มที่แสดงจำนวนมิลลิวินาทีนับตั้งแต่ยุคหนึ่ง ซึ่งก็คือ 1 มกราคม 1970 สำหรับ ตัวอย่างเช่น หากคุณต้องการทราบว่าขณะนี้เป็นเวลา 17 ชั่วโมงหลังจากนั้น:
const msSinceEpoch = (new Date()).getTime(); const seventeenHoursLater = new Date(msSinceEpoch + 17 * 60 * 60 * 1000);
การเปรียบเทียบวันที่
เช่นเดียวกับทุกสิ่งทุกอย่างที่เกี่ยวข้องกับวันที่ วันที่เปรียบเทียบมี gotchas ของตัวเอง
ขั้นแรกเราต้องสร้างวัตถุวันที่ โชคดีที่ <, >, <= และ >= ทำงานได้ทั้งหมด ดังนั้นการเปรียบเทียบ 19 กรกฎาคม 2014 กับ 18 กรกฎาคม 2014 นั้นง่ายเหมือน:
const date1 = new Date("July 19, 2014"); const date2 = new Date("July 28, 2014"); if(date1 > date2) { console.log("First date is more recent"); } else { console.log("Second date is more recent"); }
การตรวจสอบความเท่าเทียมกันนั้นยากกว่า เนื่องจากวัตถุวันที่สองรายการที่แสดงวันที่เดียวกันยังคงเป็นวัตถุวันที่สองรายการที่แตกต่างกันและจะไม่เท่ากัน การเปรียบเทียบสตริงวันที่เป็นแนวคิดที่ไม่ดี เนื่องจาก ตัวอย่างเช่น "20 กรกฎาคม 2014" และ "20 กรกฎาคม 2014" แทนวันที่เดียวกันแต่มีการแสดงสตริงต่างกัน ตัวอย่างด้านล่างแสดงจุดแรก:
const date1 = new Date("June 10, 2003"); const date2 = new Date(date1); const equalOrNot = date1 == date2 ? "equal" : "not equal"; console.log(equalOrNot);
ซึ่งจะได้ผลลัพธ์ not equal
กรณีนี้สามารถแก้ไขได้โดยการเปรียบเทียบจำนวนเต็มของวันที่ (การประทับเวลา) ดังนี้
date1.getTime() == date2.getTime()
ฉันเคยเห็นตัวอย่างนี้ในหลาย ๆ ที่ แต่ฉันไม่ชอบเพราะคุณไม่ได้สร้างวัตถุวันที่จากวัตถุวันที่อื่นโดยปกติ ผมจึงรู้สึกว่าตัวอย่างมีความสำคัญจากมุมมองทางวิชาการเท่านั้น นอกจากนี้ สิ่งนี้ต้องการให้อ็อบเจ็กต์ Date ทั้งสองอ้างถึงวินาทีเดียวกันทั้งหมด ในขณะที่คุณอาจต้องการทราบว่าอ็อบเจ็กต์เหล่านั้นอ้างถึงวันหรือชั่วโมงหรือนาทีเดียวกันเท่านั้น
มาดูตัวอย่างการใช้งานจริงกันดีกว่า คุณกำลังพยายามเปรียบเทียบว่าวันเกิดที่ผู้ใช้ป้อนตรงกับวันที่โชคดีที่คุณได้รับจาก API หรือไม่
const userEnteredString = "12/20/1989"; // MM/DD/YYYY format const dateStringFromAPI = "1989-12-20T00:00:00Z"; const dateFromUserEnteredString = new Date(userEnteredString) const dateFromAPIString = new Date(dateStringFromAPI); if (dateFromUserEnteredString.getTime() == dateFromAPIString.getTime()) { transferOneMillionDollarsToUserAccount(); } else { doNothing(); }
ทั้งสองแสดงวันเดียวกัน แต่น่าเสียดายที่ผู้ใช้ของคุณจะไม่ได้รับล้านดอลลาร์
นี่คือปัญหา: JavaScript จะถือว่าเขตเวลาเป็นเขตที่เบราว์เซอร์จัดเตรียมไว้เสมอ เว้นแต่จะระบุไว้เป็นอย่างอื่นอย่างชัดเจน
ซึ่งหมายความว่า สำหรับฉัน new Date ("12/20/1989")
จะสร้างวันที่ 1989-12-20T00:00:00+5:45 หรือ 1989-12-19T18:15:00Z ซึ่งไม่เหมือนกับ 1989-12-20T00:00:00Z ในแง่ของการประทับเวลา
ไม่สามารถเปลี่ยนเฉพาะเขตเวลาของออบเจ็กต์วันที่ที่มีอยู่ ดังนั้นตอนนี้เป้าหมายของเราคือสร้างออบเจ็กต์วันที่ใหม่แต่ใช้ UTC แทนเขตเวลาท้องถิ่น
เราจะละเว้นเขตเวลาของผู้ใช้และใช้ UTC ขณะสร้างวัตถุวันที่ มีสองวิธีในการทำ:
- สร้างสตริงวันที่ที่จัดรูปแบบ ISO จากวันที่ผู้ใช้ป้อนและใช้เพื่อสร้างวัตถุวันที่ การใช้รูปแบบวันที่ ISO ที่ถูกต้องเพื่อสร้างออบเจ็กต์ Date ในขณะที่ทำให้เจตนาของ UTC เทียบกับท้องถิ่นมีความชัดเจนมาก
const userEnteredDate = "12/20/1989"; const parts = userEnteredDate.split("/"); const userEnteredDateISO = parts[2] + "-" + parts[0] + "-" + parts[1]; const userEnteredDateObj = new Date(userEnteredDateISO + "T00:00:00Z"); const dateFromAPI = new Date("1989-12-20T00:00:00Z"); const result = userEnteredDateObj.getTime() == dateFromAPI.getTime(); // true
นอกจากนี้ยังใช้งานได้หากคุณไม่ระบุเวลาเนื่องจากค่าเริ่มต้นจะเป็นเที่ยงคืน (เช่น 00:00:00Z):
const userEnteredDate = new Date("1989-12-20"); const dateFromAPI = new Date("1989-12-20T00:00:00Z"); const result = userEnteredDate.getTime() == dateFromAPI.getTime(); // true
ข้อควรจำ: หากคอนสตรัคเตอร์วันที่ถูกส่งผ่านสตริงในรูปแบบวันที่ ISO ที่ถูกต้องของ YYYY-MM-DD จะถือว่า UTC โดยอัตโนมัติ
- JavaScript มีฟังก์ชัน Date.UTC() ที่เรียบร้อยซึ่งคุณสามารถใช้เพื่อรับการประทับเวลา UTC ของวันที่ เราแยกส่วนประกอบจากวันที่และส่งไปยังฟังก์ชัน
const userEnteredDate = new Date("12/20/1989"); const userEnteredDateTimeStamp = Date.UTC(userEnteredDate.getFullYear(), userEnteredDate.getMonth(), userEnteredDate.getDate(), 0, 0, 0); const dateFromAPI = new Date("1989-12-20T00:00:00Z"); const result = userEnteredDateTimeStamp == dateFromAPI.getTime(); // true ...
ค้นหาความแตกต่างระหว่างสองวัน
สถานการณ์ทั่วไปที่คุณจะพบคือการค้นหาความแตกต่างระหว่างวันที่สองวัน
เราพูดถึงกรณีการใช้งานสองกรณี:
การหาจำนวนวันระหว่างสองวัน
แปลงวันที่ทั้งสองเป็นเวลา UTC ค้นหาความแตกต่างในหน่วยมิลลิวินาทีและหาวันที่เท่ากัน
const dateFromAPI = "2016-02-10T00:00:00Z"; const now = new Date(); const datefromAPITimeStamp = (new Date(dateFromAPI)).getTime(); const nowTimeStamp = now.getTime(); const microSecondsDiff = Math.abs(datefromAPITimeStamp - nowTimeStamp); // Math.round is used instead of Math.floor to account for certain DST cases // Number of milliseconds per day = // 24 hrs/day * 60 minutes/hour * 60 seconds/minute * 1000 ms/second const daysDiff = Math.round(microSecondsDiff / (1000 * 60 * 60 * 24)); console.log(daysDiff);
การหาอายุของผู้ใช้จากวันเดือนปีเกิด
const birthDateFromAPI = "12/10/1989";
หมายเหตุ: เรามีรูปแบบที่ไม่ได้มาตรฐาน อ่านเอกสาร API เพื่อดูว่าหมายถึง 12 ต.ค. หรือ 10 ธ.ค. ให้เปลี่ยนรูปแบบ ISO ตามลำดับ
const parts = birthDateFromAPI.split("/"); const birthDateISO = parts[2] + "-" + parts[0] + "-" + parts[1]; const birthDate = new Date(birthDateISO); const today = new Date(); let age = today.getFullYear() - birthDate.getFullYear(); if(today.getMonth() < birthDate.getMonth()) { age--; } if(today.getMonth() == birthDate.getMonth() && today.getDate() < birthDate.getDate()) { age--; }
ฉันรู้ว่ามีวิธีการเขียนโค้ดที่กระชับกว่านี้ แต่ฉันชอบที่จะเขียนด้วยวิธีนี้เพราะความชัดเจนของตรรกะ
คำแนะนำเพื่อหลีกเลี่ยงวันที่นรก
ตอนนี้เราคุ้นเคยกับการคำนวณวันที่แล้ว เราอยู่ในฐานะที่จะเข้าใจแนวทางปฏิบัติที่ดีที่สุดที่ควรปฏิบัติตามและเหตุผลในการติดตาม
รับ DateTime จาก User
หากคุณได้รับวันที่และเวลาจากผู้ใช้ คุณมักจะมองหา DateTime ในพื้นที่ของตน เราเห็นในส่วนเลขคณิตวันที่ว่าตัวสร้าง Date
สามารถรับวันที่ได้หลายวิธี
เพื่อขจัดความสับสน ฉันมักจะแนะนำให้สร้างวันที่โดยใช้ new Date(year, month, day, hours, minutes, seconds, milliseconds)
แม้ว่าคุณจะมีวันที่ในรูปแบบแยกวิเคราะห์ที่ถูกต้องแล้วก็ตาม หากโปรแกรมเมอร์ทุกคนในทีมของคุณปฏิบัติตามกฎง่ายๆ นี้ จะเป็นการง่ายมากที่จะรักษาโค้ดในระยะยาว เพราะมันชัดเจนมากที่สุดเท่าที่คุณจะทำได้ด้วยคอนสตรัคเตอร์ Date
ส่วนที่ยอดเยี่ยมคือคุณสามารถใช้รูปแบบต่างๆ ที่ช่วยให้คุณละเว้นพารามิเตอร์สี่ตัวสุดท้ายได้หากเป็นศูนย์ เช่น new Date(2012, 10, 12)
จะเหมือนกับ new Date(2012, 10, 12, 0, 0, 0, 0)
เนื่องจากพารามิเตอร์ที่ไม่ระบุมีค่าเริ่มต้นเป็นศูนย์
ตัวอย่างเช่น หากคุณกำลังใช้ตัวเลือกวันที่และเวลาที่ให้วันที่ 2012-10-12 และเวลา 12:30 น. คุณสามารถแยกส่วนต่างๆ และสร้างวัตถุ Date ใหม่ได้ดังนี้:
const dateFromPicker = "2012-10-12"; const timeFromPicker = "12:30"; const dateParts = dateFromPicker.split("-"); const timeParts = timeFromPicker.split(":"); const localDate = new Date(dateParts[0], dateParts[1]-1, dateParts[2], timeParts[0], timeParts[1]);
พยายามหลีกเลี่ยงการสร้างวันที่จากสตริง เว้นแต่จะอยู่ในรูปแบบวันที่ ISO ใช้วิธี Date(ปี, เดือน, วันที่, ชั่วโมง, นาที, วินาที, microseconds) แทน
รับเฉพาะวันที่
ตัวอย่างเช่น หากคุณได้รับเฉพาะวันที่ เช่น วันเกิดของผู้ใช้ ควรแปลงรูปแบบเป็นรูปแบบวันที่ ISO ที่ถูกต้อง เพื่อกำจัดข้อมูลเขตเวลาใดๆ ที่อาจทำให้วันที่เลื่อนไปข้างหน้าหรือย้อนกลับเมื่อแปลงเป็น UTC ตัวอย่างเช่น:
const dateFromPicker = "12/20/2012"; const dateParts = dateFromPicker.split("/"); const ISODate = dateParts[2] + "-" + dateParts[0] + "-" + dateParts[1]; const birthDate = new Date(ISODate).toISOString();
ในกรณีที่คุณลืม หากคุณสร้างวัตถุ Date
ด้วยอินพุตในรูปแบบวันที่ ISO ที่ถูกต้อง (YYYY-MM-DD) จะมีค่าเริ่มต้นเป็น UTC แทนที่จะตั้งค่าเริ่มต้นเป็นเขตเวลาของเบราว์เซอร์
การจัดเก็บวันที่
เก็บ DateTime ไว้ใน UTC เสมอ ส่งสตริงวันที่ ISO หรือการประทับเวลาไปที่ส่วนหลังเสมอ
โปรแกรมเมอร์คอมพิวเตอร์หลายชั่วอายุคนได้ตระหนักถึงความจริงง่ายๆ นี้หลังจากประสบการณ์อันขมขื่นที่พยายามแสดงเวลาท้องถิ่นที่ถูกต้องแก่ผู้ใช้ การจัดเก็บเวลาท้องถิ่นไว้ที่ส่วนหลังเป็นความคิดที่ไม่ดี ทางที่ดีควรให้เบราว์เซอร์จัดการการแปลงเป็นเวลาท้องถิ่นในส่วนหน้า
นอกจากนี้ ควรเห็นได้ชัดว่าคุณไม่ควรส่งสตริง DateTime เช่น "20 กรกฎาคม 1989 12:10 PM" ไปที่ส่วนหลัง แม้ว่าคุณจะส่งเขตเวลาด้วย คุณกำลังเพิ่มความพยายามให้โปรแกรมเมอร์คนอื่นๆ เข้าใจความตั้งใจของคุณ แยกวิเคราะห์และจัดเก็บวันที่อย่างถูกต้อง
ใช้เมธอด toISOString()
หรือ toJSON()
ของออบเจ็กต์ Date เพื่อแปลง DateTime ในเครื่องเป็น UTC
const dateFromUI = "12-13-2012"; const timeFromUI = "10:20"; const dateParts = dateFromUI.split("-"); const timeParts = timeFromUI.split(":"); const date = new Date(dateParts[2], dateParts[0]-1, dateParts[1], timeParts[0], timeParts[1]); const dateISO = date.toISOString(); $.post("http://example.com/", {date: dateISO}, ...)
การแสดงวันที่และเวลา
- รับการประทับเวลาหรือวันที่จัดรูปแบบ ISO จาก REST API
- สร้างวัตถุ
Date
- ใช้
toLocaleString()
หรือtoLocaleDateString()
และtoLocaleTimeString()
หรือไลบรารีวันที่เพื่อแสดงเวลาท้องถิ่น
const dateFromAPI = "2016-01-02T12:30:00Z"; const localDate = new Date(dateFromAPI); const localDateString = localDate.toLocaleDateString(undefined, { day: 'numeric', month: 'short', year: 'numeric', }); const localTimeString = localDate.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit', });
คุณควรเก็บเวลาท้องถิ่นด้วยเมื่อใด
“บางครั้ง สิ่งสำคัญคือต้องทราบเขตเวลาที่เกิดเหตุการณ์ และการแปลงเป็นเขตเวลาเดียวจะลบล้างข้อมูลนั้นอย่างไม่อาจเพิกถอนได้
“หากคุณกำลังโปรโมตการตลาดและต้องการทราบว่าลูกค้ารายใดทำการสั่งซื้อในช่วงเวลากลางวัน คำสั่งซื้อที่ดูเหมือนว่าจะส่งตอนเที่ยง GMT นั้นไม่มีประโยชน์อะไรมากเมื่อวางไว้เหนืออาหารเช้าในนิวยอร์กจริงๆ”
หากคุณเจอสถานการณ์แบบนี้ เป็นการดีกว่าที่จะประหยัดเวลาในท้องถิ่นด้วย ตามปกติเราต้องการสร้างวันที่ในรูปแบบ ISO แต่เราต้องค้นหาการชดเชยเขตเวลาก่อน
ฟังก์ชัน getTimeZoneOffset()
ของออบเจ็กต์ Date บอกเราว่าจำนวนนาทีที่เพิ่มไปยังเวลาท้องถิ่นที่กำหนดจะให้เวลา UTC ที่เท่ากัน ฉันแนะนำให้แปลงเป็นรูปแบบ (+-)hh:mm เพราะมันทำให้ชัดเจนมากขึ้นว่าเป็นการชดเชยเขตเวลา
const now = new Date(); const tz = now.gettime zoneOffset();
สำหรับเขตเวลาของฉัน +05:45 ฉันได้รับ -345 นี่ไม่ใช่แค่เครื่องหมายตรงข้าม แต่ตัวเลขเช่น -345 อาจทำให้นักพัฒนาส่วนหลังรู้สึกสับสน ดังนั้นเราจึงแปลงค่านี้เป็น +05:45
const sign = tz > 0 ? "-" : "+"; const hours = pad(Math.floor(Math.abs(tz)/60)); const minutes = pad(Math.abs(tz)%60); const tzOffset = sign + hours + ":" + minutes;
ตอนนี้เราได้รับค่าที่เหลือและสร้างสตริง ISO ที่ถูกต้องซึ่งแสดงถึง DateTime ในเครื่อง
const localDateTime = now.getFullYear() + "-" + pad(now.getMonth()+1) + "-" + pad(now.getDate()) + "T" + pad(now.getHours()) + ":" + pad(now.getMinutes()) + ":" + pad(now.getSeconds());
หากต้องการ คุณสามารถรวม UTC และวันที่ท้องถิ่นในออบเจ็กต์ได้
const eventDate = { utc: now.toISOString(), local: localDateTime, tzOffset: tzOffset, }
ในส่วนแบ็คเอนด์ หากคุณต้องการทราบว่าเหตุการณ์เกิดขึ้นก่อนเที่ยงวันตามเวลาท้องถิ่นหรือไม่ คุณสามารถแยกวิเคราะห์วันที่และเพียงแค่ใช้ getHours()
const localDateString = eventDate.local; const localDate = new Date(localDateString); if(localDate.getHours() < 12) { console.log("Event happened before noon local time"); }
เราไม่ได้ใช้ tzOffset
ที่นี่ แต่เรายังคงเก็บไว้เพราะเราอาจจำเป็นต้องใช้ในอนาคตเพื่อจุดประสงค์ในการดีบัก คุณสามารถส่งการชดเชยเขตเวลาและเวลา UTC เท่านั้น แต่ฉันชอบที่จะจัดเก็บเวลาท้องถิ่นด้วย เพราะในที่สุดคุณจะต้องเก็บวันที่ในฐานข้อมูล และการจัดเก็บเวลาท้องถิ่นแยกกันทำให้คุณสามารถสืบค้นข้อมูลตามเขตข้อมูลได้โดยตรง แทนที่จะต้องคำนวณเพื่อให้ได้วันที่ในท้องถิ่น
ในบางครั้ง แม้จะจัดเก็บเขตเวลาท้องถิ่นไว้ คุณก็ยังต้องการแสดงวันที่ในเขตเวลาหนึ่งๆ ตัวอย่างเช่น เวลาสำหรับกิจกรรมอาจเหมาะสมกว่าในเขตเวลาของผู้ใช้ปัจจุบัน หากเป็นเหตุการณ์เสมือน หรือในเขตเวลาที่จะเกิดขึ้นจริง หากไม่ใช่ ไม่ว่าในกรณีใด ควรพิจารณาวิธีแก้ปัญหาที่กำหนดไว้ล่วงหน้าสำหรับการจัดรูปแบบด้วยชื่อเขตเวลาที่ชัดเจน
การกำหนดค่าเซิร์ฟเวอร์และฐานข้อมูล
กำหนดค่าเซิร์ฟเวอร์และฐานข้อมูลของคุณเสมอเพื่อใช้เขตเวลา UTC (โปรดทราบว่า UTC และ GMT ไม่ใช่สิ่งเดียวกัน ตัวอย่างเช่น GMT อาจบ่งบอกถึงการเปลี่ยนไปใช้ BST ในช่วงฤดูร้อน ในขณะที่ UTC จะไม่เป็นเช่นนั้น)
เราได้เห็นแล้วว่าการแปลงโซนเวลาที่เจ็บปวดนั้นสามารถทำได้มากเพียงใด โดยเฉพาะอย่างยิ่งเมื่อไม่ได้ตั้งใจ การส่ง UTC DateTime และการกำหนดค่าเซิร์ฟเวอร์ของคุณให้อยู่ในเขตเวลา UTC เสมอจะทำให้ชีวิตของคุณง่ายขึ้น โค้ดแบ็คเอนด์ของคุณจะเรียบง่ายและสะอาดตากว่ามาก เนื่องจากไม่ต้องทำการแปลงโซนเวลาใดๆ DateTime data coming in from servers across the world can be compared and sorted effortlessly.
Code in the back end should be able to assume the time zone of the server to be UTC (but should still have a check in place to be sure). A simple configuration check saves having to think about and code for conversions every time new DateTime code is written.
It's Time for Better Date Handling
Date manipulation is a hard problem. The concepts behind the practical examples in this article apply beyond JavaScript, and are just the beginning when it comes to properly handling DateTime data and calculations. Plus, every helper library will come with its own set of nuances—which is even true of the eventual official standard support{target=”_blank”} for these types of operations.
The bottom line is: Use ISO on the back end, and leave the front end to format things properly for the user. Professional programmers will be aware of some of the nuances, and will (all the more decidedly) use well-supported DateTime libraries on both the back end and the front end. Built-in functions on the database side are another story, but hopefully this article gives enough background to make wiser decisions in that context, too.