Menu

Time di Golang: Now, Sleep, Format, Parse, dan Duration

Cara bekerja dengan tanggal dan waktu di Go: time.Now dan time.Sleep, aritmetika Duration, layout acuan 2006-01-02 15:04:05 untuk Format dan Parse, zona waktu, timestamp Unix, serta timer dan ticker.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Dasarnya dalam satu program

time.Now() mengembalikan waktu lokal saat ini, time.Sleep menjeda goroutine yang sedang berjalan, time.Since mengukur waktu yang sudah berlalu, dan time.Date membangun sebuah momen tertentu. Bagian selanjutnya di halaman ini membahas setiap bagian satu per satu. Contoh-contohnya memakai tanggal tetap dan UTC, sehingga output-nya sama di mana pun kamu menjalankannya.

Sleep dan Duration

time.Duration adalah int64 yang menghitung nanodetik. Package ini mendefinisikan konstanta untuk membuat nilai yang mudah dibaca:

KonstantaNilai
time.Nanosecond1
time.Microsecond1000 ns
time.Millisecond1000 µs
time.Second1000 ms
time.Minute60 s
time.Hour60 min

Tidak ada time.Day, karena satu hari tidak selalu 24 jam ketika zona waktu berganti untuk daylight saving. Pakai AddDate untuk hari kalender (lihat di bawah).

Ada dua bug umum yang muncul karena Duration adalah integer:

  • time.Sleep(5) tidur selama 5 nanodetik. Selalu kalikan dengan satuan: time.Sleep(5 * time.Second).
  • time.Sleep(n * time.Second) tidak bisa dikompilasi kalau n adalah variabel int. Konversikan: time.Duration(n) * time.Second. Konstanta seperti 5 bisa dipakai tanpa konversi karena konstanta tanpa tipe menyesuaikan diri dengan tipe Duration.

ParseDuration menerima ns, us (atau µs), ms, s, m, dan h, yang bisa digabung seperti "2h45m" atau "1.5s". Tidak ada satuan untuk hari.

Format: layout acuan 2006-01-02

Go tidak memakai %Y-%m-%d atau yyyy-MM-dd. Layout adalah waktu acuan

Mon Jan 2 15:04:05 MST 2006

yang ditulis sesuai bentuk output yang kamu inginkan. Nilai-nilainya dipilih agar masing-masing unik: bulan 1, tanggal 2, jam 3 (atau 15), menit 4, detik 5, tahun 6 (2006), offset zona -7 (-0700). Bacalah sebagai 01/02 03:04:05PM '06 -0700.

Token layout yang paling sering kamu butuhkan:

TokenArtiContoh
2006 / 06tahun, 4 atau 2 digit2026 / 26
01 / 1 / Jan / Januarybulan03 / 3 / Mar / March
02 / 2 / _2tanggal dalam bulan (diisi nol, polos, diisi spasi)05 / 5 / " 5"
Mon / MondayhariThu / Thursday
15jam, format 24 jam09
03 / 3jam, format 12 jam09 / 9
04 / 4menit07 / 7
05 / 5detik03 / 3
PM / pmpenanda AM atau PMAM
.000 / .999pecahan detik (tetap / nol di belakang dibuang).250 / .25
MSTsingkatan zonaUTC
-0700 / -07:00offset zona dalam angka+0000 / +00:00
Z07:00seperti -07:00, tetapi mencetak Z untuk UTCZ

Layout yang sudah tersedia:

KonstantaLayout
time.RFC33392006-01-02T15:04:05Z07:00 (pakai ini untuk API dan JSON)
time.RFC3339Nano2006-01-02T15:04:05.999999999Z07:00
time.DateTime (Go 1.20)2006-01-02 15:04:05
time.DateOnly (Go 1.20)2006-01-02
time.TimeOnly (Go 1.20)15:04:05
time.Kitchen3:04PM
time.RFC1123Mon, 02 Jan 2006 15:04:05 MST (tanggal HTTP memakai http.TimeFormat)

Kesalahan klasiknya adalah menulis layout dengan angka yang salah, misalnya "2023-01-01". Go tidak menolaknya. Go menyalin karakter yang tidak ia kenali dan mengganti karakter yang ia kenali: setiap 2 adalah tanggal, 3 adalah jam dalam format 12 jam, dan kedua 01 adalah bulan, jadi 5 Maret pukul 9.07 diformat menjadi 5059-03-03. Layout seperti "YYYY-MM-DD" sama sekali tidak berisi token, jadi dicetak apa adanya. Kalau tanggal yang diformat terlihat aneh, periksa apakah layout-nya memakai nilai acuan dengan tepat.

Parse string menjadi waktu

time.Parse(layout, value) memakai layout yang sama, dan mengembalikan error yang wajib kamu periksa:

Kalau input-nya tidak berisi zona, Parse mengembalikan UTC. String jam dinding yang sama bisa berarti momen yang berbeda tergantung zonanya, dan itulah alasan ParseInLocation ada. Pesan error-nya menyebut bagian yang gagal dicocokkan, yang membantu saat kamu sedang debug layout.

Zona waktu

time.Time adalah sebuah momen ditambah lokasi yang dipakai untuk tampilan. Mengganti lokasi dengan In mengubah cara waktu itu dicetak, bukan momennya.

  • time.UTC selalu tersedia. Simpan dan kirim waktu dalam UTC (atau RFC 3339 dengan offset), dan konversikan hanya untuk tampilan.
  • time.Local adalah zona milik mesin. Di server dan container, zona ini sering UTC, sedangkan di laptop tidak, jadi kode yang bergantung padanya berperilaku berbeda di setiap tempat.
  • time.LoadLocation("Europe/Berlin") membaca database IANA dari sistem operasi. Image container yang minimal sering tidak memilikinya, dan panggilan itu lalu mengembalikan error. Blank import _ "time/tzdata" menanamkan database tersebut ke binary-mu (sekitar 450 KB) sehingga selalu berhasil. Selalu tangani error-nya.
  • time.FixedZone(name, offsetSeconds) membuat zona dengan offset tetap. Zona ini tidak punya aturan daylight saving, jadi pakai untuk offset yang kamu terima, bukan untuk wilayah bernama.

Aritmetika dan perbandingan

Hal yang perlu diperhatikan di output-nya:

  • AddDate(0, 1, 0) pada 31 Januari menghasilkan 3 Maret, bukan 28 Februari. Go menambahkan satu bulan sehingga menjadi "31 Februari", lalu menormalkan kelebihannya. Kalau kamu butuh "tanggal yang sama bulan depan, dibatasi sampai akhir bulan", tulis logikanya sendiri.
  • Sub mengembalikan Duration, yang batas maksimalnya sekitar 292 tahun. Untuk selisih dalam hari kalender, bandingkan tanggal pada tengah malam UTC dan bagi dengan 24 jam.
  • Untuk mendapatkan awal hari, bangun ulang waktunya dari Date(). t.Truncate(24 * time.Hour) membulatkan relatif terhadap zero time dalam UTC, jadi hasilnya salah untuk zona apa pun selain UTC.

Bandingkan dengan Equal, Before, After, jangan pernah dengan ==. time.Now() menyertakan pembacaan jam monotonik, yang dipakai agar time.Since tetap benar kalau jam dinding disesuaikan. == ikut membandingkan pembacaan itu dan lokasinya, jadi dua nilai Time untuk momen yang sama bisa dianggap tidak sama. Dengan alasan yang sama, jangan pakai time.Time sebagai key map tanpa menormalkannya lebih dulu (t.UTC().Round(0) membuang pembacaan monotoniknya).

Zero value time.Time adalah 1 Januari tahun 1, pukul 00.00 UTC. Periksa dengan t.IsZero().

Mengukur waktu yang berlalu

start := time.Now()
doWork()
log.Printf("doWork took %v", time.Since(start))

time.Since(start) sama dengan time.Now().Sub(start), dan time.Until(deadline) sama dengan deadline.Sub(time.Now()). Keduanya memakai jam monotonik jika tersedia, jadi aman dari perubahan jam sistem. Untuk benchmark kode, pakai dukungan benchmark Go di package testing, bukan mengukur waktu secara manual.

Timer dan ticker

time.After(d) mengembalikan channel yang menerima satu kali setelah d. time.Timer adalah hal yang sama dengan tambahan method Stop. time.Ticker mengirim sebuah nilai setiap periode sampai kamu menghentikannya.

Tiga tick pada 20, 40, dan 60 ms tiba jauh sebelum timer 110 ms, jadi program berhenti setelah tick ketiga. time.AfterFunc(d, f) menjalankan f di goroutine-nya sendiri setelah d, yang praktis untuk pekerjaan tertunda yang hanya sekali.

Sejak Go 1.23, timer dan ticker yang sudah tidak direferensikan akan di-garbage collect walaupun kamu tidak pernah memanggil Stop, dan channel dari timer yang sudah dihentikan atau di-reset tidak lagi mengirim nilai basi. Memanggil Stop dengan defer tetap menjadi cara yang jelas untuk menyatakan bahwa masa hidup ticker sudah selesai. Kalau batas waktu berlaku untuk seluruh operasi, bukan hanya satu penantian, context.WithTimeout biasanya lebih enak dibaca daripada timer.

Waktu di JSON

time.Time otomatis di-marshal ke dan dari string RFC 3339 di JSON, dengan presisi nanodetik:

type Event struct {
	Name string    `json:"name"`
	At   time.Time `json:"at"`
}
// {"name":"deploy","at":"2026-09-23T14:30:00Z"}

String JSON dalam format lain akan gagal di-unmarshal. Untuk timestamp Unix atau format khusus, simpan int64 atau string lalu konversikan, atau definisikan tipe dengan UnmarshalJSON miliknya sendiri.

Kesalahan umum

  • time.Sleep(1) atau time.Sleep(n) dengan angka polos. Itu dalam nanodetik.
  • Layout dengan digit yang salah. "2023-01-01" atau "YYYY-MM-DD" bukan layout. Pakai "2006-01-02".
  • Tertukar antara menit dan bulan. Menit adalah 04, bulan adalah 01. "15:01" mencetak jam lalu bulan, bukan menit.
  • Membandingkan dengan ==. Pakai Equal.
  • Mengandalkan time.Local. Nilainya berbeda di setiap mesin. Tulis secara eksplisit dengan time.UTC atau lokasi yang sudah dimuat.
  • Mengabaikan error dari LoadLocation atau Parse. Keduanya bisa gagal pada input sungguhan. Parse yang gagal mengembalikan zero time, yang tercetak sebagai tahun 1, dan LoadLocation yang gagal mengembalikan lokasi nil yang membuat t.In(loc) panic.

Pertanyaan yang sering diajukan

Bagaimana cara melakukan sleep di Go?

Panggil time.Sleep dengan sebuah time.Duration: time.Sleep(2 * time.Second) atau time.Sleep(500 * time.Millisecond). Angka polos seperti time.Sleep(2) bisa dikompilasi, tetapi hanya tidur selama 2 nanodetik, karena Duration menghitung dalam nanodetik. Sleep hanya memblokir goroutine yang sedang berjalan.

Kenapa Go memakai 2006-01-02 15:04:05 untuk format tanggal?

Go memformat tanggal berdasarkan contoh. Layout-nya adalah waktu acuan Mon Jan 2 15:04:05 MST 2006 yang ditulis sesuai bentuk output yang kamu inginkan. Bagian-bagiannya berurutan naik dalam urutan Amerika: bulan 1, tanggal 2, jam 3 (15 dalam format 24 jam), menit 4, detik 5, tahun 6 (2006), offset zona 7 (-0700). Jadi "2006-01-02" berarti tahun-bulan-tanggal dan "02/01/2006" berarti tanggal/bulan/tahun.

Bagaimana cara parse string tanggal di Go?

Pakai time.Parse(layout, value) dengan layout yang ditulis dalam waktu acuan: t, err := time.Parse("2006-01-02", "2026-09-23"). Selalu periksa err. Kalau string-nya tidak berisi informasi zona, hasilnya dalam UTC; pakai time.ParseInLocation untuk menafsirkannya di zona lain.

Bagaimana cara mendapatkan timestamp Unix di Go?

time.Now().Unix() mengembalikan jumlah detik sejak 1 Januari 1970 UTC sebagai int64. UnixMilli(), UnixMicro(), dan UnixNano() memberi satuan yang lebih kecil. Untuk arah sebaliknya, pakai time.Unix(sec, 0) atau time.UnixMilli(ms).

Bagaimana cara membandingkan dua waktu di Go?

Pakai t1.Before(t2), t1.After(t2), dan t1.Equal(t2). Jangan pakai ==: operator itu juga membandingkan lokasi dan pembacaan jam monotonik, jadi dua nilai untuk momen yang sama bisa dianggap tidak sama. t2.Sub(t1) memberi selisihnya sebagai Duration.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai