kodingup.camp

Beranda/JavaScript Mastery: Prototype, Class, Waktu, Error & Async

Dasar-dasar Data Waktu

Modul 6 dari 154 menit bacaTemporal Data Fundamentals

Isi modul

    Kenapa ini penting

    Hampir semua aplikasi berurusan dengan waktu: tanggal transaksi, jadwal janji temu, batas pembayaran, waktu kirim pesan, umur pengguna. Masalahnya, waktu itu rumit. Indonesia saja punya tiga zona (WIB, WITA, WIT). Server kamu mungkin berjalan di zona UTC di Singapura atau Amerika, sementara penggunamu di Jakarta. Kalau kamu ceroboh, transaksi yang dibuat pukul 23.30 WIB tanggal 31 bisa tercatat tanggal 1 bulan berikutnya, dan laporan keuangan bulananmu jadi berantakan.

    Di modul ini kamu belajar objek Date bawaan JavaScript: apa sebenarnya yang disimpan di dalamnya, apa itu timestamp, dan bagaimana zona waktu memengaruhi tampilan. Kamu juga akan mengenal Temporal API, pengganti Date yang jauh lebih baik dan sedang dalam proses masuk ke semua browser.

    Konsep inti

    Apa yang disimpan Date?

    Ini kunci paling penting: objek Date hanya menyimpan satu angka, yaitu jumlah milidetik sejak 1 Januari 1970 pukul 00:00:00 UTC (disebut Unix epoch). Angka ini disebut timestamp. Date tidak menyimpan zona waktu. Zona waktu baru dipakai saat kamu menampilkan atau membaca bagian-bagiannya (jam, tanggal) dengan method lokal.

    Analogi: timestamp itu seperti satu momen yang sama di seluruh dunia, misalnya saat pertandingan final dimulai. Orang di Jakarta melihat jam dinding menunjukkan 19.00, di Makassar 20.00, di London 12.00. Momennya satu, tampilannya berbeda.

    UTC vs WIB

    Cara membuat Date

    Cara Contoh Catatan
    Sekarang new Date() Waktu saat kode jalan
    Timestamp new Date(1792740600000) Milidetik sejak epoch
    String ISO lengkap new Date("2026-10-23T14:30:00+07:00") Paling aman, offset jelas
    String tanggal saja new Date("2026-10-23") Dianggap UTC tengah malam
    String tanggal+jam tanpa offset new Date("2026-10-23T14:30") Dianggap waktu lokal
    Komponen new Date(2026, 9, 23) Bulan mulai dari 0! Waktu lokal
    Komponen UTC new Date(Date.UTC(2026, 9, 23)) Interpretasi UTC

    Mendapatkan timestamp: Date.now() (sekarang) atau tanggal.getTime().

    Tanggal tidak valid

    new Date("besok") tidak melempar error, tetapi menghasilkan Invalid Date yang getTime()-nya NaN. Selalu validasi dengan Number.isNaN(d.getTime()).

    Temporal API: masa depan

    Date punya banyak kekurangan: bulan mulai dari 0, object bisa diubah (mutable), dukungan zona waktu lemah, parsing string tidak konsisten. Temporal adalah API baru dari TC39 (komite standar JavaScript) yang sudah mulai dikirim browser, dengan tipe yang jelas: Temporal.PlainDate (tanggal tanpa jam), Temporal.ZonedDateTime (waktu + zona), Temporal.Instant (momen), Temporal.Duration (durasi). Semuanya immutable.

    Status dukungan per data MDN (browser-compat-data) Oktober 2026: Chrome & Edge 144+, Firefox 139+, Deno 2.7+ sudah mendukung; Safari baru di Technology Preview; tabel MDN mencatat Node.js 26, tetapi saat diuji dengan Node 26.0.0, typeof Temporal masih "undefined". Artinya Temporal belum Baseline (belum aman dipakai tanpa cadangan). Untuk produksi saat ini: tetap kuasai Date, atau pakai polyfill @js-temporal/polyfill / temporal-polyfill, dan selalu cek dukungan dengan typeof Temporal !== "undefined".

    Contoh kode

    // 1. Date hanya menyimpan timestamp
    const momen = new Date("2026-10-23T14:30:00+07:00"); // 14.30 WIB
    console.log(momen.getTime());     // → 1792740600000
    console.log(momen.toISOString()); // → 2026-10-23T07:30:00.000Z (UTC, huruf Z = UTC)
    
    // 2. Momen yang sama, tampilan berbeda per zona
    const zona = ["Asia/Jakarta", "Asia/Makassar", "Asia/Jayapura", "UTC"];
    for (const tz of zona) {
      const jam = momen.toLocaleTimeString("id-ID", { timeZone: tz, hour: "2-digit", minute: "2-digit" });
      console.log(tz.padEnd(14), jam);
    }
    // → Asia/Jakarta   14.30
    // → Asia/Makassar  15.30
    // → Asia/Jayapura  16.30
    // → UTC            07.30
    
    // 3. Jebakan parsing string
    const a = new Date("2026-10-23");       // dianggap UTC
    const b = new Date("2026-10-23T00:00"); // dianggap waktu lokal komputer
    console.log(a.toISOString()); // → 2026-10-23T00:00:00.000Z
    console.log(b.toISOString()); // → 2026-10-22T17:00:00.000Z (jika komputer di WIB)
    
    // 4. Bulan mulai dari 0
    const c = new Date(2026, 9, 23); // 9 = Oktober!
    console.log(c.getMonth(), c.getDate()); // → 9 23
    
    // 5. Timestamp & selisih sederhana
    const mulai = Date.now();
    let total = 0;
    for (let i = 0; i < 1e6; i++) total += i;
    console.log(`Loop selesai dalam ${Date.now() - mulai} ms`); // → Loop selesai dalam 3 ms (bervariasi)
    
    // 6. Validasi tanggal
    function buatTanggal(input) {
      const d = new Date(input);
      if (Number.isNaN(d.getTime())) throw new Error(`Tanggal tidak valid: ${input}`);
      return d;
    }
    try {
      buatTanggal("tanggal 32 bulan 13");
    } catch (e) {
      console.log(e.message); // → Tanggal tidak valid: tanggal 32 bulan 13
    }
    
    // 7. Zona waktu default lingkungan
    console.log(Intl.DateTimeFormat().resolvedOptions().timeZone); // → Asia/Jakarta (tergantung komputer)
    console.log(momen.getTimezoneOffset()); // → -420 (menit; WIB = UTC+7 → -420, tandanya terbalik!)
    
    // 8. Simpan di database/JSON selalu dalam UTC ISO
    const transaksi = { id: 1, dibuatPada: momen.toISOString() };
    console.log(JSON.stringify(transaksi)); // → {"id":1,"dibuatPada":"2026-10-23T07:30:00.000Z"}
    const dibaca = new Date(JSON.parse(JSON.stringify(transaksi)).dibuatPada);
    console.log(dibaca.getTime() === momen.getTime()); // → true
    
    // 9. Temporal (jalankan hanya jika tersedia)
    if (typeof Temporal !== "undefined") {
      const hariIni = Temporal.Now.plainDateISO("Asia/Jakarta");
      console.log(hariIni.add({ days: 30 }).toString()); // → 2026-11-22 (misalnya)
    } else {
      console.log("Temporal belum didukung di lingkungan ini"); // → (di Node 26.0.0)
    }
    

    Contoh 7 memperlihatkan keanehan getTimezoneOffset(): WIB adalah UTC+7, tetapi hasilnya -420. Method ini mengembalikan "berapa menit yang harus ditambahkan ke waktu lokal agar menjadi UTC", jadi tandanya terbalik. Hal kecil seperti ini sering menjebak.

    Prinsip emas penanganan waktu: simpan dan kirim dalam UTC (ISO 8601 atau timestamp), tampilkan dalam zona pengguna. Logika bisnis (misalnya "transaksi bulan Oktober") harus didefinisikan dengan zona yang jelas.

    Kesalahan umum

    1. Lupa bulan mulai dari 0. new Date(2026, 10, 1) adalah 1 November. Buat konstanta atau selalu kurangi 1 dari bulan manusia.
    2. Mengira new Date("2026-10-23") itu tengah malam WIB. Itu tengah malam UTC, yaitu 07.00 WIB. Untuk tengah malam lokal pakai new Date(2026, 9, 23) atau string dengan offset +07:00.
    3. Menyimpan tanggal sebagai string tampilan seperti "23/10/2026". Formatnya ambigu (format AS membacanya bulan/tanggal). Simpan ISO UTC.
    4. Tidak memvalidasi input. Invalid Date tidak error, ia menyebar diam-diam menjadi NaN di perhitungan. Cek getTime().
    5. Langsung memakai Temporal di produksi tanpa cek dukungan atau polyfill. Safari dan sebagian lingkungan belum siap.

    Latihan

    1. Mudah, Buat Date untuk 17 Agustus 2026 pukul 10.00 WIB memakai string ISO dengan offset, lalu cetak toISOString()-nya.
    2. Sedang, Tulis function jamDiKota(date) yang mengembalikan object { WIB, WITA, WIT } berisi jam dalam format HH.MM untuk momen tersebut.
    3. Menantang, Tulis function apakahTanggalValid(tahun, bulan, tanggal) (bulan manusia 1-12) yang mengembalikan false untuk tanggal seperti 31 Februari. Petunjuk: Date otomatis "menggulung" tanggal yang kelebihan.
    Lihat solusi
    // 1
    const hut = new Date("2026-08-17T10:00:00+07:00");
    console.log(hut.toISOString()); // → 2026-08-17T03:00:00.000Z
    
    // 2
    function jamDiKota(date) {
      const f = (tz) => date.toLocaleTimeString("id-ID", { timeZone: tz, hour: "2-digit", minute: "2-digit" });
      return { WIB: f("Asia/Jakarta"), WITA: f("Asia/Makassar"), WIT: f("Asia/Jayapura") };
    }
    console.log(jamDiKota(hut)); // → { WIB: '10.00', WITA: '11.00', WIT: '12.00' }
    
    // 3
    function apakahTanggalValid(tahun, bulan, tanggal) {
      const d = new Date(tahun, bulan - 1, tanggal);
      return d.getFullYear() === tahun && d.getMonth() === bulan - 1 && d.getDate() === tanggal;
    }
    console.log(apakahTanggalValid(2026, 2, 31)); // → false (digulung jadi 3 Maret)
    console.log(apakahTanggalValid(2028, 2, 29)); // → true (2028 tahun kabisat)
    

    Ringkasan

    Kuis pemahaman

    Pilih satu jawaban per soal. Penjelasan muncul setelah kamu menjawab.