Format apa untuk timestamp di JSON
Intinya: Angka epoch dan string ISO masing-masing punya trade-off, tetapi mencampurnya itulah yang benar-benar merusak. Pakai ISO 8601 dengan offset, simpan UTC, render di zona waktu pengguna.

Intinya: pakai ISO 8601 dengan offset eksplisit di wire, simpan UTC dengan Z di akhir, dan konversi hanya saat tampilan; jika memilih angka epoch, tetapkan detik versus milidetik secara global dan taruh satuannya di nama field.
Mengapa 2026-10-30 14:30:00 tidak cukup
String itu tidak membawa zona. Pukul 14:30 di Shanghai dan 14:30 di London terpaut delapan jam, dan tidak ada cara mengetahui mana yang dimaksud. new Date('2026-10-30 14:30:00') mem-parsing di zona lokal runtime, sehingga server dan browser menurunkan dua instan berbeda dari satu payload — jenis bug yang tidak pernah dapat direproduksi.
2026-10-30 telanjang sama sekali bukan instan. Cocok untuk ulang tahun dan periode penagihan, salah untuk waktu pembuatan.
Dua format yang bisa dipakai
String ISO 8601
{
"createdAt": "2026-10-30T14:30:00+08:00",
"updatedAt": "2026-10-30T06:30:00Z"
}
Terbaca, dapat diurutkan bila formatnya konsisten, presisi milidetik bila perlu, dan mendeskripsikan dirinya sendiri.
Angka epoch
{ "createdAt": 1793519400 }
Ringkas dan tidak ambigu, tetapi tidak terbaca, dan detik versus milidetik adalah bahaya permanen. Jika memilih epoch, standarkan satuannya dan taruh di nama field: createdAtMs jauh lebih aman daripada createdAt.
Konvensi yang layak ditetapkan lebih awal
| Item | Konvensi |
|---|---|
| Format wire | ISO 8601 dengan Z atau +08:00 |
| Zona penyimpanan | UTC, sehingga DST tidak pernah masuk hitungan |
| Presisi | Milidetik sudah cukup |
| Penamaan field | createdAt, updatedAt, expiresAt |
| Tanggal murni | Field date terpisah, misalnya birthday: "1990-01-01" |
| Durasi | Integer plus satuan, misalnya timeoutMs: 3000 |
Rendering
new Intl.DateTimeFormat('en-GB', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: 'Europe/London',
}).format(new Date('2026-10-30T06:30:00Z'));
Tentukan timeZone secara eksplisit saat tampilan tidak boleh mengikuti perangkat. Mengandalkan default browser benar untuk waktu yang menghadap pengguna dan salah untuk laporan.
Tiga bug yang berulang
Tanggal telanjang ter-parse sebagai tengah malam UTC. Menurut spesifikasi ECMAScript, string tanggal saja adalah UTC sementara string tanggal-waktu adalah lokal. Inkonsistensi itu adalah sumber bug selisih satu hari yang andal.
Zona database tidak sesuai dengan serializer. datetime di MySQL tidak punya zona; tulis lokal, baca sebagai UTC, dan semuanya bergeser sebesar offset.
Daylight saving. Menyimpan waktu lokal di masa depan menciptakan instan yang tidak ada atau terjadi dua kali. UTC tidak punya celah seperti itu.
FAQ
Bagaimana saya harus memilih antara ISO 8601 dan angka epoch?
Pakai ISO 8601 saat manusia membaca payload, saat Anda menginginkan urutan leksikal, atau saat nilainya harus membawa zonanya sendiri; biayanya sekitar selusin byte tambahan dan library parsing. Pakai angka epoch saat kerampingan dan penanganan lintas-bahasa yang sepele lebih penting, tetapi tetapkan detik versus milidetik secara global dan sebutkan satuan apa yang dibawa field itu.
Haruskah tanggal telanjang dan timestamp berbagi field yang sama?
Tidak. 2026-10-30 telanjang adalah hari kalender tanpa waktu dan tanpa zona, sementara field timestamp diharapkan membawa instan eksak. Simpan ulang tahun dan periode penagihan di field date terpisah, dan gunakan field At ISO 8601 untuk waktu pembuatan atau pembaruan.