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

slot ส่ง​ของ​ที่​รอด​ทั้ง​เส้น​ทาง

เจ็ด​บท​ที่​ผ่าน​มา​วัด​เวลา​ที​ละ​จุด บท​นี้​เอา​จุด​เหล่า​นั้น​มา​ต่อ​กัน​เป็น​ท่อ​เดียว แล้ว​ส่ง​ออ​เด​อร์​ใบ​หนึ่ง​เข้าไป​จริง

ออ​เด​อร์ A-1042 มี delivery slotdelivery slotช่วง​เวลา​ส่ง​ของ​ที่​ร้าน​สัญญา​กับ​ลูกค้า ระบุ​เป็น​วัน​ที่​และ​เวลา​บน​หน้า​ปัด​ใน​โซน​ของ​ร้าน · คอร์ส​นี้​ใช้​มัน​เป็น​ค่าที่​ต้อง​รอด​ทั้ง​เส้น​ทาง ตั้งแต่​ฟอร์ม​ที่​ลูกค้า​กรอก​จนถึง​ระบบ​ที่​อยู่​อีก​โซน (ช่วง​เวลา​ส่ง​ของ​ที่​ร้าน​สัญญา​กับ​ลูกค้า) ให้​เลือก​สี่​ใบ ทุก​ใบ​เป็น​เวลา​บน​หน้า​ปัด​ของ​โซน America/New_York และ body ทั้ง​ใบ​คือ​สิ่ง​ที่​ท่อ​ทั้ง​สอง​เส้น​รับ​เข้าไป

body ที่​ท่อ​ทั้ง​สอง​เส้น​รับ
{"orderId": "A-1042", "zone": "America/New_York", "slots": ["2026-03-07T12:00", "2026-03-07T02:30", "2026-03-08T02:30", "2026-11-01T01:30"]}

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

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

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

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

ท่อ​ทั้ง​สอง​เส้น​อยู่​ใน file เดียวกัน อ่าน body จาก​ตัวแปร​ตัว​เดียวกัน และ slot แต่ละ​ใบ​ถูก​เลือก​มา​เพื่อ​แตะ​จุด​หนึ่ง​ของ​คอร์ส

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

scripts/time-semantics/runners/pipeline.py (หัว​และ​ท้าย​ของ file)
body = json.loads(sys.argv[1])
ZONE = ZoneInfo(body["zone"])
# ...
out = {"naive": {s: naive(s) for s in body["slots"]},
"guarded": {s: guarded(s) for s in body["slots"]}}

body มา​จาก​อาร์กิวเมนต์​ตัว​เดียว​ทาง argv แล้ว​ฟังก์ชัน​ทั้ง​สอง​ตัว​รับ slot จาก​รายการ​เดียวกัน​นั้น probe รัน file นี้​ด้วย Python 3.14.6 ซึ่ง​อ่าน tzdata รุ่น 2026c จาก /usr/share/zoneinfo ของ​ระบบ บน darwin/arm64

slot สี่​ใบ​ไม่​ได้​สุ่ม​มา แต่ละ​ใบ​แตะ​จุด​ที่​บท​ก่อน​หน้า​วัด​ไว้

  • 2026-03-07T12:00 เป็น​เวลา​ปกติ​ของ​วัน​ก่อน​ที่ DST เริ่ม ใบ​นี้​มี​ไว้​วัด​การ​เลื่อน​นัด​ข้าม​คืน​นั้น
  • 2026-03-07T02:30 มี​อยู่​จริง​ใน​วัน​นั้น แต่​วัน​พรุ่ง​นี้​ของ​มัน​ไม่มี 02:30
  • 2026-03-08T02:30 คือ​เวลา​ที่​ไม่มี​อยู่​จริง​ของบท​ที่ 1
  • 2026-11-01T01:30 คือ​เวลา​ที่​มี​สอง​ครั้ง​ของบท​ที่ 4

ทั้ง​สอง​เส้น​เดิน​สี่​ขั้น​เหมือน​กัน คือ​รับ slot จาก​ฟอร์ม · ส่ง JSON ไป​หา​คลัง​สินค้า · ให้​คลัง​อ่าน​ออก​มา​เป็น​จุด​บน​เส้น​เวลา · แล้ว​เลื่อน​นัด​ไป​วัน​พรุ่ง​นี้​เวลา​เดิม

flowchart LR
  A["ฟอร์ม · slot บนหน้าปัด"] --> B{"ท่อเส้นไหน"}
  B -->|"ท่อเปล่า"| C["รับทุกใบ"]
  C --> D["สาย · สตริงที่มีแค่ offset"]
  D --> E["คลัง · tzinfo เป็น offset คงที่"]
  E --> F["เลื่อนนัด · บวกหนึ่งวันบน offset"]
  B -->|"ท่อที่มีด่าน"| G{"ชี้จุดเดียวไหม"}
  G -->|"ไม่"| H["ValueError · ไม่ส่งต่อ"]
  G -->|"ใช่"| I["สาย · instant กับชื่อโซนสองช่อง"]
  I --> J["คลัง · tzinfo เป็นโซน"]
  J --> K{"เลื่อนนัด · ใบใหม่ชี้จุดเดียวไหม"}
  K -->|"ไม่"| H
  K -->|"ใช่"| L["slot ใบใหม่"]

คำ​บรรยาย​ภาพ: สอง​เส้น​ต่าง​กัน​สาม​ที่ คือ​ด่าน​ก่อน​รับ ของ​ที่​อยู่​บน​สาย และ​กฎ​ที่​ใช้​เลื่อน​นัด ส่วน​ที่​เหลือ​ของ​บท​วัด​ว่า​ความ​ต่าง​สาม​ที่​นั้น​ออก​มา​เป็น​ค่า​อะไร​ที่​ปลาย​ทาง

เส้น​แรก​เขียน​ตาม​สัญชาตญาณ ไม่มี​ขั้น​ไหน​ล้ม และ​ไม่มี​ขั้น​ไหน​รายงาน​อะไร​เลย

ท่อ​เส้น​แรก​ติด​โซน​ให้​เวลา​บน​หน้า​ปัด​ด้วย replace แล้ว​ส่ง isoformat() ออก​ไป ปลาย​ทาง parse สตริง​นั้น​กลับ​มา แล้ว​บวก timedelta(days=1) เพื่อ​เลื่อน​นัด

scripts/time-semantics/runners/pipeline.py (ท่อ​เปล่า เฉพาะ​บรรทัด​ที่​ทำงาน)
# 1 · รับ · ไม่มีอะไรล้มได้ตรงนี้
local = datetime.fromisoformat(slot).replace(tzinfo=ZONE)
# 2 · ส่ง
wire = json.dumps({"orderId": body["orderId"], "slot": local.isoformat()})
# 3 · ปลายทาง
got = datetime.fromisoformat(json.loads(wire)["slot"])
# 4 · เลื่อนนัด · บวกบน offset ที่ได้มาจากสาย
moved = got + timedelta(days=1)

ท่อ​เปล่า​รับ slot ครบ​ทั้ง​สี่​ใบ และ​ช่อง error ของ​ทุก​ใบ​เป็น​สตริง​ว่าง​ทั้ง​ตอน​รับ​และ​ตอน​เลื่อน​นัด

body ที่​ขึ้น​สาย​ของ slot 2026-03-07T12:00 คือ

บน​สาย · ท่อ​เปล่า · slot 2026-03-07T12:00
{"orderId": "A-1042", "slot": "2026-03-07T12:00:00-05:00"}

ชื่อ America/New_York ไม่​อยู่​บน​สาย​แล้ว สิ่ง​ที่​เหลือ​คือ offset -05:00 ตัว​เดียว คลัง​จึง​ได้ tzinfo เป็น datetime.timezone(datetime.timedelta(days=-1, seconds=68400)) ซึ่ง​เป็น offset คงที่

เอกสาร​ของ Python เขียน​ข้อ​จำกัด​ของ timezone ไว้​ตรงๆ ว่า “Objects of this class cannot be used to represent time zone information in the locations where different offsets are used in different days of the year”

ส่วน slot 2026-11-01T01:30 ได้ tzinfo เป็น datetime.timezone(datetime.timedelta(days=-1, seconds=72000)) ซึ่ง​ก็​เป็น offset คงที่​อีก​ตัว​หนึ่ง

slot ที่​ลูกค้า​จอง กับ​นาฬิกา​ของ​ลูกค้า​ตอน​รถ​มา​ถึง

หัวข้อ​ที่​มีชื่อ​ว่า “slot ที่​ลูกค้า​จอง กับ​นาฬิกา​ของ​ลูกค้า​ตอน​รถ​มา​ถึง”

ช่อง​สุดท้าย​ของ​ตาราง​ข้าง​ล่าง​ไม่​ได้​มา​จาก​ท่อ​เปล่า เพราะ​ท่อ​เปล่า​ไม่มี​ชื่อ​โซน​อยู่​ใน​มือ​แล้ว probe อ่าน​มัน​เอง​ด้วย​โซน America/New_York เพื่อ​บอก​ว่า​รถ​มา​ถึง​ตอน​ไหน​ใน​สายตา​ของ​ลูกค้า

slot ที่​จองบน​สายinstant ที่​คลัง​ได้นาฬิกา​ของ​ลูกค้า
2026-03-07T12:002026-03-07T12:00:00-05:002026-03-07T17:00:00Z2026-03-07T12:00:00-05:00
2026-03-07T02:302026-03-07T02:30:00-05:002026-03-07T07:30:00Z2026-03-07T02:30:00-05:00
2026-03-08T02:302026-03-08T02:30:00-05:002026-03-08T07:30:00Z2026-03-08T03:30:00-04:00
2026-11-01T01:302026-11-01T01:30:00-04:002026-11-01T05:30:00Z2026-11-01T01:30:00-04:00

แถว​ที่​สาม​เป็น​แถว​เดียว​ที่​นาฬิกา​ของ​ลูกค้า​ไม่​ตรง​กับ slot ที่​จอง ลูกค้า​จอง 02:30 บน​สาย​เขียน 02:30:00-05:00 แต่​รถ​มา​ถึง​ตอน​นาฬิกา​ของ​ลูกค้า​บอก 03:30:00-04:00

แถว​ที่​สี่​ตรง​กับ​ที่​จอง​ทุก​ตัว​อักษร แต่ 01:30 ของ​วัน​นั้น​มี​สอง​ครั้ง ท่อ​เปล่า​เลือก -04:00 ให้​โดย​ไม่มี​ใคร​ถาม ใน​ทรง​ที่ probe วัด การ​เลือก​นี้​มา​จาก replace(tzinfo=ZONE) ที่​ไม่​ได้​ตั้ง fold ซึ่ง​ค่า​ตั้ง​ต้น​คือ 0

ขั้น​ที่​สี่​บวก timedelta(days=1) บน offset ที่​ได้​จาก​สาย ผล​คือ

slot ที่​จองหลัง​เลื่อนinstant หลัง​เลื่อนนาฬิกา​ของ​ลูกค้า​หลัง​เลื่อน
2026-03-07T12:002026-03-08T12:00:00-05:002026-03-08T17:00:00Z2026-03-08T13:00:00-04:00
2026-03-07T02:302026-03-08T02:30:00-05:002026-03-08T07:30:00Z2026-03-08T03:30:00-04:00
2026-03-08T02:302026-03-09T02:30:00-05:002026-03-09T07:30:00Z2026-03-09T03:30:00-04:00
2026-11-01T01:302026-11-02T01:30:00-04:002026-11-02T05:30:00Z2026-11-02T00:30:00-05:00

ทั้ง​สี่​แถว นาฬิกา​ของ​ลูกค้า​หลัง​เลื่อน​ไม่​ได้​แสดง​เวลา​เดิม​ของ​วัน​พรุ่ง​นี้​เลย​สัก​แถว

  • แถว​แรก ลูกค้า​ขอ 12:00 ของ​วัน​พรุ่ง​นี้ แต่​รถ​มา​ตอน 13:00:00-04:00 เพราะ offset -05:00 ที่​ติด​มา​กับ​สาย​ไม่รู้​ว่า DST เริ่ม​แล้ว เป็น​จุด​เดียว​กับ​ที่บท​ที่ 3วัด​ไว้
  • แถว​ที่​สอง วัน​พรุ่ง​นี้​ของ 02:30 ไม่มี 02:30 ท่อ​เปล่า​ไม่รู้​เรื่อง​นี้ และ​ส่ง​รถ​ไป​ตอน 03:30:00-04:00
  • แถว​ที่​สาม slot ที่​ไม่มี​อยู่​จริง​ตั้งแต่​ต้น พา​ความคลาด​เคลื่อน​ของ​มัน​ไป​ถึง​วัน​ถัด​ไป​ด้วย
  • แถว​ที่​สี่ -04:00 ที่​ถูก​เลือก​ให้​เงียบๆ เมื่อ​วาน​ใช้​ไม่​ได้​แล้ว​ใน​วัน​นี้ รถ​จึง​มา​ตอน 00:30:00-05:00

แถว​ที่​สอง​หลัง​เลื่อน​กับ​แถว​ที่​สาม​ก่อน​เลื่อน คือ 02:30 ของ​วัน​ที่ 2026-03-08 ที่มา​ถึง​สอง​ทาง ทั้ง​สอง​ทาง​ลง​ที่ instant เดียวกัน คือ 2026-03-08T07:30:00Z และ​ไม่มี​ทาง​ไหน​บอก​ว่า​เวลา​นั้น​ไม่มี​อยู่​จริง

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

ด่าน​ของ​เส้น​ที่​สอง​คือ​ฟังก์ชัน resolve ตัว​เดียว มัน​แปลง​เวลา​บน​หน้า​ปัด​เป็น​จุด​เดียว​บน​เส้น​เวลา หรือ​โยน ValueError

scripts/time-semantics/runners/pipeline.py (ด่าน​ของ​ท่อ​ที่​มี​ด่าน)
def resolve(wall: datetime) -> datetime:
"""เวลาท้องถิ่น → จุดเดียวบนเส้นเวลา หรือ ValueError"""
a = wall.replace(tzinfo=ZONE, fold=0)
b = wall.replace(tzinfo=ZONE, fold=1)
back = a.astimezone(timezone.utc).astimezone(ZONE).replace(tzinfo=None)
if back != wall:
raise ValueError(f"nonexistent local time {wall:%Y-%m-%dT%H:%M} in {ZONE.key}")
if a.utcoffset() != b.utcoffset():
raise ValueError(f"ambiguous local time {wall:%Y-%m-%dT%H:%M} in {ZONE.key}: "
f"{a:%:z} or {b:%:z}")
return a

ด่าน​นี้​ถาม​สอง​คำถาม และ​ทั้ง​สอง​คำถาม​ใช้​กลไก​ที่​บท​ก่อน​หน้า​วัด​ไว้​แล้ว

  • เวลา​นี้​มี​อยู่​จริง​ไหม ส่ง​ไป UTC แล้วก​ลับ​มา ถ้า​ไม่​ได้​ค่า​เดิม แปล​ว่า​ไม่มี เป็น​วิธี​เดียว​กับ​หลัก​ฐาน​ในบท​ที่ 1 PEP 495 เขียน​ไว้​ว่า “The fromutc() method should never produce a time in the gap.”
  • เวลา​นี้​มี​ครั้ง​เดียว​ไหม ถาม offset ทั้ง​ที่ fold=0 และ fold=1 ถ้า​ได้​คนละ​ค่า แปล​ว่า​มี​สอง​ครั้ง

ท่อ​นี้​ปฏิเสธ​เวลา​ที่​มี​สอง​ครั้ง​ด้วย ทั้ง​ที่​เวลา​นั้น​มี​อยู่​จริง นี่​เป็นการ​ตัดสิน​ของ​คน​เขียน​ท่อ ไม่ใช่​ของ Python เพราะ slot ส่ง​ของ​ต้อง​ชี้​จุด​เดียว ท่อ​แบบ​อื่น​อาจ​เลือก​ถาม​ลูกค้า​แทน​การ​ปฏิเสธ​ก็ได้

ส่วน​ที่​เหลือ​ของ​เส้น​ที่​สอง​ส่ง instant แบบ UTC กับ​ชื่อ​โซน​เป็น​สอง​ช่อง แล้ว​เลื่อน​นัด​บน​หน้า​ปัด​ของ​โซน​นั้น

scripts/time-semantics/runners/pipeline.py (ท่อ​ที่​มี​ด่าน เฉพาะ​บรรทัด​ที่​ทำงาน)
# 1 · รับ · ตรวจก่อน
local = resolve(datetime.fromisoformat(slot))
# 2 · ส่ง · instant กับชื่อโซนเป็นสองช่อง
wire = json.dumps({"orderId": body["orderId"], "instant": utc(local), "zone": ZONE.key})
# 3 · ปลายทาง
msg = json.loads(wire)
got = datetime.fromisoformat(msg["instant"]).astimezone(ZoneInfo(msg["zone"]))
# 4 · เลื่อนนัด · บวกวันบนหน้าปัดของโซน แล้วตรวจซ้ำ
moved = resolve(got.replace(tzinfo=None) + timedelta(days=1))

ท่อ​ที่​มี​ด่าน​รับ 2026-03-07T12:00 กับ 2026-03-07T02:30 และ​ปฏิเสธ​อีก​สอง​ใบ​ด้วย​ข้อความ​เหล่า​นี้

ท่อ​ที่​มี​ด่าน · ขั้น​รับ · slot 2026-03-08T02:30
ValueError: nonexistent local time 2026-03-08T02:30 in America/New_York
ท่อ​ที่​มี​ด่าน · ขั้น​รับ · slot 2026-11-01T01:30
ValueError: ambiguous local time 2026-11-01T01:30 in America/New_York: -04:00 or -05:00

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

body ที่​ขึ้น​สาย​ของ slot 2026-03-07T12:00 คือ

บน​สาย · ท่อ​ที่​มี​ด่าน · slot 2026-03-07T12:00
{"orderId": "A-1042", "instant": "2026-03-07T17:00:00Z", "zone": "America/New_York"}

คลัง​ได้ tzinfo เป็น zoneinfo.ZoneInfo(key='America/New_York') คือ​ได้​โซน​กลับ​มา​ทั้ง​ชุด​กฎ ไม่ใช่ offset ตัว​เดียว นาฬิกา​ของ​ลูกค้า​ที่ instant นั้น​คือ 2026-03-07T12:00:00-05:00 ตรง​กับ​ที่​จอง

slot 2026-03-07T02:30 ขึ้น​สาย​เป็น instant 2026-03-07T07:30:00Z และ​นาฬิกา​ของ​ลูกค้า​คือ 2026-03-07T02:30:00-05:00 ซึ่ง​ก็​ตรง​กับ​ที่​จอง​เช่น​กัน ทุก​ใบ​ที่​ท่อ​นี้​รับ นาฬิกา​ของ​ลูกค้า​ตรง​กับ slot ที่​จอง

slot 2026-03-07T12:00 เลื่อน​ไป​ได้ 2026-03-08T12:00:00-04:00 ซึ่ง​เป็น instant 2026-03-08T16:00:00Z และ​นาฬิกา​ของ​ลูกค้า​บอก 2026-03-08T12:00:00-04:00 คือ​เวลา​เดิม​ของ​วัน​พรุ่ง​นี้

slot 2026-03-07T02:30 ผ่าน​ด่าน​ตอน​รับ แต่​ตก​ด่าน​ตอน​เลื่อน​นัด เพราะ​วัน​พรุ่ง​นี้​ของ​มัน​ไม่มี 02:30

ท่อ​ที่​มี​ด่าน · ขั้น​เลื่อน​นัด · slot 2026-03-07T02:30
ValueError: nonexistent local time 2026-03-08T02:30 in America/New_York

ใบ​นี้​คือ​ใบ​ที่​ท่อ​เปล่า​ส่ง​รถ​ไป​ตอน 03:30:00-04:00 โดย​ไม่มี​ใคร​รู้ ท่อ​ที่​มี​ด่าน​ไม่​ส่ง​รถ​ไป​เลย แล้ว​คืน​ข้อความ​ที่​บอก​ว่า​ทำไม

ค่าที่​ออก​จาก​ปลาย​ทาง​ของ​สอง​เส้น​ต่าง​กัน​ตรง​ไหน วัด​เป็น​สตริง​ทุก​ช่อง

ตาราง​นี้​เอา​นาฬิกา​ของ​ลูกค้า​จาก​สอง​เส้น​มา​วาง​คู่​กัน ทั้ง​ตอน​รถ​มา​ตาม​นัด​แรก และ​ตอน​รถ​มา​ตาม​นัด​ที่​เลื่อน​แล้ว

slot ที่​จองท่อ​เปล่า · นัด​แรกท่อ​ที่​มี​ด่าน · นัด​แรกท่อ​เปล่า · หลัง​เลื่อนท่อ​ที่​มี​ด่าน · หลัง​เลื่อน
2026-03-07T12:0012:00:00-05:0012:00:00-05:0013:00:00-04:0012:00:00-04:00
2026-03-07T02:3002:30:00-05:0002:30:00-05:0003:30:00-04:00ValueError ตอน​เลื่อน
2026-03-08T02:3003:30:00-04:00ValueError ตอน​รับ03:30:00-04:00ไม่​ได้​รับ​ไว้
2026-11-01T01:3001:30:00-04:00ValueError ตอน​รับ00:30:00-05:00ไม่​ได้​รับ​ไว้

แต่ละ​ช่อง​ตัด​มา​เฉพาะ​ส่วน​เวลา​ของ​ค่าที่​บท​นี้​ยกไว้​ข้าง​บน ค่า​เต็ม​พร้อม​วัน​ที่​อยู่​ใน​หัวข้อ​ของ​แต่ละ​เส้น

แถว​แรก​เป็น​แถว​เดียว​ที่​ทั้ง​สอง​เส้น​รับ​และ​เลื่อน​ได้​ครบ นัด​แรก​ของ​สอง​เส้น​เป็น instant เดียวกัน คือ 2026-03-07T17:00:00Z แต่​หลัง​เลื่อน ท่อ​เปล่า​ได้ 2026-03-08T17:00:00Z ส่วน​ท่อ​ที่​มี​ด่าน​ได้ 2026-03-08T16:00:00Z ซึ่ง​เป็น​คนละ​จุด

สิ่ง​ที่​แยก​สอง​เส้น​ออก​จาก​กัน​ใน​แถว​นี้​ไม่ใช่​ด่าน แต่​เป็น​ชื่อ​โซน​บน​สาย ชื่อ America/New_York อยู่​ใน body ของ​ท่อ​ที่​มี​ด่าน และ​ไม่​อยู่​ใน body ของ​ท่อ​เปล่า ปลาย​ทาง​ที่​ไม่มี​ชื่อ​โซน​จึง​บวก​วัน​ตาม​กฎ​ของ​โซน​ไม่​ได้ เป็น​จุด​เดียว​กับ​ที่ บท​ที่ 6วัด​ไว้

ส่วน​ที่​แยก​สอง​เส้น​ใน​อีก​สาม​แถว​คือ​ด่าน ท่อ​เปล่า​ไม่​รายงาน​ความ​ล้ม​เหลว​สัก​จุด ส่วน​ท่อ​ที่​มี​ด่าน​เป็น​เส้น​เดียว​ที่​รายงาน

ราคา​ของ​ท่อ​ที่​มี​ด่าน และ​สิ่ง​ที่​บท​นี้​ไม่​ได้​วัด

ด่าน​ไม่​ได้​ทำให้ slot สาม​ใบ​ที่​ตก​ด่าน​กลาย​เป็น​นัด​ที่​ใช้ได้ สิ่ง​ที่​ด่าน​เปลี่ยน​คือ​ความคลาด​เคลื่อน​กลาย​เป็น​ข้อความ​ที่​อ่าน​ได้ แทนที่​จะ​เป็น​รถ​ที่มา​ผิด​เวลา

ราคา​ที่​เห็น​ได้​จาก​ค่าที่​วัด​ใน​บท​นี้​มี​สาม​ข้อ

  • รูป​ของ body บน​สาย​เปลี่ยน จาก​ช่อง slot ช่อง​เดียว เป็น​ช่อง instant กับ zone ทุก service ที่​อ่าน body นี้​ต้อง​แก้​ตาม
  • slot สอง​ใบ​ถูก​ปฏิเสธ​ตั้งแต่​ฟอร์ม ระบบ​ต้อง​มี​ทาง​ถาม​ลูกค้า​ใหม่ ซึ่ง​ท่อ​ใน​บท​นี้​ไม่​ได้​เขียน​ไว้
  • การ​เลื่อน​นัด​หนึ่ง​ใบ​ไม่มี​คำ​ตอบ ผู้​เรียก​ต้อง​เขียน​ทาง​เดิน​ของ​ความ​ล้ม​เหลว​เอง ไม่ใช่​รับ​ค่า​มา​แล้วไป​ต่อ

probe ของ​คอร์ส​นี้​ไม่​ได้​วัด​เวลา​ที่​ใช้​รัน และ​ไม่​ได้​วัด​ต้นทุน​ของ​ด่าน บท​นี้​จึง​ไม่​บอก​ว่า​ด่าน​ถูก​หรือ​แพง มัน​บอก​เฉพาะ​ค่าที่​ออก​จาก​ปลาย​ทาง​ของ​สอง​เส้น

ท่อ​ทั้ง​สอง​เส้น​เขียน​ด้วย Python ภาษา​เดียว ค่า​ใน​บท​นี้​จึง​เป็น​ค่า​ของ Python ใน​ทรง​ที่ probe วัด ไม่ใช่​ค่า​ของ​อีก​สี่​ภาษา ฝั่ง JavaScript มี Temporal เป็น​ทิศทาง​ที่​น่า​ตาม​ต่อ แต่ probe ไม่​ได้​วัด​มัน บท​นี้​จึง​ไม่​พิมพ์​ค่า​ของ​มัน​สัก​ค่า

บท​นี้​ไม่​ได้​เป็น​เจ้าของ​จุด​ไหน มัน​คือ​ที่​ที่​จุด​ที่​วัด​แล้ว​ถูก​วาง​ต่อ​กัน​เป็น​ท่อ​เดียว

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

เจ็ด​บท​ก่อน​หน้า​วัด​หก​จุด​ที่​เวลา​เปลี่ยน​ไป​ระหว่าง​ทาง

จุดเรื่องบท
1เวลา​ท้อง​ถิ่น​ที่​ไม่มี​อยู่​จริงบท​ที่ 1
2วัน​ที่​ที่​ไม่มี​เวลาบท​ที่ 2
3offset ที่มา​กับ​สายบท​ที่ 3 และบท​ที่ 6
4เวลา​ท้อง​ถิ่น​ที่​มี​สอง​ครั้งบท​ที่ 4
5การ​บวก​ข้าม​คืน​ที่​เปลี่ยน DSTบท​ที่ 5
6กฎ​ของ​โซน​ที่​เปลี่ยน​ตาม​ปีบท​ที่ 7

ท่อ​ใน​บท​นี้​เดิน​ผ่าน​สี่​จุด​ใน​หก​จุด​นั้น

  • จุด​ที่ 1 คือ slot 2026-03-08T02:30 และ​วัน​พรุ่ง​นี้​ของ slot 2026-03-07T02:30
  • จุด​ที่ 3 คือ body ของ​ท่อ​เปล่า​ที่​พา​แค่ offset ไป​บน​สาย แล้ว​คลัง​ได้ tzinfo เป็น offset คงที่
  • จุด​ที่ 4 คือ slot 2026-11-01T01:30 ที่​ท่อ​เปล่า​เลือก -04:00 ให้​เงียบๆ
  • จุด​ที่ 5 คือ​การ​เลื่อน 2026-03-07T12:00 ข้าม​คืน​ที่ DST เริ่ม

จุด​ที่ 2 กับ​จุด​ที่ 6 ไม่มี​ที่​นั่ง​ใน​ท่อ​นี้ เพราะ​ไม่มี slot ใบ​ไหน​เป็น​วัน​ที่​ที่​ไม่มี​เวลา และ​ทุก​ใบ​อยู่​ใน​ปี 2026 การ​เขียน​ว่า​สอง​จุด​นั้น​โผล่​ที่​นี่​ด้วย​จะ​เป็นการ​อ้าง​ค่าที่ probe ไม่​ได้​วัด

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


🔗 อ้างอิง​ต้นทาง​ของ​บท​นี้
  • Python — datetime (เข้า​ถึง 2026-10-03) — ที่มา​ของ​ข้อ​จำกัด​ของ timezone ที่​ท่อ​เปล่า​ได้​จาก​สาย หน้า​นี้​เขียน​ว่า “The timezone class is a subclass of tzinfo, each instance of which represents a time zone defined by a fixed offset from UTC.” และ “Objects of this class cannot be used to represent time zone information in the locations where different offsets are used in different days of the year or where historical changes have been made to civil time.”

  • Python — zoneinfo (เข้า​ถึง 2026-10-03) — ที่มา​ของ ZoneInfo ที่​ท่อ​ที่​มี​ด่าน​ได้​กลับ​มา​จาก​ชื่อ​โซน​บน​สาย หน้า​นี้​เขียน​ว่า​มัน “represents an IANA time zone specified by the string key”

  • PEP 495 — Local Time Disambiguation (เข้า​ถึง 2026-10-03) — ที่มา​ของ​สอง​กลไก​ใน resolve คือ “The fromutc() method should never produce a time in the gap.” และ​กฎ​ของ​เวลา​ใน gap ที่ fold=0 ใช้ “the rules in effect before the transition” ส่วน fold=1 ใช้ “the rules in effect after the transition”

  • MDN — Temporal (เข้า​ถึง 2026-10-03) — หน้า​นี้​เขียน​ว่า “The Temporal object enables date and time management in various scenarios, including built-in time zone and calendar representation” และ​ติด​ป้าย “Limited availability” ไว้ · probe ไม่​ได้​วัด​มัน

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

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

ข้อ 1 / 3

ในท่อเปล่า slot `2026-03-08T02:30` ขึ้นสายเป็น `2026-03-08T02:30:00-05:00` นาฬิกาของลูกค้าบอกเวลาอะไรตอนรถมาถึง