ข้าม​ไป​ยัง​เนื้อหา

โซน​ที่​ข้าม​สาย​ไม่​ได้

ออ​เด​อร์ A-1042 ถูก​สั่ง​ที่​ร้าน​ใน Bangkok เวลา 09:00 ของ​วัน​ที่ 2026-10-02 ตาม​นาฬิกา​ของ​ร้าน ซึ่ง​อยู่​ใน​โซน Asia/Bangkok

เวลา​นี้​ต้อง​เดิน​ทาง​ต่อ service ที่​ตัด​รอบ​ต้อง​รู้​มัน ใบ​เสร็จ​ต้อง​พิมพ์​มัน และ​ระบบ​จัด​รถ​ต้อง​คำนวณ​จาก​มัน ทุก​ทาง​ผ่าน JSON

คำถาม​ของ​บท​นี้​คือ เวลา​ขอ​งอ​อเด​อร์​ข้าม JSON ไป​แล้ว​เหลือ​อะไร ใน​สตริง​บน​สาย​ทุก​ตัว​ที่ probe ตรวจ สิ่ง​ที่​เหลือ​คือ offset หรือ UTC และ​ไม่มี​ชื่อ​โซน​ติด​ไป​ด้วย​เลย

📦 orderctl — ของ​ชิ้น​เดียวกัน​กับ​คอร์ส​ภาษา​อื่น​ใน​เสา​นี้

orderctl คือ​เครื่อง​มือ​ประมวล​ผล​ออ​เด​อร์​ที่​คอร์ส​ภาษา​ใน​เสา​นี้​สร้าง​ซ้ำ​ที​ละ​ภาษา repo ตัวอย่าง กำลัง​จัด​ทำ

ระหว่าง​นี้​ทุก​ค่า​ใน​บท​นี้​รัน​เอง​ได้​ด้วย npm run verify:time-semantics ซึ่ง​เรียก python3 scripts/time-semantics/probe.py · ไม่​ต้อง​มี Docker แต่​การ​รัน​ครั้ง​แรก ต้อง​ต่อ​เน็ต​เพื่อ​ดึง chrono กับ chrono-tz จาก crates.io

JSON ไม่มี​ชนิด​ของ​เวลา ใน​ทรง​ที่ probe วัด ทุก​ภาษา​ที่​เขียน​ได้​จึง​เขียน​เวลา​เป็น​สตริง และ RFC 3339 ที่​สตริง​บน​สาย​เหล่า​นั้น​ใช้​ไม่มี​ช่อง​ให้​ชื่อ​โซน

JSON มี​ชนิด​ของ​ค่า​อยู่​ไม่​กี่​ชนิด และ​ไม่มี​ชนิด​ไหน​เป็น​เวลา ภาษา​ที่​ส่ง​เวลา​ข้าม JSON จึง​ต้อง​ตัดสิน​ใจ​เอง​ว่า จะ​เขียน​เวลา​นั้น​เป็น​ค่า​แบบ​ไหน ใน​ทรง​ที่ probe วัด ค่า​นั้น​เป็น​สตริง​ทุก​ตัว

สตริง​บน​สาย​ที่ probe วัด​ใน​บท​นี้​อ่าน​ได้​ตาม grammar ของ RFC 3339RFC 3339รูป​แบบ​สตริง​ของ​เวลา​ที่​ใช้บน​สาย​เป็น​ส่วน​ใหญ่ และ​เป็น profile ที่​แคบ​กว่า​ของ ISO 8601 · ช่อง offset ของ​มัน​มี​แค่​ชั่วโมง​กับ​นาที offset ที่​มี​เศษ​วินาที​จึง​เขียน​ลง​ไป​ตรงๆ ไม่​ได้ (รูป​แบบ​สตริง​ของ​เวลา​บน​อินเทอร์เน็ต) ใน​รูป​แบบ​นั้น ส่วน​ที่​บอก​ว่า​เวลา​นี้​เป็น​ของ​ที่ไหน​มี​แค่​ช่อง​เดียว คือ offset และ grammar ของ RFC 3339 เขียน​ช่อง​นี้​ไว้​ว่า

time-numoffset = ("+" / "-") time-hour ":" time-minute
time-offset = "Z" / time-numoffset

UTC offsetUTC offsetระยะ​ห่าง​จาก UTC ณ จุด​หนึ่ง​บน​เส้น​เวลา · offset ถูก​ต้อง​เฉพาะ​จุด​นั้น​จุด​เดียว มัน​ไม่รู้​ว่า​วัน​ถัด​ไป​โซน​เดียวกัน​จะ​ใช้ offset อะไร การ​บวก​เวลา​บน offset จึง​ไม่​เดิน​ตาม DST (ระยะ​ห่าง​จาก UTC) อย่าง +07:00 ถูก​ต้อง​เฉพาะ​จุด​เดียว​บน​เส้น​เวลา มัน​ไม่รู้​ว่า​วัน​พรุ่ง​นี้​หรือ​ปี 1900 โซน​เดียวกัน​ใช้ offset อะไร คน​ที่​รู้​คือ​ชื่อ​โซน และ grammar ข้าง​บน​ไม่มี​ที่​ให้​ชื่อ​โซน​เลย

RFC 3339 เลือก offset ที่​เป็น​ตัวเลข หัวข้อ 4.2 เขียน​เหตุผล​ไว้​ว่า “Attempts to label local offsets with alphabetic strings have resulted in poor interoperability in the past” แล้ว​สรุป​ว่า RFC2822 “has made numeric offsets mandatory” ป้าย​ใน​ประโยค​นี้​คือ​ป้าย​ของ offset ไม่ใช่​ชื่อ​โซน​อย่าง Asia/Bangkok

ชื่อ​โซน​ที่​ต้อง​เดิน​ทาง​ไป​กับ​เวลา​จึง​เป็น​งาน​ของ​ผู้​ส่ง ไม่ใช่​ของ​รูป​แบบ​สตริง บท​นี้​เรียก​มัน​ว่า zone on the wirezone on the wireชื่อ​โซน​ที่​ต้อง​เดิน​ทาง​ไป​กับ​เวลา​เมื่อ​ส่ง​ข้าม​ระบบ · JSON ไม่มี​ชนิด​ของ​เวลา ถ้า​ไม่​ส่ง​ชื่อ​โซน​ไป​ด้วย​อย่าง​ตั้งใจ ปลาย​ทาง​ได้​แค่ offset หรือ UTC และ​คำนวณ​ต่อตาม​กฎ​ของ​โซน​เดิม​ไม่​ได้ (ชื่อ​โซน​ที่​ส่ง​ไป​กับ​เวลา) ถ้า​ไม่มี​ใคร​ส่ง​มัน​อย่าง​ตั้งใจ ปลาย​ทาง​ก็​ไม่​ได้​มัน

flowchart LR
  A["เวลาของออเดอร์ · 09:00 ที่ Asia/Bangkok"] --> B{"เขียนเป็นสตริงก่อนขึ้นสาย"}
  B -->|"เก็บ offset"| C["2026-10-02T09:00:00+07:00"]
  B -->|"แปลงไป UTC"| D["2026-10-02T02:00:00.000Z · Node ที่ TZ=Asia/Bangkok"]
  B -->|"ไม่ยอมเขียน"| E["TypeError"]
  C --> F["ปลายทางได้ +07:00 แต่ไม่ได้ชื่อโซน"]
  D --> G["ปลายทางได้ instant แต่ไม่ได้ทั้ง offset และชื่อโซน"]

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

แต่ละ​ภาษา​ได้​รับ 09:00 ของ 2026-10-02 ที่ Asia/Bangkok เหมือน​กัน แล้ว​เขียน​ลง​สาย​คนละ​แบบ

ทุก​การ​เรียก​ข้าง​ล่าง​ตัด​มา​จาก runner ของ probe ใน scripts/time-semantics/runners/ และ​ค่า​ใน​คอม​เมน​ต์ คือ​ค่าที่ probe วัด​ได้ ทรง​นี้ probe วัด​สี่​ภาษา คือ Go, Node, Python และ Java

Rust ไม่​อยู่​ใน​ทรง​นี้ เพราะ crate ของ probe ตั้ง chrono กับ chrono-tz ไว้​ที่ features = ["std"] และ​ไม่มี crate สำหรับ JSON ทรง​นี้​จึง​ไม่มี​ค่า​ของ Rust ให้​พิมพ์

scripts/time-semantics/runners/go/main.go (เฉพาะ​ทรง E)
bkk, err := time.LoadLocation("Asia/Bangkok")
// ...
b, err := json.Marshal(time.Date(2026, 10, 2, 9, 0, 0, 0, bkk))
string(b) // "2026-10-02T09:00:00+07:00"

เอกสาร​ของ Time.MarshalJSON เขียน​ว่า “The time is a quoted string in the RFC 3339 format with sub-second precision.” สตริง​ที่​ได้​จึง​มี 09:00 และ +07:00 ครบ ปลาย​ทาง​รู้​ว่า​ร้าน​เห็น​นาฬิกา​บอก​เวลา​เท่าไร

แต่​คำ​ว่า Asia/Bangkok ไม่​อยู่​ใน​สตริง​นี้ เพราะ grammar ของ RFC 3339 ไม่มี​ที่​ให้​มัน location ที่ bkk ถือ​ไว้ หาย​ไป​ตอน json.Marshal เหลือ​แค่ offset ของ​จุด​เดียว​นี้

scripts/time-semantics/runners/shapes.mjs (เฉพาะ​ทรง E)
// เดือนของ Date เริ่มที่ 0 · เลข 9 คือเดือนตุลาคม
JSON.stringify({ t: new Date(2026, 9, 2, 9, 0) });

Date สร้าง​เวลา​จาก​วัน​ที่​และ​ชั่วโมง​ได้​แค่​ใน​โซน​ของ process ซึ่ง​มา​จาก TZ probe จึง​รัน file เดียวกัน​สอง​ครั้ง ต่าง​กัน​ที่ TZ อย่าง​เดียว

TZJSON.stringify(...)
America/New_York{"t":"2026-10-02T13:00:00.000Z"}
Asia/Bangkok{"t":"2026-10-02T02:00:00.000Z"}

ทั้ง​สอง​แถว​ลงท้าย​ด้วย Z ไม่มี​แถว​ไหน​เก็บ offset ไว้ MDN อธิบาย​ค่าที่ toJSON() คืน​ว่า “A string representing the given date in the date time string format according to universal time” และ​เขียน​ว่า “The toJSON() method is automatically called by JSON.stringify() when a Date object is stringified.”

แถว​ที่ TZ=Asia/Bangkok คือ​เวลา​ขอ​งอ​อเด​อร์​ที่​ถูก​ต้อง แต่​ตัวเลข 09 ไม่​อยู่​ใน​สตริง​นั้น​เลย ปลาย​ทาง​ที่​อยาก​พิมพ์ 09:00 บน​ใบ​เสร็จ​ต้อง​รู้​ชื่อ​โซน​จาก​ที่​อื่น

แถว​ที่ TZ=America/New_York เป็น​คนละ​จุด​ตั้งแต่​ก่อน​ขึ้น​สาย มัน​คือ 09:00 ของ New York ไม่ใช่​ของ Bangkok ปัญหา​นี้​เป็น​เรื่อง​เดียว​กับ​ที่ บท​ที่ 1 วัด​ไว้ คือ Date สร้าง​เวลา​ของ​โซน​อื่น​นอกจาก​โซน​ของ process ไม่​ได้

scripts/time-semantics/runners/shapes.py (เฉพาะ​ทรง E)
import json
from datetime import datetime
from zoneinfo import ZoneInfo
bkk = ZoneInfo("Asia/Bangkok")
json.dumps({"t": datetime(2026, 10, 2, 9, 0, tzinfo=bkk)})

บรรทัด​สุดท้าย​โยน exception และ runtime พิมพ์​ว่า

TypeError: Object of type datetime is not JSON serializable

ใน​สี่​ภาษา​ของ​ทรง​นี้ Python เป็น​ภาษา​เดียว​ที่​แดง เอกสาร​ของ json เขียน​กฎ​นี้​ไว้​ที่​ช่อง default ว่า “If None (the default), TypeError is raised.”

ความ​ดังนี้​มี​ราคา Python ไม่​ได้​เลือก​รูป​แบบ​ให้ ผู้​เขียน​ต้อง​เลือก​เอง​ว่า​จะ​ส่ง​อะไร และ probe ไม่​ได้​วัด​ทาง​เลือก​ที่​ผู้​เขียน​เลือก บท​นี้​จึง​พูด​ได้​แค่​ว่า json.dumps ไม่​ยอม​เดา​แทนคุณ

Java ไม่มี JSON ใน library มาตรฐาน probe จึง​วัด​สอง​สตริง​ที่ ZonedDateTime ตัว​เดียวกัน​เขียน​ออก​มา​ได้

scripts/time-semantics/runners/Shapes.java (เฉพาะ​ทรง E)
ZoneId bkk = ZoneId.of("Asia/Bangkok");
ZonedDateTime e = ZonedDateTime.of(2026, 10, 2, 9, 0, 0, 0, bkk);
e.toString(); // 2026-10-02T09:00+07:00[Asia/Bangkok]
DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(e); // 2026-10-02T09:00:00+07:00

toString() เป็น​สตริง​เดียว​ใน​บท​นี้​ที่​มีชื่อ​โซน Javadoc ของ​มัน​เขียน​ว่า “If the ZoneId is not the same as the offset, then the ID is output.” ส่วน ISO_OFFSET_DATE_TIME ได้​สตริง​หน้าตา​เดียว​กับ​ของ Go และ​ไม่มี​ชื่อ​โซน

สตริง​ของ toString() ไม่มี​วินาที ขณะ​ที่ grammar ของ RFC 3339 บังคับ​ช่อง​วินาที​ไว้​ใน partial-time = time-hour ":" time-minute ":" time-second [time-secfrac] มัน​จึง​ไม่ใช่​สตริง​ตาม​รูป​แบบ​ที่ RFC 3339 กำหนด

รวม​สตริง​ที่​แต่ละ​ภาษา​เขียน​ลง​สาย​ไว้​ใน​ตาราง​เดียว พร้อม​รุ่น​ของ tzdata ที่​แต่ละ​ภาษา​อ่าน​จริง

ภาษาการ​เรียกค่าที่​วัด​ได้tzdata ที่​ใช้
Go go1.27.0json.Marshal(...)"2026-10-02T09:00:00+07:00"2026c · /usr/share/zoneinfo ของ​ระบบ
Node v24.19.0 ที่ TZ=Asia/BangkokJSON.stringify(...){"t":"2026-10-02T02:00:00.000Z"}2026b · ICU ที่​ฝัง​ใน node
Node v24.19.0 ที่ TZ=America/New_YorkJSON.stringify(...){"t":"2026-10-02T13:00:00.000Z"}2026b · ICU ที่​ฝัง​ใน node
Python 3.14.6json.dumps(...)TypeError: Object of type datetime is not JSON serializable2026c · /usr/share/zoneinfo ของ​ระบบ
Java openjdk 25.0.4.1ISO_OFFSET_DATE_TIME.format(e)2026-10-02T09:00:00+07:002026b · tzdb.dat ของ JDK
Java openjdk 25.0.4.1e.toString()2026-10-02T09:00+07:00[Asia/Bangkok]2026b · tzdb.dat ของ JDK

probe ตรวจ​สี่​สตริง​ใน​ตาราง​ว่า​เป็น​สตริง​บน​สาย คือ​ของ Go ของ Node ทั้ง​สอง​แถว และ​ของ ISO_OFFSET_DATE_TIME ทั้ง​สี่​ไม่มี​คำ​ว่า Asia/Bangkok อยู่​เลย

แถว​ที่​มีชื่อ​โซน​มี​แถว​เดียว คือ toString() ของ Java ซึ่ง​ผู้​เขียน​ต้อง​เลือก​ใช้​มัน​เอง และ​มัน​ไม่ใช่​สตริง​ตาม RFC 3339

สี่​ภาษา​บน​เครื่อง​เดียวกัน​อ่าน tzdata สอง​รุ่น​ใน​ตาราง​นี้ คือ 2026b กับ 2026c probe ไม่​ได้​วัด​ว่า​สอง​รุ่น​นี้​ต่าง​กัน​ตรง​ไหน แต่​ตาราง​ที่​รวม​หลาย​ภาษา​ยัง​ต้อง​พิมพ์​รุ่น​ของ​ทุก​ภาษา เพราะ tzdata คือ​ข้อมูล​ที่​ปลาย​ทาง​ใช้​ตีความ​ชื่อ​โซน

ปลาย​ทาง​ได้ instant ที่​ถูก​ต้อง แต่​ไม่​ได้​กฎ​ของ​โซน และ​ทุก​การ​คำนวณ​ที่​ต้อง​ใช้​กฎ​นั้น​ต้องหา​มัน​จาก​ที่​อื่น

สตริง​ที่​มี +07:00 บอก​จุด​บน​เส้น​เวลา​ได้​ครบ RFC 3339 หัวข้อ 4.2 นิยาม offset ว่า​เป็น “local time minus UTC” ถ้า​หัก offset ออก​ตาม​นั้น ค่า 09:00+07:00 ของ Go คือ​จุด​เดียว​กับ 02:00 ใน UTC ของ Node ที่ TZ=Asia/Bangkok

ความ​เสีย​หาย​จึง​ไม่​ได้​อยู่​ที่​จุด​ที่​ส่ง​ไป แต่​อยู่​ที่​การ​คำนวณ​ครั้ง​ถัด​ไป​ของ​ปลาย​ทาง

  • บวก​เวลา​ตาม​ปฏิทิน · บท​ที่ 3 วัด​แล้ว​ว่า การ​บวก​หนึ่ง​วัน​บน offset ที่มา​กับ​สาย กับ​การ​บวก​บน​โซน ได้​คนละ​จุด​เมื่อ​ข้าม​คืน​ที่​เปลี่ยน DST
  • ย้อน​ไป​วัน​ที่​ใน​อดีต · บท​ที่ 7 วัด​ว่า Bangkok ไม่​ได้​ใช้ +07:00 มา​ตั้งแต่​แรก offset ของ​วัน​นี้​จึง​ตอบแทน​วัน​ใน​อดีต​ไม่​ได้
  • แสดง​เวลา​ให้​คนใน​ร้าน​เห็น · สตริง Z ของ Node ที่ TZ=Asia/Bangkok ไม่มี​ตัวเลข​บน​นาฬิกา​ของ​ร้าน​อยู่​ใน​นั้น ปลาย​ทาง​ต้อง​รู้​เอง​ว่า​ร้าน​อยู่​โซน​ไหน

ทั้ง​สาม​ข้อ​ต้อง​ใช้​ชื่อ​โซน และ​ชื่อ​โซน​คือ​สิ่ง​เดียว​ที่​ไม่​ได้​ข้าม​สาย​มา

ส่ง​ชื่อ​โซน​เป็น​ข้อมูล ไม่ใช่​หวัง​ว่า​มัน​จะ​ติด​ไป​เอง

ทางออก​คือ​ส่ง instant กับ​ชื่อ​โซน​เป็น​สอง​ช่อง​แยก​กัน​ใน JSON เช่น​ช่อง​หนึ่ง​เป็น UTC อีก​ช่อง​เป็น Asia/Bangkok บท​ที่ 8 วัด​ท่อ​แบบ​นั้น​ทั้ง​เส้น

ราคา​มี​สาม​ข้อ

  • สอง​ช่อง​ต้อง​ไป​ด้วย​กัน​ทุก​ทาง service ไหน​ที่​ส่ง​ต่อ​แค่​ช่อง​เดียว ก็​ทำให้​ชื่อ​โซน​หาย​เหมือน​เดิม
  • ปลาย​ทาง​ต้อง​มี tzdata ของ​ตัว​เอง เพื่อ​แปลง​ชื่อ​โซน​กลับ​เป็น​กฎ และ​ตาราง​ข้าง​บน​แสดง​แล้ว​ว่า​สอง​ภาษา​บน​เครื่อง​เดียวกัน​อ่าน​คนละ​รุ่น​ได้
  • JSON ไม่​ตรวจ​ว่า​สตริง​ใน​ช่อง​นั้น​เป็น​ชื่อ​โซน​ที่​มี​อยู่​จริง ปลาย​ทาง​ต้อง​ตรวจ​เอง

RFC 9557 เพิ่ม​รูป​แบบ​ที่​ต่อ​ชื่อ​โซน​ใน​วงเล็บ​เหลี่ยม​ท้าย​สตริง​ของ RFC 3339 แต่ probe ของ​คอร์ส​นี้ ไม่​ได้​วัด​ว่า​ภาษา​ไหน​เขียน​หรือ​อ่าน​รูป​แบบ​นั้น​ได้

🔁 เส้น​แบ่ง​กับ​คอร์ส integer-semantics

บท​ที่ 6 ของ integer-semantics วัด body JSON ใบ​เดียว​ที่​เดิน​ไป​หา​ปลาย​ทาง​หลาย​แห่ง คอร์ส​นั้น​เป็น​เจ้าของตัวเลข​บน JSON

คอร์ส​นี้​เป็น​เจ้าของเวลา​บน JSON บท​นี้​จึง​ไม่​วัด orderId หรือ​ยอด​เงิน และ​คอร์ส​นั้น​ไม่​วัด​สตริง​ของ​เวลา

จุด​ที่​สาม · offset ที่มา​กับ​สาย มอง​จาก​ฝั่ง​ที่​ส่ง

หัวข้อ​ที่​มีชื่อ​ว่า “จุด​ที่​สาม · offset ที่มา​กับ​สาย มอง​จาก​ฝั่ง​ที่​ส่ง”

บท​ที่ 3 วัด​ฝั่ง​ที่​รับ offset มา​จาก​สาย บท​นี้​วัด​ฝั่ง​ที่​เขียน offset ลงไป และ​ทั้ง​สอง​ฝั่ง​นับ​เป็น​จุด​ที่​สาม​จุด​เดียวกัน

ธี​สิ​ส​ของ​คอร์ส​นี้​คือ wall-clock time ค่า​หนึ่ง​ไม่​ได้​ระบุ​จุด​เดียว​บน​เส้น​เวลา มัน​อาจ​ไม่มี​จุด​เลย มี​สอง​จุด หรือ​มี​จุด​เดียว​ที่​แต่ละ​ภาษา​เลือก​ต่าง​กัน และ​ใน​ทรง​ที่ probe วัด มี​ภาษา​เดียว​จาก​ห้า​ภาษา​ที่​บอก​คุณ

จุด​ที่​สาม​คือ offset ที่มา​กับ​สาย ฝั่ง​ที่​ส่ง​เป็นต้น​เหตุ​ของ​มัน ใน​ทรง​ที่ probe วัด สี่​สตริง​บน​สาย​ไม่มี​ชื่อ​โซน​สัก​ตัว และ​ภาษา​เดียว​ที่​แดง​คือ Python ซึ่ง​แดง​เพราะ​ไม่​ยอม​เขียน​อะไร​เลย ไม่ใช่​เพราะ​มัน​เห็น​ว่า​ชื่อ​โซน​กำลัง​จะ​หาย

บท​ที่ 7 ใช้​ชื่อ​โซน​ที่​บท​นี้​บอก​ว่า​หาย​ไป แล้ว​ถาม​ว่า Asia/Bangkok เคย​มี offset อะไร​บ้าง และ​ภาษา​ไหน​พิมพ์​มัน​ผิด


🔗 อ้างอิง​ต้นทาง​ของ​บท​นี้
  • RFC 3339 — Date and Time on the Internet: Timestamps (เข้า​ถึง 2026-10-03) — ที่มา​ของ grammar time-numoffset และ partial-time และ​ของ​เหตุผล​ใน​หัวข้อ 4.2 ที่​เลือก offset แบบ​ตัวเลข “Attempts to label local offsets with alphabetic strings have resulted in poor interoperability in the past”

  • RFC 9557 — Date and Time on the Internet: Timestamps with Additional Information (เข้า​ถึง 2026-10-03) — ที่มา​ของ​รูป​แบบ​ที่​ต่อ​ชื่อ​โซน​ท้าย​สตริง​ของ RFC 3339 · บทคัดย่อ​เขียน​ว่า “This document defines an extension to the timestamp format defined in RFC 3339 for representing additional information, including a time zone.”

  • Go — package time, func (Time) MarshalJSON (เข้า​ถึง 2026-10-03) — ที่มา​ของ​ประโยค “The time is a quoted string in the RFC 3339 format with sub-second precision.”

  • MDN — Date.prototype.toJSON() (เข้า​ถึง 2026-10-03) — ที่มา​ของ​ข้อ​ที่ toJSON() คืน​สตริง​ตาม universal time และ​ของ​ข้อ​ที่ “The toJSON() method is automatically called by JSON.stringify() when a Date object is stringified.”

  • Python — json (เข้า​ถึง 2026-10-03) — ที่มา​ของ​กฎ​ที่​ช่อง default เป็น None แล้ว “TypeError is raised.”

  • Java SE 25 — ZonedDateTime (เข้า​ถึง 2026-10-03) — ที่มา​ของ​กฎ​ของ toString() “If the ZoneId is not the same as the offset, then the ID is output.”

  • Java SE 25 — DateTimeFormatter (เข้า​ถึง 2026-10-03) — ที่มา​ของ ISO_OFFSET_DATE_TIME ซึ่ง​เขียน​วัน​ที่ เวลา และ offset โดย​ไม่มี​ชื่อ​โซน

  • ค่า​ทุก​ค่า​ใน​บท​นี้​มา​จาก scripts/time-semantics/measured.json ซึ่ง scripts/time-semantics/probe.py เขียน​เมื่อ 2026-10-02 บน darwin/arm64 · probe วัด​ทั้ง​ชุด​สาม​รอบ​ต่อ​การ​เรียก​หนึ่ง​ครั้ง และ Node รัน​ด้วย TZ ที่ probe ตั้ง​เอง​ทุก​ครั้ง

เช็กความเข้าใจ — บทที่ 6

ข้อ 1 / 3

`json.Marshal(time.Date(2026, 10, 2, 9, 0, 0, 0, bkk))` ของ Go ที่ `bkk` คือ `Asia/Bangkok` เขียนอะไรลงสาย