ส่วนขยายวันที่/เวลาแบบความละเอียดสูง
SQLite มีฟังก์ชันวันที่พื้นฐานมาให้ แต่เนื่องจากต้องการความสามารถที่มากขึ้น จึงได้สร้างส่วนขยายวันที่/เวลาแบบความละเอียดสูงชื่อ sqlean-time ขึ้นมา ส่วนขยายนี้มี API ที่เป็นโครงสร้างชัดเจนและมีฟีเจอร์หลากหลาย
หมายเหตุ การเพิ่มส่วนขยายให้ SQLite ทำได้ง่ายมาก เพียงดาวน์โหลดไฟล์แล้วรันคำสั่งฐานข้อมูลเพียงคำสั่งเดียว
แนวคิด
ส่วนขยายนี้ใช้ชนิดค่าหลัก 2 แบบ: เวลา (Time) และช่วงเวลา (Duration)
-
เวลา (Time): เป็นคู่ค่าที่ประกอบด้วยวินาทีและนาโนวินาที โดยแสดงจำนวนวินาทีหลังจากเวลา 0 (0001-01-01 00:00:00 UTC) และจำนวนนาโนวินาทีภายในวินาทีปัจจุบัน
- สามารถเก็บเวลาในรูปแบบแทนภายในได้ ซึ่งทำให้แสดงวันที่ย้อนหลังหรือไปข้างหน้าได้หลายพันล้านปีด้วยความละเอียดระดับนาโนวินาที
- ยังสามารถเก็บเวลาเป็นจำนวนวินาทีหลัง Unix epoch (1970-01-01 00:00:00 UTC) ได้ด้วย รวมถึงมิลลิวินาที ไมโครวินาที และนาโนวินาที
- เวลาจะถูกเก็บและประมวลผลเป็น UTC เสมอ แต่สามารถแปลงเป็นออฟเซ็ตเขตเวลาเฉพาะได้
-
ช่วงเวลา (Duration): เป็นตัวเลข 64 บิตในหน่วยนาโนวินาที ซึ่งแทนค่าได้ยาวประมาณ 290 ปี
การสร้างค่าเวลา
-
เวลาปัจจุบัน:
select time_fmt_iso(time_now()); -- 2024-08-06T21:22:15.431295000Z -
วันที่/เวลาที่ระบุ:
select time_fmt_iso(time_date(2011, 11, 18)); -- 2011-11-18T00:00:00Z select time_fmt_iso(time_date(2011, 11, 18, 15, 56, 35)); -- 2011-11-18T15:56:35Z
การดึงฟิลด์ของเวลา
มีฟังก์ชันสำหรับดึงฟิลด์วันที่/เวลาหลากหลายแบบ:
select 'year = ' || time_get_year(time_now());
select 'month = ' || time_get_month(time_now());
select 'day = ' || time_get_day(time_now());
เวลา Unix
ฟังก์ชันสำหรับสร้างค่าเวลาจากเวลา Unix (เวลาหลัง 1970-01-01 UTC):
select time_fmt_iso(time_unix(1321631795)); -- 2011-11-18T15:56:35Z
ฟังก์ชันสำหรับแปลงค่าเวลาเป็นเวลา Unix:
select time_to_unix(time_now()); -- 1722979335
การเปรียบเทียบเวลา
ฟังก์ชันสำหรับเปรียบเทียบค่าเวลา:
select time_after(time_now(), time_date(2011, 11, 18)); -- 1
select time_before(time_now(), time_date(2011, 11, 18)); -- 0
การคำนวณเวลา
ฟังก์ชันสำหรับบวกช่วงเวลาเข้ากับค่าเวลา:
select time_fmt_iso(time_add(time_now(), 24*dur_h())); -- 2024-08-07T21:22:15.431295000Z
ค่าคงที่ของช่วงเวลา:
dur_us()- 1 ไมโครวินาทีdur_ms()- 1 มิลลิวินาทีdur_s()- 1 วินาทีdur_m()- 1 นาทีdur_h()- 1 ชั่วโมง
การปัดค่า
ฟังก์ชันสำหรับปัดค่าเวลาให้มีความละเอียดตามฟิลด์ที่กำหนด:
select 'original = ' || time_fmt_iso(t.v) from t union all
select 'millennium = ' || time_fmt_iso(time_trunc(t.v, 'millennium')) from t;
การจัดรูปแบบ
ฟังก์ชันที่คืนค่าสตริงเวลาแบบ ISO 8601:
select time_fmt_iso(time_date(2011, 11, 18, 15, 56, 35, 666777888), 3*3600); -- 2011-11-18T18:56:35.666777888+03:00
ค่าคงที่ของช่วงเวลา
ฟังก์ชันที่คืนค่าช่วงเวลาทั่วไปในหน่วยนาโนวินาที:
select dur_ns(); -- 1
select dur_us(); -- 1000
กิตติกรรมประกาศ
ส่วนขยายนี้พัฒนาด้วย C และออกแบบกับพัฒนาบนพื้นฐานของแพ็กเกจ time ใน standard library ของ Go (BSD 3-Clause License)
การติดตั้งและวิธีใช้งาน
- ดาวน์โหลดรีลีสล่าสุด
- ใช้งานใน SQLite command-line interface:
sqlite> .load ./time sqlite> select time_now();
สรุปโดย GN⁺
- ส่วนขยาย
sqlean-timeเพิ่มความสามารถด้านวันที่/เวลาแบบความละเอียดสูงให้ SQLite ทำให้รองรับการคำนวณเวลาหลากหลายรูปแบบ - สามารถจัดการเวลาและช่วงเวลาในระดับนาโนวินาที จึงรองรับการคำนวณเวลาที่ละเอียดมาก
- มีทั้งฟังก์ชันจัดรูปแบบและเปรียบเทียบเวลาหลากหลายแบบ ทำให้นักพัฒนาใช้งานได้สะดวก
- มีความสามารถมากกว่าฟังก์ชันวันที่พื้นฐานของ SQLite อย่างชัดเจน จึงเหมาะกับโปรเจ็กต์ที่ต้องการการคำนวณเวลาที่ซับซ้อน
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
มีคำถามว่ารองรับกรณีพิเศษของการเปลี่ยนเขตเวลาและความไม่ต่อเนื่องของเวลาท้องถิ่นที่ Jon Skeet เคยอธิบายไว้หรือไม่
ไม่ควรสร้างไลบรารีวันที่/เวลาและไลบรารีเข้ารหัสลับขึ้นมาใช้เอง
การแทนค่า/ขนาดเวลาที่ต่างกันสามแบบเป็นเรื่องน่าสนใจ
การระบุให้ชัดว่าใช้ signed integer หรือไม่เป็นเรื่องสำคัญ
อยากให้ SQLite3 มีระบบชนิดข้อมูลที่ขยายต่อได้
มองว่านี่เจ๋งมาก พร้อมทั้งชี้ถึงความสามารถสำคัญที่ SQLite ยังขาดอยู่
โต้แย้งว่าฐานข้อมูลควรติดตามหน่วยด้วย
มีคำถามว่าระหว่างการแทนค่านาโนวินาทีกับปีที่อยู่นอกช่วงระดับนาโน แบบไหนมีประโยชน์กว่ากัน
เสนอให้ใช้ Unix timestamp แบบสไตล์ golang ในหน่วยนาโนวินาที โดยใช้ signed int64
โต้แย้งว่าไม่ควรใช้คำว่า "วินาทีหลัง epoch" เว้นแต่จะหมายถึงสิ่งนั้นอย่างแม่นยำ
select time_sub(time_date(2011, 11, 19), time_date(1311, 11, 18));