7 menit

Format & Konversi Waktu JavaScript: Perangkap Umum

Pelajari cara memformat dan mengonversi waktu di JavaScript tanpa kejutan: timestamp, string ISO, zona waktu, DST, aturan parsing, dan pola yang dapat diandalkan.

Format & Konversi Waktu JavaScript: Perangkap Umum

Apa yang Biasanya Salah dengan Waktu di JavaScript

Bug waktu di JavaScript jarang muncul sebagai “jam salah”. Mereka muncul sebagai pergeseran kecil yang membingungkan: tanggal yang benar di laptop Anda tapi salah di mesin rekan kerja, respons API yang tampak baik sampai dirender di zona waktu lain, atau laporan yang “melenceng satu” di sekitar perubahan musim.

Gejala yang paling umum

Anda biasanya akan melihat satu (atau lebih) dari ini:

  • Melenceng satu jam: terutama di sekitar Daylight Saving Time, atau saat sebuah nilai tak sengaja dikonversi antara waktu lokal dan UTC.
  • Melenceng satu hari: nilai hanya-tanggal (mis. "2025-12-23") muncul sebagai hari sebelumnya/berikutnya tergantung zona waktu.
  • Zona waktu salah: waktu terlihat benar, tapi offset (mis. +02:00) berbeda dari yang Anda harapkan.
  • Format tidak konsisten: "berfungsi di Chrome" tetapi terlihat berbeda di Safari, atau server dan browser tidak sepakat bagaimana mem-parse sebuah string.

Mengapa ini terjadi: "waktu" bisa bermakna berbeda

Sumber sakit yang besar adalah kata waktu bisa merujuk ke konsep berbeda:

  • Sebuah instant: momen spesifik di seluruh dunia (mis. "2025-12-23T10:00:00Z"). Ini biasanya yang Anda inginkan untuk logging, event, dan penyimpanan API.
  • Tanggal kalender: hari di kalender tanpa zona waktu (mis. ulang tahun, tanggal faktur). Menganggapnya seperti instant dapat menggesernya ke batas hari lain.
  • Waktu jam-dinding (wall-clock time): "09:00 di Berlin", yang bergantung pada aturan zona waktu dan perubahan daylight saving.

Date bawaan JavaScript mencoba mencakup semua ini, tetapi utamanya merepresentasikan instant dalam waktu sambil terus-menerus mendorong Anda ke arah tampilan lokal, sehingga konversi yang tidak disengaja mudah terjadi.

Fokus artikel ini

Panduan ini sengaja praktis: bagaimana mendapatkan konversi yang dapat diprediksi di browser dan server, cara memilih format yang lebih aman (seperti ISO 8601), dan bagaimana mengenali jebakan klasik (detik vs milidetik, UTC vs lokal, dan perbedaan parsing). Tujuannya bukan teori lebih banyak—melainkan lebih sedikit kejutan "kenapa bergeser?".

Tipe Data Waktu: Timestamp, Date, dan String

Bug waktu di JavaScript sering dimulai dengan mencampur representasi yang terlihat dapat saling ditukar, tetapi sebenarnya tidak.

Tiga representasi yang paling sering Anda lihat

1) Epoch milidetik (number)

Angka polos seperti 1735689600000 biasanya adalah "milidetik sejak 1970-01-01T00:00:00Z". Ini merepresentasikan sebuah instant dalam waktu tanpa format atau zona waktu yang terlampir.

2) Objek Date (pembungkus sebuah instant)

Date menyimpan jenis instant yang sama seperti timestamp. Bagian yang membingungkan: ketika Anda mencetak Date, JavaScript memformatnya menggunakan aturan lokal lingkungan Anda kecuali Anda meminta sebaliknya.

3) String terformat (tampilan manusia)

String seperti "2025-01-01", "01/01/2025 10:00", atau "2025-01-01T00:00:00Z" bukanlah satu hal yang tunggal. Beberapa tidak ambigu (ISO 8601 dengan Z), lainnya tergantung locale, dan beberapa tidak menyertakan zona waktu sama sekali.

"Instant dalam waktu" vs "tampilan untuk manusia"

  • Instant dalam waktu: "momen ini persis secara global" (terbaik disimpan sebagai epoch ms atau string ISO UTC).
  • Tampilan untuk manusia: "apa yang harus dilihat pengguna" (bergantung pada locale dan zona waktu).

Instant yang sama dapat ditampilkan berbeda berdasarkan zona waktu:

const instant = new Date("2025-01-01T00:00:00Z");

instant.toLocaleString("en-US", { timeZone: "UTC" });
// "1/1/2025, 12:00:00 AM"

instant.toLocaleString("en-US", { timeZone: "America/Los_Angeles" });
// "12/31/2024, 4:00:00 PM" (hari sebelumnya)

Pilih satu "sumber kebenaran"

Pilih satu representasi internal (umumnya epoch milidetik atau UTC ISO 8601) dan pertahankan di seluruh aplikasi dan API Anda. Konversi ke/dari Date dan string terformat hanya pada boundary: parsing input dan tampilan UI.

Timestamp: Detik vs Milidetik (Mudah Tercampur)

"Timestamp" biasanya berarti waktu epoch (juga disebut Unix time): jumlah waktu sejak 1970-01-01 00:00:00 UTC. Perangkapnya: sistem berbeda menghitung dalam unit yang berbeda.

Date JavaScript adalah sumber kebingungan karena menggunakan milidetik. Banyak API, database, dan log menggunakan detik.

Aturan praktis

  • Unix timestamp (detik): 1704067200
  • Timestamp JavaScript (milidetik): 1704067200000

Momen yang sama, tetapi versi milidetik punya tiga digit tambahan.

Konversi aman (detik ↔ milidetik)

Gunakan perkalian/pembagian eksplisit supaya unit jelas:

// seconds -> Date
const seconds = 1704067200;
const d1 = new Date(seconds * 1000);

// milliseconds -> Date
const ms = 1704067200000;
const d2 = new Date(ms);

// Date -> seconds
const secondsOut = Math.floor(d2.getTime() / 1000);

// Date -> milliseconds
const msOut = d2.getTime();

Bug klasik: mengoper detik ke Date()

Ini tampak masuk akal, tapi salah ketika ts dalam detik:

const ts = 1704067200;      // seconds
const d = new Date(ts);     // WRONG: treated as milliseconds

Hasilnya akan menjadi tanggal di 1970, karena 1,704,067,200 milidetik hanya sekitar 19 hari setelah epoch.

Validasi cepat dan cek debugging

Saat Anda tidak yakin unit apa yang Anda punya, tambahkan penjaga cepat:

function asDateFromUnknownEpoch(x) {
  // crude heuristic: seconds are ~1e9-1e10, milliseconds are ~1e12-1e13
  if (x < 1e11) return new Date(x * 1000); // assume seconds
  return new Date(x);                      // assume milliseconds
}

const input = Number(valueFromApi);
console.log({ input, digits: String(Math.trunc(input)).length });
console.log('as ISO:', asDateFromUnknownEpoch(input).toISOString());

Jika jumlah "digit" sekitar 10, kemungkinan itu detik. Jika sekitar 13, kemungkinan milidetik. Juga cetak toISOString() saat debugging: itu tidak ambigu dan membantu Anda menemukan kesalahan unit seketika.

Waktu Lokal vs UTC: Mengapa Output Anda Bergeser

Date JavaScript bisa membingungkan karena menyimpan sebuah instant tunggal, tetapi bisa menampilkan instant itu dalam zona waktu berbeda.

Secara internal, Date pada dasarnya adalah "milidetik sejak epoch Unix (1970-01-01T00:00:00Z)". Angka itu merepresentasikan sebuah momen dalam UTC. Pergeseran terjadi ketika Anda meminta JavaScript memformat momen itu sebagai waktu lokal (berdasarkan pengaturan komputer/server) versus UTC.

Getter lokal vs getter UTC

Banyak API Date punya varian lokal dan UTC. Mereka mengembalikan angka berbeda untuk instant yang sama:

const d = new Date('2025-01-01T00:30:00Z');

d.getHours();      // hour in *local* time zone
d.getUTCHours();   // hour in UTC

d.toString();      // local time string
d.toISOString();   // UTC (always ends with Z)

Jika mesin Anda di New York (UTC-5), waktu UTC itu mungkin muncul sebagai "19:30" pada hari sebelumnya secara lokal. Pada server yang diatur ke UTC, ia akan muncul sebagai "00:30". Instant yang sama, tampilan berbeda.

Mengapa log terlihat "salah"

Log sering menggunakan Date#toString() atau menginterpolasi Date secara implisit, yang menggunakan zona waktu lokal lingkungan. Itu berarti kode yang sama bisa mencetak timestamp berbeda di laptop Anda, CI, dan produksi.

Panduan praktis

Simpan dan kirim waktu sebagai UTC (mis. epoch milidetik atau ISO 8601 dengan Z). Konversi ke zona waktu pengguna hanya saat menampilkan:

  • Untuk API: prefer toISOString() atau kirim epoch milidetik
  • Untuk UI: format di zona waktu pengguna menggunakan Intl.DateTimeFormat

Jika Anda membangun aplikasi dengan cepat (mis. alur kerja vibe-coding di Koder.ai), ada baiknya menetapkan ini ke dalam kontrak API yang dihasilkan sejak awal: beri nama field dengan jelas (createdAtMs, createdAtIso) dan jaga konsistensi server (Go + PostgreSQL) dan klien (React) terhadap apa yang setiap field wakili.

String ISO 8601: Format Teraman untuk API

Jika Anda perlu mengirim tanggal/waktu antar browser, server, dan database, string ISO 8601 adalah default teraman. Mereka eksplisit, didukung luas, dan (yang terpenting) membawa informasi zona waktu.

Gunakan UTC eksplisit atau offset eksplisit

Dua format pertukaran yang baik:

  • Waktu UTC (direkomendasikan saat Anda tidak peduli zona lokal): 2025-03-04T12:30:00Z
  • Waktu lokal dengan offset (direkomendasikan saat "waktu jam lokal" penting): 2025-03-04T12:30:00+02:00

Apa arti "Z"?

Z berarti Zulu time, nama lain untuk UTC. Jadi 2025-03-04T12:30:00Z adalah "12:30 di UTC."

Kapan offset seperti +02:00 penting?

Offset krusial ketika sebuah event terkait konteks zona waktu lokal (janji, booking, jam buka toko). 2025-03-04T12:30:00+02:00 menggambarkan momen yang dua jam lebih cepat dari UTC, dan itu bukan instant yang sama dengan 2025-03-04T12:30:00Z.

Hindari string tanggal ambigu

String seperti 03/04/2025 adalah jebakan: apakah itu 4 Maret atau 3 April? Pengguna dan lingkungan berbeda menafsirkannya berbeda. Lebih baik 2025-03-04 (tanggal ISO) atau datetime ISO penuh.

Round-trip aman (string → Date → string)

const iso = "2025-03-04T12:30:00Z";
const d = new Date(iso);
const back = d.toISOString();

console.log(iso);  // 2025-03-04T12:30:00Z
console.log(back); // 2025-03-04T12:30:00.000Z

Perilaku "round-trip" ini persis yang Anda inginkan untuk API: konsisten, dapat diprediksi, dan sadar zona waktu.

Jebakan Parsing: Date.parse dan Perbedaan Browser

Luncurkan di domain Anda sendiri
Publikasikan aplikasi Anda dengan domain kustom saat UI tanggal-waktu Anda siap.

Date.parse() terasa praktis: beri dia string, dapatkan timestamp. Masalahnya, untuk apa pun yang bukan ISO 8601 jelas, parsing dapat bergantung pada heuristik browser. Heuristik itu berbeda antar engine dan versi, yang berarti input yang sama bisa diparse berbeda (atau tidak sama sekali) tergantung di mana kode dijalankan.

Mengapa Date.parse() bisa bervariasi

JavaScript hanya menstandarkan parsing secara andal untuk string bergaya ISO 8601 (dan bahkan di sana, detail seperti zona waktu berpengaruh). Untuk format "ramah"—seperti "03/04/2025", "March 4, 2025", atau "2025-3-4"—browser dapat menafsirkan:

  • Bulan/hari vs hari/bulan berdasarkan asumsi locale
  • Zona waktu yang hilang sebagai waktu lokal di satu engine, tetapi ditolak di engine lain
  • String sedikit cacat sebagai "cukup dekat"… sampai tidak

Jika bentuk string tidak dapat Anda prediksi persis, Anda tidak dapat memprediksi hasilnya.

Kasus mengejutkan: YYYY-MM-DD

Perangkap umum adalah bentuk tanggal polos "YYYY-MM-DD" (mis. "2025-01-15"). Banyak pengembang mengharapkannya diinterpretasikan sebagai tengah malam lokal. Dalam praktiknya, beberapa lingkungan menganggap bentuk ini sebagai tengah malam UTC.

Perbedaan itu penting: tengah malam UTC yang dikonversi ke waktu lokal dapat menjadi hari sebelumnya di zona negatif (mis. Amerika) atau menggeser jam secara tak terduga. Ini cara mudah mendapatkan bug "kenapa tanggal saya melenceng satu hari?".

Daftar periksa parsing: input pengguna vs input server

Untuk input server/API:

  • Prefer ISO 8601 penuh dengan zona waktu eksplisit, mis. 2025-01-15T13:45:00Z atau 2025-01-15T13:45:00+02:00.
  • Perlakukan nilai hanya-tanggal sebagai data, bukan sebuah momen dalam waktu. Jika itu ulang tahun atau tanggal jatuh tempo, simpan sebagai string polos ("YYYY-MM-DD") dan hindari mengonversinya ke Date kecuali Anda juga mendefinisikan zona waktu yang dimaksud.

Untuk input pengguna:

  • Jangan terima format ambigu seperti 03/04/2025 kecuali UI Anda memaksa maknanya.
  • Prefer kontrol input (date pickers) yang menghasilkan format yang diketahui.
  • Jika harus mem-parse teks bebas, definisikan dan tegakkan format yang diterima terlebih dahulu.

Gunakan aturan eksplisit (bukan heuristik)

Daripada mengandalkan Date.parse() untuk "menentukan sendiri", pilih salah satu pola ini:

  • Hanya terima ISO 8601 dari server; tolak selain itu.
  • Parse manual format yang dikenal (split string dan gunakan new Date(year, monthIndex, day) untuk tanggal lokal).
  • Simpan dan kirim timestamp (epoch milidetik) untuk instant tepat, dan format untuk tampilan nanti.

Ketika data waktu kritikal, "di mesin saya ter-parse" tidak cukup—buat aturan parsing Anda eksplisit dan konsisten.

Format untuk Manusia dengan Intl.DateTimeFormat

Jika tujuan Anda adalah "menampilkan tanggal/waktu sebagaimana orang harapkan", alat terbaik di JavaScript adalah Intl.DateTimeFormat. Ia menggunakan aturan locale pengguna (urutan, pemisah, nama bulan) dan menghindari pendekatan rapuh merangkai string secara manual seperti month + '/' + day.

Mengapa ini lebih baik daripada membangun string manual

Pemformatan manual sering meng-hardcode keluaran gaya AS, lupa angka awal (leading zeros), atau menghasilkan hasil 24/12 jam yang membingungkan. Intl.DateTimeFormat juga membuat eksplisit zona waktu mana yang Anda tampilkan—kritis saat data disimpan di UTC tetapi UI harus mencerminkan waktu lokal pengguna.

Opsi umum yang akan sering Anda gunakan

Untuk "format yang rapi", dateStyle dan timeStyle adalah yang paling sederhana:

const d = new Date('2025-01-05T16:30:00Z');

// User’s locale + user’s local time zone
console.log(new Intl.DateTimeFormat(undefined, {
  dateStyle: 'medium',
  timeStyle: 'short'
}).format(d));

// Force a specific time zone (great for event times)
console.log(new Intl.DateTimeFormat('en-GB', {
  dateStyle: 'full',
  timeStyle: 'short',
  timeZone: 'UTC'
}).format(d));

Jika Anda perlu siklus jam yang konsisten (mis. toggle pengaturan), gunakan hour12:

console.log(new Intl.DateTimeFormat('en-US', {
  hour: 'numeric',
  minute: '2-digit',
  hour12: true
}).format(d));

Pola UI praktis

Pilih satu fungsi pemformatan per "jenis" timestamp di UI Anda (waktu pesan, entri log, mulai event), dan buat keputusan timeZone secara sengaja:

  • Gunakan waktu lokal untuk "kapan itu terjadi bagi saya."
  • Gunakan zona tetap (sering UTC) untuk audit log, event server, atau koordinasi lintas-tim.

Ini memberi Anda keluaran yang konsisten dan ramah-locale tanpa memelihara sekumpulan string format kustom yang rapuh.

Daylight Saving Time: Bug Tersembunyi Melenceng Satu Jam

Buat API yang aman terhadap masalah waktu
Hasilkan endpoint React + Go dengan field createdAtMs yang jelas dan payload ISO 8601.

Daylight Saving Time (DST) adalah saat zona waktu mengubah offset UTC-nya (biasanya satu jam) pada tanggal tertentu. Bagian rumit: DST tidak hanya "mengubah offset"—ia mengubah eksistensi waktu lokal tertentu.

Waktu jam-dinding yang hilang dan diduplikasi

Saat jam maju (spring forward), rentang waktu lokal tidak pernah terjadi. Misalnya, di banyak wilayah, jam melompat dari 01:59 ke 03:00, jadi 02:30 waktu lokal adalah "hilang."

Saat jam mundur (fall back), rentang waktu lokal terjadi dua kali. Misalnya, 01:30 bisa terjadi sekali sebelum pergeseran dan sekali setelahnya, yang berarti waktu jam-dinding yang sama dapat merujuk ke dua instant berbeda.

Menambah 24 jam vs "waktu lokal yang sama besok"

Kedua ini tidak setara di sekitar batas DST:

  • Tambah 24 jam: "tepat 24 * 60 * 60 detik kemudian"
  • Besok pada waktu lokal yang sama: "besok jam 9:00 di zona waktu ini"

Jika DST dimulai malam ini, "besok jam 9:00" mungkin hanya 23 jam jauhnya. Jika DST berakhir malam ini, mungkin 25 jam jauhnya.

// Scenario: schedule “same local time tomorrow”
const d = new Date(2025, 2, 8, 9, 0); // Mar 8, 9:00 local

const plus24h = new Date(d.getTime() + 24 * 60 * 60 * 1000);
const nextDaySameLocal = new Date(d);
nextDaySameLocal.setDate(d.getDate() + 1);

// Around DST, plus24h and nextDaySameLocal can differ by 1 hour.

Mengapa setHours bisa mengejutkan Anda

Jika Anda melakukan sesuatu seperti date.setHours(2, 30, 0, 0) pada hari "spring forward", JavaScript mungkin menormalkannya ke waktu valid lain (sering 03:30), karena 02:30 tidak ada dalam waktu lokal.

Pendekatan yang lebih aman

  • Lakukan aritmetika di UTC untuk waktu yang berlalu (durasi): gunakan epoch milidetik dan metode UTC.
  • Untuk penjadwalan lokal, jelaskan niatnya: "besok jam 9:00 lokal" harus menggunakan operasi kalender (setDate) daripada menambahkan milidetik.
  • Saat bertukar waktu lewat API, prefer ISO 8601 dengan offset atau Z sehingga instant tidak ambigu.

Durasi vs Tanggal: Jangan Gunakan Date untuk Timer

Sumber bug umum adalah menggunakan Date untuk merepresentasikan sesuatu yang bukan momen kalender.

Sebuah timestamp menjawab "kapan ini terjadi?" (instant spesifik seperti 2025-12-23T10:00:00Z). Sebuah durasi menjawab "berapa lama?" (seperti "3 menit 12 detik"). Ini konsep berbeda, dan mencampurkannya menyebabkan matematika membingungkan dan efek zona waktu/DST yang tak terduga.

Mengapa Date alat yang salah untuk durasi

Date selalu merepresentasikan sebuah titik pada timeline relatif terhadap epoch. Jika Anda menyimpan "90 detik" sebagai Date, sebenarnya Anda menyimpan "1970-01-01 plus 90 detik" dalam zona waktu tertentu. Memformatnya bisa tiba-tiba menampilkan 01:01:30, bergeser satu jam, atau memilih tanggal yang tidak Anda maksud.

Untuk durasi, lebih baik gunakan angka polos:

  • Simpan durasi sebagai detik atau milidetik (pilih satu unit dan konsisten).
  • Lakukan aritmetika dengan angka.
  • Konversi ke string tampilan hanya di akhir.

Mengonversi detik ke HH:mm:ss

Berikut formatter sederhana yang bekerja untuk countdown timer dan durasi media:

function formatHMS(totalSeconds) {
  const s = Math.max(0, Math.floor(totalSeconds));
  const hh = String(Math.floor(s / 3600)).padStart(2, "0");
  const mm = String(Math.floor((s % 3600) / 60)).padStart(2, "0");
  const ss = String(s % 60).padStart(2, "0");
  return `${hh}:${mm}:${ss}`;
}

formatHMS(75);    // "00:01:15" (countdown timer)
formatHMS(5423);  // "01:30:23" (media duration)

Jika Anda mengonversi dari menit, kalikan dulu (minutes * 60) dan pertahankan nilai numerik sampai Anda merendernya.

Membandingkan, Mengurutkan, dan Rentang Tanpa Kejutan

Saat Anda membandingkan waktu di JavaScript, pendekatan paling aman adalah membandingkan angka, bukan teks yang diformat. Objek Date pada dasarnya adalah pembungkus di sekitar timestamp numerik (epoch milidetik), jadi Anda ingin perbandingan berakhir sebagai "angka vs angka".

Perbandingan aman (timestamp menang)

Gunakan getTime() (atau Date.valueOf(), yang mengembalikan angka yang sama) untuk membandingkan secara andal:

const a = new Date('2025-01-10T12:00:00Z');
const b = new Date('2025-01-10T12:00:01Z');

if (a.getTime() < b.getTime()) {
  // a is earlier
}

// Also works:
if (+a < +b) {
  // unary + calls valueOf()
}

Hindari membandingkan string yang diformat seperti "1/10/2025, 12:00 PM"—itu bergantung locale dan tidak akan terurut dengan benar. Pengecualian utama adalah string ISO 8601 dalam format yang sama dan zona waktu yang sama (mis. semua ...Z), yang dapat diurutkan secara leksikografis.

Mengurutkan dan memfilter berdasarkan rentang

Mengurutkan berdasarkan waktu sederhana jika Anda mengurutkan berdasarkan epoch milidetik:

items.sort((x, y) => new Date(x.createdAt).getTime() - new Date(y.createdAt).getTime());

Memfilter item dalam rentang sama idenya:

const start = new Date('2025-01-01T00:00:00Z').getTime();
const end   = new Date('2025-02-01T00:00:00Z').getTime();

const inRange = items.filter(i => {
  const t = new Date(i.createdAt).getTime();
  return t >= start && t < end;
});

"Awal/akhir hari" (lokal vs UTC)

"Awal hari" tergantung apakah yang Anda maksud waktu lokal atau UTC:

// Local start/end of day
const d = new Date(2025, 0, 10); // Jan 10 in local time
const localStart = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0);
const localEnd   = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59, 999);

// UTC start/end of day
const utcStart = new Date(Date.UTC(2025, 0, 10, 0, 0, 0, 0));
const utcEnd   = new Date(Date.UTC(2025, 0, 10, 23, 59, 59, 999));

Pilih satu definisi sejak awal dan pertahankan di seluruh logika perbandingan dan rentang Anda.

Daftar Cek Debug: Cara Mendiagnosis Bug Konversi Waktu

Uji konversi di aplikasi live
Hasilkan, deploy, dan host viewer zona waktu untuk memvalidasi format secara end-to-end.

Bug waktu terasa acak sampai Anda menentukan apa yang Anda punya (timestamp? string? Date?) dan di mana pergeseran diperkenalkan (parsing, konversi zona waktu, pemformatan).

1) Tangkap “tiga tampilan” dari momen yang sama

Mulailah dengan men-logging nilai yang sama dalam tiga cara berbeda. Ini cepat memperlihatkan apakah masalahnya detik vs milidetik, lokal vs UTC, atau parsing string.

console.log('raw input:', input);

const d = new Date(input);
console.log('toISOString (UTC):', d.toISOString());
console.log('toString (local):', d.toString());
console.log('timezone offset (min):', d.getTimezoneOffset());

Apa yang dicari:

  • Jika toISOString() sangat meleset (mis. tahun 1970 atau jauh di masa depan), curigai detik vs milidetik.
  • Jika toISOString() tampak benar tapi toString() "bergeser", Anda melihat isu tampilan zona waktu lokal.
  • Jika getTimezoneOffset() berubah tergantung tanggal, Anda melewati daylight saving time.

2) Verifikasi lingkungan: zona waktu dan locale

Banyak laporan "berfungsi di mesin saya" hanyalah default lingkungan berbeda.

  • Browser: periksa pengaturan zona waktu OS dan bahasa browser. Kemudian log:
console.log(Intl.DateTimeFormat().resolvedOptions());
  • Node.js / server: konfirmasi zona waktu proses:
console.log('TZ:', process.env.TZ);
console.log(Intl.DateTimeFormat().resolvedOptions().timeZone);

Jika server Anda berjalan di UTC tetapi laptop Anda di zona lokal, keluaran yang diformat akan berbeda kecuali Anda menentukan timeZone secara eksplisit.

3) Tambahkan test pada titik-titik rentan

Buat unit test di sekitar batas DST dan waktu "edge":

  • Satu jam sebelum dan setelah pergantian DST di zona relevan
  • Akhir bulan/tahun, dan crossover 23:3000:30
  • Beberapa zona waktu jika produk Anda mendukungnya

Jika Anda cepat iterasi, pertimbangkan menjadikan test ini bagian dari scaffolding. Misalnya, ketika menghasilkan aplikasi React + Go di Koder.ai, Anda bisa menambahkan suite test "kontrak waktu" kecil sejak awal (contoh payload API + asersi parsing/pemformatan) sehingga regresi tertangkap sebelum deploy.

Daftar pra-rilis singkat

  • Input punya kontrak jelas: epoch milidetik atau ISO 8601 dengan offset.
  • Tidak ada string ambigu seperti "2025-03-02 10:00".
  • Pemformatan selalu menentukan locale dan (jika perlu) timeZone.
  • Test mencakup batas DST untuk region target Anda.

Pola yang Direkomendasikan untuk Penanganan Waktu yang Andal

Penanganan waktu yang andal di JavaScript sebagian besar soal memilih "sumber kebenaran" dan konsisten dari penyimpanan hingga tampilan.

Sekumpulan praktik terbaik sederhana

Simpan dan hitung di UTC. Perlakukan waktu lokal pengguna sebagai detail presentasi.

Kirim tanggal antar sistem sebagai string ISO 8601 dengan offset eksplisit (sebaiknya Z). Jika Anda harus mengirim epoch numerik, dokumentasikan unitnya dan pertahankan konsistensi (milidetik adalah default umum di JS).

Format untuk manusia dengan Intl.DateTimeFormat (atau toLocaleString), dan berikan timeZone eksplisit saat Anda membutuhkan keluaran deterministik (mis. selalu menampilkan waktu di UTC atau wilayah bisnis tertentu).

Panduan keputusan: DB vs API vs UI

  • Database: simpan instant dalam waktu sebagai UTC (epoch milidetik atau tipe datetime UTC). Hindari datetime "lokal" kecuali domain Anda benar-benar menyimpan waktu jam-dinding (seperti "toko buka jam 09:00").
  • Boundary API: prefer ISO 8601 dengan Z (mis. 2025-12-23T10:15:00Z). Jika memakai epoch, sertakan nama field seperti createdAtMs agar satuan jelas.
  • UI: ambil instant UTC yang disimpan dan format untuk locale pengguna. Untuk UI penjadwalan, beri label zona waktu dengan jelas dan buat konversi eksplisit.

Kapan library berguna

Pertimbangkan library tanggal-waktu khusus jika Anda membutuhkan event rekuren, aturan zona waktu kompleks, aritmetika aman DST ("waktu lokal yang sama besok"), atau banyak parsing dari input tidak konsisten. Nilainya ada pada API yang lebih jelas dan lebih sedikit bug kasus tepi.

Jika Anda ingin mendalami, jelajahi panduan terkait waktu di /blog. Jika Anda sedang mengevaluasi tooling atau opsi dukungan, lihat /pricing.

Pertanyaan umum

Format apa yang sebaiknya digunakan untuk stempel waktu di JavaScript?

Gunakan milidetik epoch atau string ISO 8601 UTC sebagai format internal. Ubah ke format lokal hanya saat menampilkan nilainya kepada pengguna.

Mengapa stempel waktu Unix saya berubah menjadi tanggal pada 1970?

JavaScript Date mengharapkan milidetik. Kalikan stempel waktu Unix dalam detik dengan 1000 sebelum meneruskannya ke new Date().

Mengapa tanggal yang sama menunjukkan waktu berbeda di komputer yang berbeda?

Date menyimpan satu momen, tetapi JavaScript sering menampilkannya dalam zona waktu lokal komputer. Bandingkan toISOString() dengan toString() untuk melihat apakah datanya berubah atau hanya tampilannya yang berubah.

Bagaimana cara mencegah tanggal bergeser satu hari?

Simpan nilai yang hanya berisi tanggal, seperti tanggal lahir atau tanggal faktur, sebagai YYYY-MM-DD. Jangan mengubahnya menjadi Date kecuali Anda juga menentukan zona waktu yang dimaksud.

Format tanggal apa yang paling aman untuk API?

Kirim nilai ISO 8601 lengkap dengan Z untuk UTC, seperti 2025-03-04T12:30:00Z, atau sertakan offset eksplisit. Hindari string seperti 03/04/2025 karena orang dan browser dapat membacanya secara berbeda.

Bagaimana sebaiknya saya memformat tanggal untuk pengguna?

Gunakan Intl.DateTimeFormat dan tentukan timeZone saat layar memerlukan zona tetap. API ini memformat tanggal sesuai lokal pengguna tanpa perlu menyusun string secara manual.

Haruskah saya menggunakan Date.parse untuk tanggal yang dimasukkan pengguna?

Jangan mengandalkannya untuk string informal atau ambigu. Terima format ISO yang sudah dikenal dari API, atau uraikan input pengguna yang terkontrol dengan aturan yang Anda tetapkan sendiri.

Mengapa saya harus menghindari penggunaan Date untuk hitung mundur atau durasi?

Date menandai momen dalam kalender, sedangkan durasi hanya berupa jumlah waktu. Simpan durasi sebagai detik atau milidetik, lalu format angkanya saat menampilkannya.

Bagaimana Daylight Saving Time memengaruhi tanggal JavaScript?

Gunakan milidetik epoch untuk perhitungan waktu berlalu. Untuk jadwal seperti "besok pukul 9.00 pagi" dalam zona bernama, gunakan operasi berbasis kalender dan uji tanggal transisi DST.

Apa cara tercepat untuk men-debug bug waktu di JavaScript?

Catat input mentah, toISOString(), toString(), dan getTimezoneOffset(). Nilai ISO yang salah sering berarti ada masalah penguraian atau satuan, sedangkan string lokal yang berbeda biasanya berarti perbedaan tampilan zona waktu.

Related posts