- มาตรฐานใหม่ Temporal API ที่มาแทนข้อจำกัดของ อ็อบเจ็กต์ Date ใน JavaScript แบบถึงราก ได้มาถึง ECMAScript Stage 4 หลังพัฒนามานาน 9 ปี
- Temporal มอบ ชนิดข้อมูลแบบ immutable, การรองรับเขตเวลาและปฏิทินอย่างชัดเจน, และ ความละเอียดระดับนาโนวินาที ช่วยขจัดความกำกวมและข้อผิดพลาดของ Date เดิม
- องค์กรหลากหลายแห่งอย่าง Bloomberg, Igalia, Microsoft, Google, Mozilla ร่วมมือกันออกแบบสเปกและพัฒนา โดยใช้ ไลบรารีส่วนกลาง
temporal_rs ที่สร้างด้วย Rust เพื่อให้หลายเอนจินทำงานร่วมกันได้
- Temporal รองรับการคำนวณเวลาและการจัดการปฏิทินสากลได้อย่างแม่นยำผ่านชนิดข้อมูลที่แยกละเอียด เช่น ZonedDateTime, Instant, PlainDate/Time, Duration
- มาตรฐานนี้ซึ่งแก้ปัญหาที่สะสมมากว่า 30 ปี ถูกยกให้เป็น ตัวอย่างความสำเร็จของการทำงานร่วมกันและนวัตกรรมแบบเปิดในระบบนิเวศ JavaScript
ปัญหาการจัดการเวลาใน JavaScript และการมาของ Temporal
- เดิมที อ็อบเจ็กต์ Date เป็นการพอร์ต Date จาก Java ปี 1995 มาแทบตรง ๆ และตลอดหลายสิบปีที่ผ่านมาได้กลายเป็นต้นตอของบั๊กจากปัญหาอย่าง การเปลี่ยนค่าได้, การคำนวณเดือนที่ไม่สอดคล้องกัน, การพาร์สที่กำกวม
- ตัวอย่าง: เมื่อใช้
setMonth อาจเกิดข้อผิดพลาดในการคำนวณช่วงสิ้นเดือน หรือเมื่อพาร์สสตริงคล้าย ISO ผลลัพธ์อาจต่างกันในแต่ละเบราว์เซอร์
- หลังปี 2010 เมื่อเว็บแอปพลิเคชันมีความซับซ้อนขึ้น ข้อจำกัดของ Date ก็ยิ่งชัดเจนขึ้น
- นักพัฒนาจึงใช้ไลบรารีภายนอกอย่าง Moment.js เพื่ออุดช่องว่าง แต่ก็แลกมากับ ขนาดบันเดิลที่ใหญ่ขึ้นและภาระในการดูแลรักษา
- ในปี 2017 Maggie Johnson-Pint ได้ยื่น ข้อเสนอ Temporal ต่อ TC39 และเป็นจุดเริ่มต้นของการหารือเพื่อทำให้เป็นมาตรฐาน
ความร่วมมือระหว่าง TC39 และภาคอุตสาหกรรม
- Temporal เริ่มต้นที่ Stage 1 ในปี 2018 และใช้เวลา 9 ปีจนมาถึง Stage 4 (การเป็นมาตรฐาน)
- Bloomberg เข้ามามีส่วนร่วมอย่างจริงจังเพื่อแก้ปัญหาเรื่องเขตเวลาและความละเอียดในสภาพแวดล้อม JavaScript ขนาดใหญ่
- ความต้องการหลัก: เขตเวลาที่ผู้ใช้กำหนดเองได้, ความแม่นยำของเขตเวลาเชิงประวัติศาสตร์ตาม IANA, และความละเอียดระดับนาโนวินาที
- มีการร่วมมือกับ Igalia, Microsoft, Google, Mozilla และอื่น ๆ ในการออกแบบสเปกและพัฒนา
- วิศวกรหลายคน เช่น Philipp Dunkel, Ujjwal Sharma, Philip Chimento, Shane Carr, Justin Grant เข้าร่วมในฐานะแชมเปียนของข้อเสนอ
ชนิดข้อมูลและความสามารถหลักของ Temporal
- Temporal.ZonedDateTime: การแทนค่าช่วงเวลาที่เป็น immutable พร้อมเขตเวลา ปฏิทิน และการชดเชย DST อย่างชัดเจน
- ตัวอย่าง: หาก
01:30 ไม่มีอยู่จริงในช่วงเปลี่ยน DST ของลอนดอน ระบบจะปรับเป็น 02:30 โดยอัตโนมัติ
- Temporal.Instant: การแทนค่าจุดเวลาแบบสัมบูรณ์ที่ไม่ผูกกับเขตเวลาหรือปฏิทิน และรองรับ ความละเอียดระดับนาโนวินาที
- สามารถแปลงจุดเวลาเดียวกันไปยังหลายเขตเวลาได้
- PlainDate / PlainTime / PlainDateTime / PlainYearMonth / PlainMonthDay: ชนิดข้อมูลแบบ “นาฬิกาบนผนัง” ที่ไม่มีเขตเวลา
- เหมาะกับการแสดงหรือคำนวณวันที่และเวลาแบบทั่วไป
- Temporal.Duration: ใช้แทนช่วงเวลา และแปลงหน่วยได้หลากหลาย (
total({ unit: "second" }))
- การรองรับปฏิทิน: คำนวณกับปฏิทินที่ไม่ใช่เกรกอเรียน เช่น ปฏิทินฮีบรู ได้อย่างถูกต้อง
กระบวนการพัฒนาและการทำให้เป็นมาตรฐาน
- Temporal เป็น การเพิ่มสเปกครั้งใหญ่ที่สุดครั้งหนึ่งในประวัติศาสตร์ ECMAScript และมี เคสทดสอบราว 4,500 รายการ
- มีการพัฒนา อิมพลีเมนเทชันส่วนกลาง
temporal_rs ที่สร้างด้วย Rust ซึ่ง เอนจินหลายตัวอย่าง V8 และ Boa ใช้ร่วมกัน
- ข้อดี: ลดอุปสรรคในการเริ่มต้นพัฒนา, ดูแลรักษาระยะยาวได้ง่ายขึ้น, และยกระดับคุณภาพของโค้ด
- ตลอดปี 2024~2025
temporal_rs ผ่านการทดสอบได้ครบ 100% และถูกมองเป็นกรณีศึกษาความสำเร็จของความร่วมมือข้ามเอนจิน
สถานะการรองรับและโจทย์ต่อจากนี้
- ปัจจุบัน Temporal รองรับแล้วใน Firefox 139, Chrome/Edge 144, TypeScript 6.0 Beta
- ส่วน Safari ยังอยู่ในขั้นเทคโนโลยีพรีวิว และ Node.js 26 มีกำหนดรองรับในอนาคต
- โจทย์สำคัญถัดไปคือ การผสานเข้ากับ Web API
- ตัวอย่าง: รองรับชนิด
Temporal ในองค์ประกอบฟอร์มอย่าง <input type="date">
- มีการพิจารณาความเป็นไปได้ในการใช้แทน
DOMHighResTimeStamp (พร้อมยกตัวอย่างการใช้ Temporal.Now.instant())
ผลลัพธ์ของความร่วมมือและนวัตกรรมแบบเปิด
- Temporal เป็นมาตรฐานที่เสร็จสมบูรณ์จาก ความร่วมมือข้ามหลายองค์กรตลอด 9 ปี โดยมีผู้เล่นอย่าง
- Microsoft, Google, Mozilla, Bloomberg, Igalia, Boa เข้าร่วม
temporal_rs เป็นตัวอย่างความสำเร็จของ โมเดลโครงสร้างพื้นฐานแบบใช้ร่วมกัน โดย
- พิสูจน์ให้เห็นถึงการลดต้นทุนจากการพัฒนาซ้ำซ้อน เพิ่มความสอดคล้อง และเร่งนวัตกรรม
- Temporal ไม่ได้เป็นเพียงการปรับปรุง API แต่ยังเป็น หลักฐานของความร่วมมือที่ทำให้ชุมชน JavaScript แก้หนี้เทคนิคระยะยาวได้สำเร็จ
- หลังผ่านไป 30 ปี ในที่สุด JavaScript ก็มี API สำหรับวันที่และเวลาที่ทันสมัย
7 ความคิดเห็น
ความซับซ้อนของการคำนวณเวลาเกิดจากหลายอย่างที่มากกว่าปัญหาเรื่องรูปแบบ ไม่ว่าจะเป็นปรัชญาของมนุษยชาติ ความแม่นยำทางดาราศาสตร์ และวัฒนธรรม การคำนวณเองนั้นใช้แค่
longก็ง่ายอยู่แล้ว เส้นเวลาทางประวัติศาสตร์มีช่วงพิเศษที่ 1 + 1 ไม่ได้เท่ากับ 2 ถูกกำหนดไว้ในหลายแห่ง และส่วนใหญ่ก็มาจากปฏิทินแบบอี้จิงที่เปลี่ยนไปตามตำแหน่ง เช่น มุมของดวงอาทิตย์กับพื้นผิวโลก ในกรณีแบบนี้ ไม่ว่าอย่างไรก็ตาม ปฏิทินสุริยคติ-จันทรคติของเกาหลีเองก็ไม่เคยถูกนำมาถกเถียงด้วยซ้ำและสิ่งนั้น ถูกกำหนด โดยสถาบันวิจัยดาราศาสตร์เกาหลี
ในที่สุด! สนุกจัง!!
ในที่สุด!!
ZonedDateTime...? อย่าบอกนะว่าเธอจะ...!
ในที่สุด
จาก
time.hของ C ->java.util.Dateของ Java ->Dateของ jsจาก joda-time ของ Java -> JSR 310 ->
java.time-> moment.js ->
Temporalของ jsดูเหมือนว่าจะเป็นลำดับการพัฒนาแบบนี้นะ
ความคิดเห็นบน Hacker News
การแยกความต่างระหว่าง instant กับ datetime แบบอิงปฏิทินช่วยป้องกันความผิดพลาดที่มักเกิดกับ Date ได้เกือบหมด
ถึงจะดูยืดเยื้อไปบ้าง แต่ก็ยังดีกว่าถูกเรียกไปแก้บั๊ก DSTตอนตี 3 มาก
ประเด็นที่เริ่มขึ้นในปี 2012 สุดท้ายก็ได้ทางแก้เข้าไปอยู่ใน standard library
ดูการถกเถียงที่เกี่ยวข้องได้ในกระทู้ Google Groups นี้
เมื่อก่อนผมใช้ ciso8601 แต่พอเข้า standard แล้ว ทุกอย่างก็ง่ายและเสถียรกว่ามาก
โดยเฉพาะเมื่อรู้ว่าเขาทำทั้งหมดนี้คนเดียวในฐานะอาสาสมัคร
ผมแชร์โค้ดระหว่าง client กับ server เลยพยายามแยกข้อมูลออกจาก logic อย่างเข้มงวด
ผมอยากเก็บข้อมูลทั้งหมดให้เป็น pure JSON เพื่อให้ serialize/deserialize ได้ง่าย แต่ object ของ Temporal เป็น class instance ที่มี property แบบฟังก์ชัน เลยใช้งานลำบาก
ผมคิดว่าวิธีแบบ date-fns ที่เอา pure function ไปใช้กับ object ที่เป็นข้อมูลล้วนจะดีกว่า
นักพัฒนาต้องประกอบ object ที่ถูกต้องกลับขึ้นมาเองจากสตริง ISO
ถ้าทำให้เป็นอัตโนมัติจะมีความเสี่ยงในการจัดการ type ที่ผิด
ตัวอย่าง Temporal.Instant reviver ในเอกสาร น่าจะช่วยได้
แต่ผมคิดว่าทีม Temporal ตัดสินใจถูกแล้ว สำหรับ logic เรื่องวันและเวลา type safety สำคัญกว่าวิธีแบบข้อมูล+ฟังก์ชันธรรมดา
การผูก operation ไว้กับ object ช่วยป้องกันไม่ให้ PlainDate ถูกเผลอจัดการเหมือน ZonedDateTime
ในที่อย่าง tRPC แค่เพิ่ม layer บางๆ ที่แปลงด้วย Temporal.from() และ toString() ตรงขอบเขตก็พอแล้ว
จะน่ารำคาญอยู่บ้าง แต่ก็ดีกว่ายอมเสีย type safety ไป
Date.toJSON มีอยู่ แต่ตอน parse JSON ก็ยังต้องแปลงสตริงกลับเป็น Date เอง
Temporal ก็เหมือนกัน และ date-fns เองสุดท้ายก็จัดการกับinstance ของ Date แบบเนทีฟ
.toString()และTemporal.from()เช่นเดียวกับ Date ควรจัดการแบบ explicit ลักษณะนี้มากกว่า
ขอแสดงความยินดีกับchampionทุกคนที่ทุ่มเทมาอย่างยาวนาน
ช่วงหลายปีที่ผ่านมา ผมสนุกมากกับการทำงานบน temporal_rs
เพราะข้อเสนอแบบค่อนข้างพลิกแนวทางเดิมของ JavaScript ออกมาในปี 2018 เลยสงสัยว่าแนวทางของ Java อาจมีอิทธิพลอยู่บ้างไหม
TC39 อ้างอิงแบบอย่างจากภาษาอื่น แต่ก็ตกผลึกเป็นฉันทามติในทิศทางที่เหมาะกับ JavaScript
ผมคิดว่า API ชุดนี้คือ implementation ที่สมบูรณ์ที่สุดที่ผู้เชี่ยวชาญ JS ออกแบบร่วมกันตลอด 9 ปี
ดูเพิ่มเติมได้ในกระทู้ HN นี้
เพราะ util.Date ของ Java เองก็แทบจะเป็นพอร์ตของ API
time.hใน Cอยู่แล้วตอนนี้ Safari ดูเหมือนจะกลายเป็นทายาททางจิตวิญญาณของ IEไปแล้ว
ปัญหาของ IE ไม่ใช่ความช้า แต่คือการหยุดนิ่งทั้งที่ครองตลาด
ตอนนี้ Chrome ต่างหากที่อยู่ในตำแหน่งจักรวรรดิ และยิ่งทำให้ Safari กับ Firefox จำเป็นมากขึ้น
ปัญหาจริงคือการที่เว็บที่ใช้ได้เฉพาะบน Chrome เพิ่มขึ้นเรื่อยๆ