Python zoneinfo.reset_tzpath: คุมแหล่งข้อมูล timezone ใน test และ deployment
ระบบเวลาในเครื่องนักพัฒนา, container และ CI อาจอ่านฐานข้อมูลเขตเวลาจากคนละที่ ถ้าต้องทดสอบกรณี “ไม่มี system tzdata” หรือบังคับ fixture เฉพาะ การแก้ตัวแปร environment กลางโปรเซสอาจสายเกินไป ฟังก์ชัน zoneinfo.reset_tzpath ช่วยตั้ง search path ที่ ZoneInfo จะใช้กับการค้นหาครั้งถัดไปครับ
WHY: dependency เรื่องเวลาก็ควรถูกควบคุม
ลองนึกถึงครัวที่มีชั้นเครื่องปรุงหลายจุด หากแต่ละเครื่องไปหยิบคนละชั้น รสชาติ test ก็ไม่นิ่ง TZPATH คือรายชื่อชั้นที่ runtime เดินหาไฟล์ TZif ส่วน reset_tzpath คือการบอกพ่อครัวว่าให้เริ่มค้นจากชั้นชุดไหน
import unittest
import zoneinfo
class TimeZonePathTests(unittest.TestCase):
def test_path_can_be_replaced_and_restored(self):
original = zoneinfo.TZPATH
try:
zoneinfo.reset_tzpath([])
self.assertEqual(zoneinfo.TZPATH, ())
finally:
zoneinfo.reset_tzpath(list(original))
self.assertEqual(zoneinfo.TZPATH, original)
if __name__ == "__main__":
unittest.main()
ตัวอย่างเก็บค่าเดิมและ restore ใน finally เพราะนี่คือ global state ของโปรเซส หาก test หนึ่งเปลี่ยนแล้วไม่คืน test อื่นอาจล้มตามแบบหาต้นเหตุยาก ยิ่งรัน parallel ยิ่งควรแยกเป็น subprocess หรือ fixture ที่ล็อก scope แทนการหวังลำดับ
สิ่งที่ reset ไม่ได้ทำ
เอกสารเตือนว่าการเปลี่ยน TZPATH ไม่ได้ล้าง cache ของ ZoneInfo ที่สร้างไปแล้ว ดังนั้น object เดิมอาจยังอยู่ หากต้องทดสอบ cache behavior ให้ใช้ API ล้าง cache อย่างระมัดระวังและเข้าใจว่า identity ของ object อาจเปลี่ยน การเปลี่ยน path ระหว่างงาน production ยังทำให้ process เดียวเห็น timezone คนละรุ่น จึงควรกำหนดก่อนรับ traffic
บนระบบที่ไม่มี IANA database, package tzdata จาก PyPI เป็น fallback ที่โครงการ Python ดูแล แต่การเลือกใช้ต้องล็อกเวอร์ชันตามนโยบาย deploy อย่า download ตอน runtime แบบเงียบ ๆ เพราะทำให้ reproducibility และ supply-chain review หายไป
Recap
- เก็บ TZPATH เดิมก่อน reset
- restore ใน finally ทุกครั้ง
- จำไว้ว่า cache ของ ZoneInfo เป็นอีกเรื่องหนึ่ง
- ตั้ง path ตอนเริ่มโปรเซส ไม่เปลี่ยนกลาง traffic