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

time

Package time มี type หลักสองตัว:

  • time.Time — ช่วงเวลาหนึ่งที่มีความแม่นยำระดับ nanosecond พร้อม location (timezone) เสมอ
  • time.Duration — signed 64-bit integer แทนความยาวของเวลาในหน่วย nanosecond ค่าคงที่อย่าง time.Hour, time.Minute, time.Second และ time.Millisecond ทำให้การคำนวณอ่านง่าย
d := 2*time.Hour + 30*time.Minute + 15*time.Second
fmt.Println(d) // 2h30m15s

ในโค้ด production จะเรียก time.Now() เพื่อรับเวลาปัจจุบัน สำหรับการทดสอบและตัวอย่างที่ต้องการผลลัพธ์คงที่ให้ใช้ time.Date:

t := time.Date(2024, 1, 2, 15, 4, 5, 0, time.UTC)
// year, month, day, hour, min, sec, nanosec, location

ค่าของ time.Month (ตั้งแต่ time.January ถึง time.December) เป็น typed constant แต่ก็สามารถส่ง integer literal (1–12) ได้เพราะสามารถ assign ให้ time.Month ได้

Go ใช้ช่วงเวลาอ้างอิงที่เป็นรูปธรรมแทนรหัสฟอร์แมตแบบนามธรรมอย่าง YYYY-MM-DD ช่วงเวลาอ้างอิงคือ:

Mon Jan 2 15:04:05 MST 2006

หากต้องการฟอร์แมตเวลา ให้เขียนช่วงเวลาอ้างอิงในรูปแบบที่ต้องการ:

t.Format("2006-01-02") // "2024-01-02"
t.Format("15:04:05") // "15:04:05"
t.Format("02 Jan 2006 15:04 MST") // "02 Jan 2024 15:04 UTC"
t.Format(time.RFC3339) // "2024-01-02T15:04:05Z"

time.Parse เป็นการทำงานตรงข้ามกับ Format — รับ layout และ string:

parsed, err := time.Parse("2006-01-02", "2024-06-15")
// parsed คือเที่ยงคืน UTC ของวันที่ 15 มิถุนายน 2024

string ของ layout ต้องตรงกับ component ของช่วงเวลาอ้างอิงที่ใช้ — ตัวอักษรเดียวกันในตำแหน่งเดียวกัน

deadline := t.Add(72 * time.Hour) // 3 วันต่อมา
diff := deadline.Sub(t) // time.Duration: 72h0m0s
before := deadline.Before(t) // false
after := deadline.After(t) // true

Add รับ Duration และคืน Time Sub รับ Time สองค่าและคืน Duration ระหว่างทั้งสอง

package main
import (
"fmt"
"time"
)
func main() {
// Fixed time — deterministic in any interpreter
t := time.Date(2024, 1, 2, 15, 4, 5, 0, time.UTC)
fmt.Println(t)
// Formatting with the reference layout
fmt.Println(t.Format("2006-01-02"))
fmt.Println(t.Format("15:04:05"))
fmt.Println(t.Format("Mon, 02 Jan 2006 15:04:05 MST"))
fmt.Println(t.Format(time.RFC3339))
// Parsing
parsed, err := time.Parse("2006-01-02", "2024-06-15")
if err == nil {
fmt.Println(parsed.Format("January 2, 2006"))
}
// Arithmetic
deadline := t.Add(72 * time.Hour)
fmt.Println(deadline.Format("2006-01-02 15:04:05"))
diff := deadline.Sub(t)
fmt.Println(diff)
// Duration construction
d := 2*time.Hour + 30*time.Minute
fmt.Println(d)
// Accessing date parts
fmt.Println(t.Year(), t.Month(), t.Day())
fmt.Println(t.Hour(), t.Minute(), t.Second())
}
สิ่งที่ได้ประโยชน์ต้นทุน
time.Time เป็น value typeimmutable, safe to copy และ shareต้องระวัง timezone ที่แต่ละ Time carry
time.Duration (int64 nanoseconds)arithmetic ชัดเจน — 5*time.Secondต้อง multiply constant ชัดเจน ไม่ใช่แค่ “5”
time.After / time.NewTimerสร้าง timeout ง่ายtime.After leak goroutine ใน tight loop — ควรใช้ time.NewTimer
reference layout (“2006-01-02”)อ่านเข้าใจได้โดยดู exampleต่างจาก YYYY/MM/DD ของภาษาอื่น — ต้องจำ magic numbers
  • time.Now() return UTC เสมอ — ขึ้นกับ local timezone ของเครื่อง — ควรใช้ time.Now().UTC() เมื่อต้องการ UTC ชัดเจน
  • time.Sleep(1*time.Second) precise — OS scheduler อาจ sleep นานกว่าที่กำหนด เช่น 1.05s — ไม่ใช่ hard real-time
  • time.Equal เหมือน == — time.Equal เปรียบเทียบ instant ในเวลา (ignore timezone), == เปรียบเทียบ memory layout ทั้งหมดรวม timezone
  • time.After ใน loop ไม่เป็นปัญหา — time.After สร้าง channel และ goroutine ใหม่ทุกครั้ง — ใน hot loop ใช้ time.NewTimer + Reset() แทน

💡 ตัวอย่างจากของจริง

Kubernetes: pod timeout, job deadline, lease expiry ล้วนใช้ time.Duration — เช่น terminationGracePeriodSeconds คือ time.Duration

Prometheus: scrape interval และ timeout ใช้ time.Duration — alerting rule duration เช่น “5m” parse ด้วย time.ParseDuration

Go HTTP server: http.TimeoutHandler ใช้ context + time.AfterFunc สำหรับ request timeout — ตัด connection เมื่อ handler ช้าเกินกำหนด

Reference time ของ Go ที่ใช้สำหรับการฟอร์แมตคืออะไร?
การเรียกใดที่คืนค่า time.Time ใหม่ที่ 24 ชั่วโมงหลังจาก t?
t.Sub(other) คืนค่าอะไร?
ทำไมควรหลีกเลี่ยง time.Now() ใน playground / test snippet?