Unix Timestamp กับ ISO 8601: แบบไหนดีกว่ากันนะ?

นักพัฒนาเปรียบเทียบรูปแบบ Unix timestamp และ ISO 8601 สำหรับใช้งาน API และฐานข้อมูล

ถ้าคุณเคยต้องเชื่อมต่อระบบสองตัวที่เก็บข้อมูลวันที่ต่างรูปแบบกัน คุณคงรู้ดีว่ามันปวดหัวแค่ไหน API ตัวหนึ่งส่งมาเป็น 1714521600 อีกตัวส่งมาเป็น 2024-05-01T00:00:00Z แล้วคุณก็ต้องนั่งเขียน logic แปลงค่าตอนเที่ยงคืน การเลือกใช้ unix timestamp หรือ ISO 8601 ให้ถูกตั้งแต่แรกช่วยประหยัดเวลา debug ได้หลายชั่วโมง และป้องกัน bug เงียบๆ ที่แฝงอยู่ใน production ทั้งสองรูปแบบต่างก็ถูกใช้งานกันอย่างแพร่หลาย มีจุดแข็งของตัวเอง และไม่มีอันไหน "ดีกว่า" อีกอันในทุกสถานการณ์ สิ่งสำคัญคือต้องเข้าใจว่าแต่ละรูปแบบเหมาะกับงานแบบไหน และทำไมการเลือกผิดถึงสร้างปัญหาจริงๆ ครับ

สรุปประเด็นสำคัญ:

  • Unix timestamp คือ integer ที่นับจำนวนวินาที (หรือมิลลิวินาที) ตั้งแต่วันที่ 1 มกราคม 1970 UTC เหมาะสำหรับการคำนวณ การเก็บข้อมูล และ API
  • ISO 8601 คือมาตรฐาน string รูปแบบวันที่-เวลาที่อ่านได้ด้วยมนุษย์ เหมาะสำหรับ log ไฟล์ หน้าจอผู้ใช้ และการแลกเปลี่ยนข้อมูลระหว่างระบบ
  • ทั้งสองรูปแบบเสริมกัน ไม่ได้แข่งกัน ระบบ production ส่วนใหญ่เก็บเป็น Unix timestamp ภายใน แต่เปิดเผยออกมาเป็น ISO 8601
  • การเลือกรูปแบบผิดบริบทนำไปสู่ bug เรื่อง timezone ข้อผิดพลาดในการ parse และความซับซ้อนที่ไม่จำเป็น

Unix Timestamp คืออะไร?

Unix timestamp (หรือที่เรียกว่า Unix time หรือ epoch time) คือ integer ตัวเดียวที่แทนจำนวนวินาทีที่ผ่านไปนับตั้งแต่ Unix epoch ซึ่งก็คือวันที่ 1 มกราคม 1970 เวลา 00:00:00 UTC รูปแบบนี้ไม่ขึ้นกับ timezone โดยนิยาม เพราะอ้างอิง UTC เสมอ จึงไม่มีความกำกวมเรื่องเวลาออมแสงหรือ offset ของแต่ละภูมิภาค

ตัวอย่างเช่น Unix timestamp 1714521600 แทนช่วงเวลาที่แน่นอนช่วงหนึ่ง ไม่ว่าจะอ่านจากที่ไหนในโลกก็ได้ค่าเดียวกัน ระบบสมัยใหม่มักขยายความละเอียดไปถึงมิลลิวินาที (1714521600000) หรือไมโครวินาที อ่านเพิ่มเติมเกี่ยวกับความแตกต่างเหล่านี้ได้ในคู่มือ วินาที vs มิลลิวินาที vs ไมโครวินาทีใน Unix timestamp

ในทางเทคนิค Unix timestamp คือตัวเลขธรรมดาๆ ตัวเดียว ความเรียบง่ายนี้เป็นทั้งจุดแข็งที่ยิ่งใหญ่ที่สุด และต้นตอของปัญหาด้านการอ่านค่าในเวลาเดียวกันครับ

อ่านพื้นหลังเพิ่มเติมเกี่ยวกับที่มาของแนวคิดนี้ได้ที่ บทความเกี่ยวกับ epoch time และรากฐานของมัน

รูปแบบวันที่ ISO 8601 คืออะไร?

ISO 8601 คือมาตรฐานสากลที่เผยแพร่โดย องค์การระหว่างประเทศว่าด้วยการมาตรฐาน ที่กำหนดวิธีแสดงวันที่และเวลาในรูปแบบ string รูปแบบ datetime ตาม ISO 8601 ทั่วไปหน้าตาแบบนี้: 2024-05-01T00:00:00Z

แยกส่วนประกอบออกมาได้ดังนี้:

  • 2024-05-01 — วันที่ในรูปแบบ YYYY-MM-DD
  • T — ตัวคั่นระหว่างวันที่และเวลา
  • 00:00:00 — เวลาในรูปแบบ HH:MM:SS
  • Z — ระบุว่าเป็น UTC (สามารถใช้ offset เช่น +05:30 แทนได้)

ISO 8601 เป็นรากฐานของ มาตรฐาน RFC 3339 ที่ใช้กันอย่างแพร่หลายในโปรโตคอลอินเทอร์เน็ต อ่านได้ด้วยมนุษย์ เรียงลำดับได้ในรูปแบบ string และไม่มีความกำกวมข้ามภูมิภาค ต่างจากการเขียน "05/01/2024" ซึ่งหมายถึง 1 พฤษภาคมในสหรัฐอเมริกา แต่หมายถึง 5 มกราคมในยุโรป ISO 8601 สื่อสารได้ชัดเจนทั่วโลกครับ

เปรียบเทียบความแตกต่างหลัก

คุณสมบัติ Unix Timestamp ISO 8601
ชนิดข้อมูล Integer (หรือ float) String
อ่านได้ด้วยมนุษย์ ไม่ได้ ได้
การจัดการ timezone UTC เสมอ (โดยปริยาย) ระบุ offset หรือ Z ชัดเจน
เหมาะกับการคำนวณ ใช่ (ลบ เปรียบเทียบได้ทันที) ไม่ (ต้อง parse ก่อน)
ขนาดที่เก็บ เล็ก (4-8 bytes) ใหญ่กว่า (20+ ตัวอักษร)
เรียงลำดับได้ทันที ใช่ (เรียงตามตัวเลข) ใช่ (เรียงแบบ lexicographic)
ปลอดภัยข้ามภาษา/ภูมิภาค ใช่ ใช่

ควรใช้ Unix Timestamp เมื่อไหร่?

Unix timestamp โดดเด่นในสถานการณ์ที่ชัดเจนและเฉพาะเจาะจง ควรใช้เมื่อ:

1. คำนวณระยะเวลา

การคำนวณช่วงเวลาด้วย Unix timestamp ทำได้ง่ายมาก แค่ลบ integer สองตัว ก็รู้ว่าผ่านไปกี่วินาทีแล้ว ในขณะที่ถ้าใช้ ISO 8601 string ต้อง parse ทั้งสองค่าเป็น datetime object ก่อน แล้วค่อยคำนวณ สำหรับการทำงานที่ความถี่สูง เช่น บันทึก event หลายล้านรายการ overhead จากการ parse สะสมกันได้มากครับ

2. เก็บวันที่ในฐานข้อมูล

คอลัมน์ integer สร้าง index และเปรียบเทียบได้เร็วกว่าคอลัมน์ string ถ้าต้องรัน query เช่น "ดึง event ทั้งหมดใน 7 วันที่ผ่านมา" การเปรียบเทียบ integer สองตัวมีประสิทธิภาพกว่าการ parse และเปรียบเทียบ string คู่มือละเอียดเรื่อง Unix timestamp ในฐานข้อมูล ของเราครอบคลุมกลยุทธ์การสร้าง index และรูปแบบ query อย่างละเอียด

3. สื่อสารระหว่าง internal service

เมื่อ backend service สองตัวที่คุณควบคุมเองต้องส่ง timestamp ให้กัน รูปแบบ Unix ช่วยลดความซับซ้อนในการ parse ทั้งสองฝั่งตกลงกันบน integer contract และไม่มีความเสี่ยงที่จะตีความ timezone string ผิดพลาด

4. ลอจิกการหมดอายุและ TTL

JWT token, cache entry, และการหมดอายุของ session แทบทั้งหมดใช้ Unix timestamp field exp ใน JSON Web Token (JWT) เป็น Unix timestamp ด้วยเหตุผลนี้พอดี เพราะการเปรียบเทียบ exp > Date.now() / 1000 เป็นแค่การเปรียบเทียบ integer ครั้งเดียว รวดเร็วมาก

5. หลีกเลี่ยง bug เรื่อง timezone

เพราะ Unix timestamp เป็น UTC เสมอ จึงขจัด bug ทั้งกลุ่มที่เกิดจากเวลาออมแสงออกไปได้ ถ้าแอปพลิเคชันของคุณให้บริการผู้ใช้หลาย timezone การเก็บ Unix timestamp แล้วแปลงเป็นเวลาท้องถิ่นเฉพาะตอนแสดงผลเป็น architectural pattern ที่ได้รับการพิสูจน์แล้วว่าใช้งานได้ดีครับ

ควรระวัง ปัญหาปี 2038 ถ้าใช้ signed integer 32-bit เก็บ Unix timestamp ควรใช้ integer 64-bit ในระบบสมัยใหม่เสมอนะครับ

ควรใช้ ISO 8601 เมื่อไหร่?

ISO 8601 ชนะในบริบทที่มนุษย์หรือระบบภายนอกต้องอ่าน เขียน หรือตรวจสอบวันที่โดยไม่ต้องรันโค้ดครับ

1. API response สำหรับบุคคลภายนอก

ถ้าคุณกำลังสร้าง public API การส่งกลับ "created_at": "2024-05-01T12:30:00Z" เป็นมิตรกับนักพัฒนามากกว่า "created_at": 1714562200 มาก นักพัฒนาภายนอกเข้าใจค่าได้ทันทีโดยไม่ต้องแปลง คู่มือสไตล์ API หลายฉบับ รวมถึงของ Stripe และ GitHub ใช้ ISO 8601 เป็นค่าเริ่มต้นด้วยเหตุผลนี้

2. Log ไฟล์และ audit trail

Log ถูกอ่านโดยมนุษย์ระหว่างเกิดเหตุการณ์ฉุกเฉิน บรรทัด log ที่ขึ้นต้นด้วย [2024-05-01T14:22:05Z] ERROR: payment failed สามารถนำไปใช้งานได้ทันที แต่ถ้าเป็น [1714569725] ERROR: payment failed ผู้อ่านต้องแปลง timestamp ก่อนถึงจะเริ่ม debug ได้ครับ

3. การรองรับหลายภาษาและหลายภูมิภาค

ISO 8601 มีข้อมูล timezone offset ชัดเจน เมื่อระบบต้องเก็บเวลาท้องถิ่นดั้งเดิมของผู้ใช้ เช่น event ในปฏิทินที่สร้างเวลา 9:00 น. ที่โตเกียว ISO 8601 พร้อม offset ที่ถูกต้อง (2024-05-01T09:00:00+09:00) จะเก็บ intent นั้นไว้ได้ Unix timestamp เพียงอย่างเดียวไม่สามารถบอกได้ว่าผู้ใช้อยู่ใน timezone ไหนตอนสร้าง event

4. ไฟล์ config และรูปแบบแลกเปลี่ยนข้อมูล

ไฟล์ JSON, YAML, และ CSV ที่มนุษย์แก้ไขเองควรใช้ ISO 8601 ถ้านักพัฒนาต้องกำหนดวันหมดอายุในไฟล์ config ด้วยตนเอง การเขียน 2025-01-01T00:00:00Z มีโอกาสผิดพลาดน้อยกว่าการคำนวณและพิมพ์ Unix timestamp เองมากครับ

ตัวอย่างโค้ดใน JavaScript และ Python

JavaScript: แปลงระหว่างสองรูปแบบ

// ดึง Unix timestamp ปัจจุบัน (หน่วยวินาที)
const unixNow = Math.floor(Date.now() / 1000);
console.log(unixNow); // เช่น 1714521600

// แปลง Unix timestamp เป็น ISO 8601 string
const isoString = new Date(unixNow * 1000).toISOString();
console.log(isoString); // "2024-05-01T00:00:00.000Z"

// แปลง ISO 8601 string กลับเป็น Unix timestamp
const parsed = new Date("2024-05-01T00:00:00Z");
const backToUnix = Math.floor(parsed.getTime() / 1000);
console.log(backToUnix); // 1714521600

// คำนวณระยะเวลาระหว่าง Unix timestamp สองตัว (ไม่ต้อง parse)
const start = 1714521600;
const end = 1714608000;
const durationSeconds = end - start;
console.log(`Duration: ${durationSeconds / 3600} hours`); // 24 hours

Python: ทำงานกับทั้งสองรูปแบบ

import time
from datetime import datetime, timezone

# ดึง Unix timestamp ปัจจุบัน
unix_now = int(time.time())
print(unix_now)  # เช่น 1714521600

# แปลง Unix timestamp เป็น ISO 8601 string
dt = datetime.fromtimestamp(unix_now, tz=timezone.utc)
iso_string = dt.isoformat()
print(iso_string)  # "2024-05-01T00:00:00+00:00"

# แปลง ISO 8601 string กลับเป็น Unix timestamp
parsed_dt = datetime.fromisoformat("2024-05-01T00:00:00+00:00")
back_to_unix = int(parsed_dt.timestamp())
print(back_to_unix)  # 1714521600

# คำนวณระยะเวลา - ง่ายมากด้วย Unix timestamp
start = 1714521600
end = 1714608000
duration_hours = (end - start) / 3600
print(f"Duration: {duration_hours} hours")  # 24.0 hours

สำคัญ: ใน Python ควรส่ง tz=timezone.utc เสมอเมื่อเรียก datetime.fromtimestamp() ถ้าไม่ระบุ Python จะใช้ timezone ของระบบ ซึ่งอาจให้ผลลัพธ์ผิดพลาดบนเซิร์ฟเวอร์ที่อยู่ต่าง timezone กันครับ

ตัวอย่างจริง: ระบบจองห้องพัก

สมมติว่าคุณกำลังสร้าง API สำหรับระบบจองโรงแรม ผู้ใช้ในนิวยอร์กจองห้องพักสำหรับเช็คอินวันที่ 15 มิถุนายน 2024 เวลา 15:00 น. ตามเวลาท้องถิ่น ลองดูว่าทั้งสองรูปแบบทำงานต่างกันอย่างไรในทางปฏิบัติครับ

เก็บเป็น Unix timestamp: คุณแปลงเวลาท้องถิ่นของผู้ใช้เป็น UTC แล้วเก็บ 1718470800 กะทัดรัดและ query ได้รวดเร็ว แต่เมื่อพนักงานโรงแรมในนิวยอร์กเปิดดู record ดิบในฐานข้อมูล จะเห็นแค่ตัวเลข ต้องใช้เครื่องมือแปลงถึงจะรู้ว่าหมายถึงเวลาอะไร ยิ่งกว่านั้น ถ้าลืมแปลงจากเวลาท้องถิ่นเป็น UTC ก่อนเก็บ จะเกิด bug เงียบๆ ที่คลาดเคลื่อนไป 4 ชั่วโมง (นิวยอร์กคือ UTC-4 ในช่วงฤดูร้อน)

เก็บเป็น ISO 8601: คุณเก็บ 2024-06-15T15:00:00-04:00 offset ถูกเก็บไว้ครบ พนักงานอ่าน record ได้โดยตรง intent ของ timezone ดั้งเดิมไม่สูญหาย แต่การเปรียบเทียบ string ใน SQL ช้ากว่าเล็กน้อย และการคำนวณ "อีกกี่ชั่วโมงถึงจะเช็คอิน" ต้อง parse string ก่อนครับ

วิธีที่ทีม production ส่วนใหญ่ใช้: เก็บ Unix timestamp ในฐานข้อมูลเพื่อประสิทธิภาพและความถูกต้อง แล้วส่งกลับเป็น ISO 8601 string ใน API response เพื่อความสะดวกในการใช้งาน นี่คือ pattern ที่แพลตฟอร์มใหญ่ๆ ใช้กัน คุณจะได้ประโยชน์จากทั้งสองรูปแบบพร้อมกัน

อ่านคู่มือรูปแบบการแปลงค่าแบบครบถ้วนได้ที่ คู่มือการแปลง Unix timestamp เป็นวันที่ฉบับสมบูรณ์

สรุปคำแนะนำตามกรณีใช้งาน

อิงจากข้อจำกัดในโลกจริง นี่คือคำแนะนำตรงๆ สำหรับแต่ละสถานการณ์:

  • การเก็บข้อมูลในฐานข้อมูล: ใช้ Unix timestamp (integer) สร้าง index ได้เร็วกว่า ไม่ต้อง parse timezone ใช้พื้นที่น้อยกว่า
  • การสื่อสารระหว่าง microservice ภายใน: ใช้ Unix timestamp ทั้งสองฝั่งควบคุม contract เองและไม่มีมนุษย์อ่าน payload ดิบ
  • Public REST API response: ใช้ ISO 8601 นักพัฒนาภายนอกต้องการค่าที่อ่านได้และอธิบายตัวเองได้
  • Log ไฟล์และ audit trail: ใช้ ISO 8601 มนุษย์อ่าน log ภายใต้ความกดดันระหว่างเกิดเหตุการณ์ฉุกเฉิน
  • JWT และการหมดอายุของ session: ใช้ Unix timestamp ข้อกำหนดกำหนดให้ใช้และการเปรียบเทียบทำได้ในขั้นตอนเดียว
  • ไฟล์ config และงาน scheduled: ใช้ ISO 8601 มนุษย์เขียนและแก้ไขไฟล์เหล่านี้โดยตรง
  • ฟีเจอร์ปฏิทินและการจัดตารางเวลา: ใช้ ISO 8601 พร้อม timezone offset ชัดเจน เพื่อเก็บ intent ของ timezone ดั้งเดิมของผู้ใช้ไว้
  • การคำนวณวันที่ใน application logic: แปลงเป็น Unix timestamp ก่อน คำนวณ แล้วค่อยแปลงกลับถ้าจำเป็น

สำหรับแนวปฏิบัติที่ดีในการทำงานกับ timestamp ใน backend code อ่านเพิ่มเติมได้ที่ บทเรียน Unix timestamp สำหรับนักพัฒนา ซึ่งครอบคลุม pattern การเก็บข้อมูล การจัดรูปแบบ และการจัดการ timezone อย่างละเอียดครับ

สรุป

การถกเถียงระหว่าง Unix timestamp กับ ISO 8601 ไม่ใช่เรื่องว่าอันไหนดีกว่ากัน แต่เป็นเรื่องของการเลือกเครื่องมือให้ตรงกับงาน Unix timestamp เหมาะกับคอลัมน์ในฐานข้อมูล contract ระหว่าง internal service และลอจิกการหมดอายุ ส่วน ISO 8601 เหมาะกับ API response, log ไฟล์ และไฟล์ที่มนุษย์อาจเปิดอ่าน ระบบ production ที่แข็งแกร่งส่วนใหญ่ใช้ทั้งสองอย่าง: เก็บเป็น Unix timestamp แล้วเปิดเผยออกมาเป็น ISO 8601 ถ้าคุณจำ pattern เดียวนี้ได้ คุณจะหลีกเลี่ยง bug การจัดการวันที่ที่พบบ่อยที่สุดได้ก่อนที่มันจะถึง production ครับ

เครื่องมือแปลง Unix Timestamp ฟรี - แปลงระหว่าง Unix time และ ISO 8601 ได้ทันที

หยุดเดาว่าควรใช้รูปแบบวันที่แบบไหน

ลองใช้เครื่องมือแปลง Unix Timestamp ฟรีของเราที่ unixtimestamp.app แปลงระหว่าง Unix time และ ISO 8601 ได้ทันที ไม่ต้องเขียนโค้ด แค่วาง timestamp แล้วรับวันที่ที่อ่านได้ภายในไม่กี่วินาทีครับ

ลองใช้เครื่องมือฟรีของเรา →

ได้ครับ และฐานข้อมูลหลายตัวรองรับชนิดข้อมูล datetime แบบ native ที่เก็บ ISO 8601 ภายใน อย่างไรก็ตาม Unix timestamp แบบ integer โดยทั่วไปเร็วกว่าสำหรับ range query และการเปรียบเทียบ index สำหรับตารางที่มีปริมาณข้อมูลสูงและกรองตามวันที่บ่อย integer timestamp ให้ข้อได้เปรียบด้านประสิทธิภาพที่วัดได้จริงเมื่อเทียบกับคอลัมน์ string หรือ datetime

Unix timestamp เป็น UTC เสมอโดยนิยาม ไม่มีการเก็บข้อมูล timezone ไว้ในตัว หากต้องการแสดง Unix timestamp ตาม timezone ท้องถิ่นของผู้ใช้ ให้แปลงที่ presentation layer นี่คือข้อได้เปรียบจริงๆ เพราะค่าที่เก็บไว้ไม่มีความกำกวมเลย และการแปลง timezone ถูกจัดการอย่างชัดเจนในจุดที่ควรจัดการครับ

Unix timestamp แบบวินาที (เช่น 1714521600) คือรูปแบบดั้งเดิมที่ใช้ในระบบ Unix ส่วนใหญ่และมาตรฐานต่างๆ เช่น JWT ส่วนแบบมิลลิวินาที (เช่น 1714521600000) พบบ่อยใน JavaScript และสภาพแวดล้อม browser ควรตรวจสอบเสมอว่า API ที่ใช้งานต้องการความละเอียดแบบไหน เพราะถ้าส่งวินาทีไปในขณะที่ต้องการมิลลิวินาที วันที่ที่ได้จะคลาดเคลื่อนไปถึง 1,000 เท่าในอดีตครับ

RFC 3339 คือ profile ของ ISO 8601 ที่ออกแบบมาเฉพาะสำหรับการใช้งานบนอินเทอร์เน็ต มีข้อกำหนดเข้มงวดกว่าเล็กน้อย: กำหนดให้ต้องมี timezone offset (เช่น Z หรือ +00:00) และไม่อนุญาตฟีเจอร์บางอย่างที่ ISO 8601 รองรับ ในทางปฏิบัติ นักพัฒนาส่วนใหญ่ถือว่าทั้งสองใช้แทนกันได้สำหรับ datetime string มาตรฐานอย่าง 2024-05-01T00:00:00Z ครับ

GitHub ใช้ ISO 8601 string ใน REST API response ส่วน Stripe ใช้ Unix timestamp (integer) ใน API ของตัวเอง ทั้งสองการเลือกเป็นไปโดยตั้งใจและสอดคล้องกับกรณีใช้งานของแต่ละฝ่าย นี่แสดงให้เห็นว่าไม่มีกฎตายตัวในระดับอุตสาหกรรม การเลือกที่ถูกต้องขึ้นอยู่กับกลุ่มเป้าหมายของ API และการดำเนินการที่ผู้ใช้งานต้องทำกับค่าเหล่านั้นครับ