เวลาที่เชื่อไม่ได้ — ครึ่งชั่วโมงที่ไม่มีอยู่จริง และภาษาเดียวที่บอกว่ามันไม่มี
คำถามของคอร์ส และคำตอบที่วัดได้
หัวข้อที่มีชื่อว่า “คำถามของคอร์ส และคำตอบที่วัดได้”คำถามเดียว คือเวลาที่ถึงปลายทางยังชี้จุดเดิมบนเส้นเวลาหรือไม่ · คำตอบวัดเป็นสตริงของเวลาล้วน
คำถามคือ เวลาของออเดอร์ที่เดินผ่านระบบ ยังชี้จุดเดิมบนเส้นเวลาอยู่หรือเปล่า
ประเทศไทยใช้ +07:00 ตลอดปี แต่ระบบไทยคุยกับระบบในโซนที่มี DST และ Bangkok เองก็เคยใช้
offset อื่น คอร์สนี้จึงเป็นปัญหาของคนไทยด้วย ไม่ใช่แค่ของคนที่อยู่ในโซนที่มี DST
ที่ America/New_York วันที่ 2026-03-08 offset เปลี่ยนจาก -05:00 เป็น -04:00 และนาฬิกากระโดดข้ามไปหนึ่งช่วง
เวลา 02:30 ของวันนั้นจึงไม่มีอยู่จริง แล้วห้าภาษาก็ยังตอบมันกลับมา:
- Java
ZonedDateTime.of(...)คืน2026-03-08T03:30-04:00[America/New_York] - Node ที่
TZ=America/New_Yorkคืน03:30:00 GMT-0400 - Python เก็บ
2026-03-08T02:30:00-05:00ไว้ตามเดิม ทั้งที่เวลานี้ไม่มีอยู่ - Go คืนเวลาค่าหนึ่งออกมา แต่เอกสารไม่รับปากว่าจะเป็นค่าไหน ดูหัวข้อถัดไป
- Rust คืน
LocalResult::Noneและเป็นภาษาเดียวที่บอกว่าเวลานี้ไม่มีอยู่
ค่าทั้งห้าวัดบน darwin/arm64 และห้าภาษาใช้ tzdata สามรุ่น: Java กับ Node 2026b
· Go กับ Python อ่าน 2026c จากระบบ · chrono-tz ฝัง 2025b ไว้ในตัว
ธีสิสของคอร์สจึงเป็นประโยคเดียว คือ เวลาท้องถิ่นค่าหนึ่งไม่ได้ระบุจุดเดียวบนเส้นเวลา มันอาจไม่มีจุดเลย มีสองจุด หรือมีจุดเดียวที่แต่ละภาษาเลือกต่างกัน และในทรงที่ probe วัด มีภาษาเดียวจากห้าภาษาที่บอกคุณ
ภาษาที่ไม่รับปาก
หัวข้อที่มีชื่อว่า “ภาษาที่ไม่รับปาก”Go เลือกฝั่งหนึ่งของการเปลี่ยน DST ให้ แต่เอกสารของมันบอกตรงๆ ว่าไม่รับปากว่าฝั่งไหน
go doc time.Date เขียนไว้ว่า
“Date returns a time that is correct in one of the two zones involved in the transition, but it does not guarantee which.”
ค่าที่ Go คืนให้ในเวลาที่ไม่มีอยู่จริงและในเวลาที่มีสองครั้ง จึงเป็นค่าของเครื่องที่วัดเท่านั้น คอร์สนี้พิมพ์มันพร้อมชื่อเครื่องเสมอ และไม่เคยใช้มันเป็นคำตอบของ Go ทั้งภาษา
หกจุดที่เวลาเปลี่ยน
หัวข้อที่มีชื่อว่า “หกจุดที่เวลาเปลี่ยน”หกหัวข้อนี้คือโครงของแปดบท และทุกค่าข้างล่างเป็นค่าที่วัดมาแล้ว
เวลาท้องถิ่นที่ไม่มีอยู่จริง
หัวข้อที่มีชื่อว่า “เวลาท้องถิ่นที่ไม่มีอยู่จริง”02:30 ของวันที่ 2026-03-08 ที่ America/New_York ไม่มีอยู่จริง Java กับ Node เลื่อนไปข้างหน้า
Python เก็บไว้ตามเดิม และ Rust ตอบ LocalResult::None
วันที่ที่ไม่มีเวลา
หัวข้อที่มีชื่อว่า “วันที่ที่ไม่มีเวลา”วันส่งของ 2026-10-02 ของร้านใน Bangkok คือ 2026-10-01T17:00:00Z ใน UTC ซึ่งเป็นคนละวัน
ที่ TZ=America/New_York สตริงสองตัวที่ต่างกันแค่ T00:00 ทำให้ Node อ่านคนละโซน:
new Date("2026-10-02")ได้2026-10-02T00:00:00.000Zคืออ่านเป็น UTCnew Date("2026-10-02T00:00")ได้2026-10-02T04:00:00.000Zคืออ่านเป็นเวลาท้องถิ่น
offset ที่มากับสาย
หัวข้อที่มีชื่อว่า “offset ที่มากับสาย”parse "2026-03-07T12:00-05:00" แล้วบวกหนึ่งวัน Java Go Python และ Rust ได้ 12:00-05:00
ตรงกันทั้งสี่ภาษา ส่วนค่าที่บวกบนโซน America/New_York ได้ 12:00-04:00 เพราะ offset ไม่เดินตาม DST
Node ทิ้ง offset ตั้งแต่ parse และให้คำตอบตาม TZ ของเครื่องที่รัน:
TZ=America/New_Yorkได้2026-03-08T16:00:00.000ZTZ=Asia/Bangkokได้2026-03-08T17:00:00.000Z
เมื่อเวลาของออเดอร์ข้าม JSON Go ส่ง "2026-10-02T09:00:00+07:00" ซึ่งเหลือแค่ offset
ส่วน json.dumps ของ Python โยน TypeError · ในภาษาที่วัด ไม่มีภาษาไหนส่งชื่อโซน Asia/Bangkok ไปบนสาย
เวลาท้องถิ่นที่มีสองครั้ง
หัวข้อที่มีชื่อว่า “เวลาท้องถิ่นที่มีสองครั้ง”01:30 ของวันที่ 2026-11-01 ที่ America/New_York เกิดขึ้นสองครั้ง Rust คืน
LocalResult::Ambiguous(01:30-04:00, 01:30-05:00) ให้คุณเลือกเอง ส่วน Python ได้ -04:00
เมื่อ fold=0 และได้ -05:00 เมื่อ fold=1
การบวกข้ามคืนที่เปลี่ยน DST
หัวข้อที่มีชื่อว่า “การบวกข้ามคืนที่เปลี่ยน DST”เริ่มที่ 2026-03-07 12:00 ใน America/New_York แล้วบวกสองแบบ:
- Java
plusDays(1)ได้12:00-04:00ส่วนplus(Duration.ofHours(24))ได้13:00-04:00 - Python
timedelta(days=1)ได้12:00-04:00และtimedelta(hours=24)ก็ได้12:00-04:00· Python ตอบสองคำถามเหมือนกัน
กฎของโซนที่เปลี่ยนตามปี
หัวข้อที่มีชื่อว่า “กฎของโซนที่เปลี่ยนตามปี”Bangkok ในปี 1900 ใช้ +06:42:04 ไม่ใช่ +07:00 · Java กับ Python พิมพ์ค่านี้ครบ
ส่วน time.RFC3339 ของ Go กับ to_rfc3339() ของ chrono พิมพ์ +06:42 เพราะ offset ของ RFC 3339
ไม่มีช่องวินาที · ค่าที่พิมพ์ออกมาจึงห่างจากเวลาจริงสี่วินาที
สิ่งที่คอร์สนี้จงใจไม่ทำ
หัวข้อที่มีชื่อว่า “สิ่งที่คอร์สนี้จงใจไม่ทำ”ประกาศไว้ตรงนี้ เพื่อไม่ให้ใครอ่านจบแล้วเชื่อว่าได้ของที่คอร์สนี้ไม่ได้ให้
- ไม่วัดความเร็ว ทั้งคอร์สไม่มีหน่วยเวลาที่วัดจากการรันสักตัว หน่วยคือสตริงของเวลา offset ที่อ่านจาก API ชื่อ class ของ exception และ variant ของ enum
- ไม่สอนการแสดงปี ปฏิทินพุทธกับ
th-THเป็นของบทความ ภาษาไทยทำให้ code พังคนละชั้นกันสี่ชั้น คอร์สนี้เป็นเจ้าของจุดบนเส้นเวลา - ไม่แตะนาฬิกา monotonic คอร์สนี้ไม่วัดเวลาที่ผ่านไปของการรัน
- ไม่แตะ
timestamptzของ PostgreSQL มันต้องใช้ Docker ซึ่งจะดัน probe ทั้งตัวออกไปนอก CI · ตัดออกตั้งแต่ตอนออกแบบ - ไม่สอน
Temporalของ JavaScript Node 24 ที่ CI ใช้ยังไม่มีมันเป็นค่าตั้งต้น - ไม่แตะ leap second
ก่อนเริ่ม — สิ่งที่ควรมีมาก่อน
หัวข้อที่มีชื่อว่า “ก่อนเริ่ม — สิ่งที่ควรมีมาก่อน”อ่านห้าภาษาออกพอตามตัวอย่างสั้นๆ ได้ก็พอ ไม่ต้องรู้เรื่อง DST มาก่อน
- อ่าน Rust Go และ Java ออก ระดับที่ตามตัวอย่างสิบบรรทัดได้ก็พอ ถ้ายังไม่ถึงตรงนั้น เริ่มที่ Rust จากศูนย์ Go จากศูนย์ หรือ Java จากศูนย์ ก่อน
- ไม่ต้องรู้จัก DST มาก่อน บทที่ 1 อธิบายมันตอนที่มันโผล่ครั้งแรก
- ควรเคยอ่านคอร์ส จำนวนเต็มที่เชื่อไม่ได้ คอร์สนี้ใช้วิธีวัดแบบเดียวกัน กับห้าภาษาเดียวกัน แต่เดินตามเวลาของออเดอร์แทนยอดออเดอร์
- ต้องมี Rust Go JDK 25 Node และ Python 3 เพราะทุกข้ออ้างมาจาก probe ที่คุณรันเองได้ · ไม่ต้องมี Docker
เส้นทางการเรียน
หัวข้อที่มีชื่อว่า “เส้นทางการเรียน”แผนผังนี้เติมขึ้นเองเมื่อบทเรียนถูกเพิ่มเข้ามา