16 คะแนน โดย GN⁺ 2024-08-25 | 5 ความคิดเห็น | แชร์ทาง WhatsApp
  • หนึ่งในการเปลี่ยนแปลงล่าสุดของ ECMAScript ที่น่าจับตามองที่สุดคือข้อเสนอ Temporal
    • API นี้สามารถใช้งานได้แล้วผ่าน polyfill ที่ทีม FullCalendar จัดให้
    • หนึ่งในข้อดีหลักของ API นี้คือ ในที่สุดก็มีอ็อบเจ็กต์แบบเนทีฟสำหรับแสดง "Zoned Date Time"

Zoned Date Time คืออะไร?

  • เมื่อต้องจัดการกับวันที่ในแบบที่มนุษย์ใช้กัน เรามักพูดถึงวันที่และเวลาโดยละเขตเวลาออกไป
  • แต่ใน JavaScript อ็อบเจ็กต์ Date จัดการเพียงตัวเลข ทำให้ความหมายดั้งเดิมของวันที่สูญหายไป
  • ตัวอย่างเช่น หากต้องการบันทึกเวลาที่ชำระเงินผ่านบัตร หลายคนอาจเขียนโค้ดแบบนี้
    const paymentDate = new Date('2024-07-20T10:30:00');  
    
  • เบราว์เซอร์จะคำนวณมิลลิวินาทีโดยอิงจากเขตเวลาของผู้ใช้ (CET) แต่ข้อมูลที่บันทึกไว้สามารถถูกตีความต่างกันไปตามเขตเวลา
  • นอกจากข้อเท็จจริงสำคัญมากที่ว่า วันที่ใน JavaScript ไม่ได้ยึดตาม UTC แต่เป็น POSIX ซึ่งไม่สนใจ leap second อย่างสิ้นเชิง ยังมีปัญหาที่ว่าเมื่อเหลือเพียงตัวเลข ความหมายเดิมของวันที่ก็หายไปด้วย
  • หลายคนคิดว่าถ้าทำงานด้วย UTC หรือส่งวันที่ในรูปแบบ ISO ก็จะปลอดภัย แต่จริง ๆ แล้วข้อมูลก็ยังสูญหายได้ จึงไม่ใช่คำตอบที่ถูกต้อง

UTC ไม่เพียงพอ

  • ต่อให้ทำงานด้วยรูปแบบ ISO เวลาจะแสดงวันที่ก็ยังขาดข้อมูลเขตเวลาอยู่ดี
  • ฟังก์ชันที่แปลง timestamp เป็นวันที่ที่มนุษย์อ่านได้ไม่เป็น injective (ฟังก์ชันหนึ่งต่อหนึ่ง)
  • ตัวอย่างเช่น หากคุณเดินทางจากมาดริดไปซิดนีย์แล้วกลับมา คุณอาจสับสนกับปัญหาเขตเวลาในรายการธุรกรรมของธนาคาร

แนะนำ Temporal API

  • Temporal API เพิ่มอ็อบเจ็กต์ Temporal.ZonedDateTime สำหรับแสดงวันที่และเวลาพร้อมเขตเวลา
  • มีการเสนอส่วนขยายของ RFC 3339 เพื่อกำหนดมาตรฐานสำหรับ serialize และ deserialize วันที่ในรูปแบบสตริง
  • 1996-12-19T16:39:57-08:00[America/Los_Angeles]
    • สตริงนี้หมายถึงวันที่ 19 ธันวาคม 1996 เวลา 16:39:57
    • offset จาก UTC คือ -08:00 (Pacific Standard Time, PST ซึ่งลอสแอนเจลิสใช้อยู่)
    • และระบุ standard time zone ที่เกี่ยวข้องเพิ่มเติม ("Pacific Standard Time") เพื่อให้แอปพลิเคชันที่รับรู้เขตเวลาสามารถนำไปพิจารณาได้
  • รองรับระบบปฏิทินหลากหลายแบบ (เช่น พุทธ, จีน, Dangi, เกรกอเรียน, อิสลาม, เปอร์เซีย, ญี่ปุ่น ฯลฯ)

การดำเนินการพื้นฐาน

การสร้างวันที่
  • Temporal API มีเครื่องมือทรงพลังสำหรับจัดการเขตเวลา
  • ตัวอย่างเช่น เมื่อสร้างอ็อบเจ็กต์ Temporal.ZonedDateTime ก็จะสะท้อนเขตเวลาได้อย่างถูกต้อง
    const zonedDateTime = Temporal.ZonedDateTime.from({  year: 2024,  month: 8,  day: 16,  hour: 12,  minute: 30,  second: 0,  timeZone: 'Europe/Madrid'});  
    
  • ด้วยเหตุนี้ จึงรักษาเวลาได้อย่างถูกต้องแม้มีการเปลี่ยนเขตเวลาหรือการปรับเวลาท้องถิ่นอย่าง DST
การเปรียบเทียบวันที่
  • อ็อบเจ็กต์ ZonedDateTime มีเมธอด compare สำหรับเปรียบเทียบ ZonedDateTime สองค่า
    const one = Temporal.ZonedDateTime.from('2020-11-01T01:45-07:00[America/Los_Angeles]');  
    const two = Temporal.ZonedDateTime.from('2020-11-01T01:15-08:00[America/Los_Angeles]');  
    Temporal.ZonedDateTime.compare(one, two);  // => -1  
    
ความสามารถในตัวที่มีประโยชน์
  • พร็อพเพอร์ตี hoursInDay จะคืนค่าจำนวนชั่วโมงจริงของวันนั้น
    Temporal.ZonedDateTime.from('2020-03-08T12:00-07:00[America/Los_Angeles]').hoursInDay;  // => 23  (วันเริ่ม DST)  
    
การแปลงเขตเวลา
  • สามารถเปลี่ยนเขตเวลาของ ZonedDateTime ได้ด้วยเมธอด withTimeZone
    zdt = Temporal.ZonedDateTime.from('1995-12-07T03:24:30+09:00[Asia/Tokyo]');  
    zdt.withTimeZone('Africa/Accra').toString(); // => '1995-12-06T18:24:30+00:00[Africa/Accra]'  
    
การคำนวณเลขคณิตพื้นฐาน
  • ใช้เมธอด .add เพื่อบวกหรือลบวันที่ตามกฎ DST ได้
    zdt = Temporal.ZonedDateTime.from('2020-03-08T00:00-08:00[America/Los_Angeles]');  
    laterDay = zdt.add({ days: 1 });  // => 2020-03-09T00:00:00-07:00[America/Los_Angeles]  
    
การคำนวณความแตกต่างระหว่างวันที่
  • เมธอด .until ใช้คำนวณความต่างระหว่างสองช่วงเวลา และคืนค่าเป็นอ็อบเจ็กต์ Temporal.Duration
    • ตัวอย่างเช่น สามารถใช้ในรูปแบบ zdt.until(other)

บทสรุป

  • Temporal API กำลังเปลี่ยนวิธีที่ JavaScript จัดการเรื่องเวลาอย่างมีนัยสำคัญ
  • บทความนี้อธิบายความแตกต่างระหว่างวันที่ที่มนุษย์อ่านเข้าใจได้กับวันที่แบบ UTC รวมถึงวิธีใช้ Temporal.ZonedDateTime เพื่อแสดงสิ่งเหล่านี้อย่างถูกต้อง
  • ในบทความถัดไปจะไปสำรวจอ็อบเจ็กต์ที่น่าสนใจอื่น ๆ เช่น Instant, PlainDate และ Duration

ความเห็นของ GN⁺

  • ปัญหาการจัดการวันและเวลาที่สร้างความลำบากให้กับนักพัฒนา JavaScript มานาน น่าจะได้รับการแก้ไขด้วย Temporal API
  • ความสามารถในการจัดการปัญหาเขตเวลาและ DST โดยอัตโนมัติ ทำให้มีประโยชน์มากในการพัฒนาแอปพลิเคชันระดับโลก
  • ประเด็นเรื่องความเข้ากันได้กับอ็อบเจ็กต์ Date เดิมและการย้ายระบบยังเป็นสิ่งที่ต้องพิจารณา
  • Temporal API ถูกออกแบบมาให้ชัดเจนและเข้าใจง่าย อีกทั้งยังโดดเด่นด้านการรองรับ internationalization เช่น การสนับสนุนระบบปฏิทินหลากหลายแบบ
  • คาดว่าการเปลี่ยนแปลงนี้จะช่วยเพิ่มประสิทธิภาพการทำงานของนักพัฒนา JavaScript ได้อย่างมาก

5 ความคิดเห็น

 
kyc1682 2024-08-26

ในที่สุด!

 
huiya 2024-08-26

สุดยอดเลย ตอนออกแบบบริการระดับโลก เรื่องวันที่ทำให้ปวดหัวตลอด
อยากลองใช้สิ่งนี้ดูสักครั้งครับ

 
jjpark78 2024-08-26

จริงสิ ในที่สุดก็ไม่ต้องใช้ moment หรือ dayjs แล้วเหรอ

 
GN⁺ 2024-08-25
ความเห็นจาก Hacker News
  • การจัดการวันที่และเวลาใน Javascript เป็นเรื่องที่ยากมาก

    • ไลบรารี Moment ทำให้เกิดปัญหามากมายจากการสับสนระหว่างวันที่กับเวลา
    • ไลบรารี Arrow ของ Python ก็ทำพลาดแบบเดียวกัน
    • ไลบรารี Chrono ของ Rust คาดเดาพฤติกรรมได้และมีข้อบกพร่องน้อยกว่า
    • Date และ Moment ของ JS ใช้งานยาก
  • คาดว่า API ใหม่จะช่วยแก้ปัญหา timezone ของ JS

    • มีปัญหาที่บางกรณีพาร์ส timezone เฉพาะได้สำเร็จ แต่บางกรณีกลับถือว่าเป็น UTC
    • เคยเจอความลำบากอย่างมากจากปัญหานี้ในที่ทำงานเก่า
  • ฟังก์ชันที่แปลง timestamp เป็นวันที่ในรูปแบบที่มนุษย์อ่านได้ไม่เป็น injective

    • มีการสับสนระหว่างแนวคิดของ injectivity กับ well-definedness
    • สำหรับ timestamp t ไม่มีวันที่ที่มนุษย์อ่านได้ x ที่เป็นเอกลักษณ์เสมอไป
  • มุกเกี่ยวกับเส้นโค้งความยากของการจัดการเวลา

    • มือใหม่ใช้แค่ UTC timestamp
    • ระดับกลางยืนยันว่าต้องเก็บ timezone แล้วค่อยแปลง
    • ระดับเซียนกลับไปใช้แค่ UTC timestamp อีกครั้ง
  • ถ้าใช้ตัวอย่างวันที่ในอนาคตมากกว่านี้ บทความน่าจะน่าเชื่อถือขึ้น

    • เวลาบันทึก timestamp ต้องการแค่ UTC กับตำแหน่งที่ตั้ง
    • ตัวอย่างเรื่องธนาคารเป็นเพียงปัญหา UX ไม่ใช่การสูญหายของข้อมูล
  • ผู้ใช้ที่กังวลเพราะยังไม่เข้าใจการจัดการเวลา

    • ขอคำแนะนำหนังสือหรือบทนำที่ดีเพื่อทำความเข้าใจปัญหาการจัดการเวลาในภาษาอย่าง Python
  • การมีมาตรฐาน datetime ที่ดีคือชนะไปแล้วครึ่งหนึ่ง

    • อีกครึ่งคือการทำให้มีการยอมรับใช้อย่างแพร่หลาย
    • เพื่อความเข้ากันได้กับระบบอื่น การแปลงเป็นสตริง ISO หรือ unix timestamp เป็นทางเลือกที่ปลอดภัย
  • สตริงวันที่แบบ ISO ควรเก็บข้อมูลที่ถูกต้องครบถ้วน

    • ตั้งคำถามว่าทำไม JavaScript หรือภาษาอื่นจึงต้องการโครงสร้างที่ฝังมาในตัว
    • Temporal และ Date ทำให้ปัญหาง่าย ๆ ซับซ้อนเกินไป
  • ถามว่าใน Postgres ควรจัดการปัญหานี้อย่างไร

  • ยังมีหลักฐานไม่เพียงพอว่า Temporal จะถูกนำมาใช้จริง

    • เช่นเดียวกับข้อเสนอ JS ที่ดูมีอนาคตหลายตัว มันถูกพูดถึงมาเป็นเวลานานโดยยังไม่มีความคืบหน้าชัดเจน