Use Cases (Diperbarui: 2/6/2026)

Date dan time handling dengan Claude Code

Panduan praktis menangani timezone, DST, Intl, pengujian, dan storage tanggal dengan Claude Code.

Date dan time handling dengan Claude Code

Mengapa date-time handling tidak cukup dengan satu prompt

Bug tanggal dan waktu mudah lolos code review, tetapi dampaknya besar di production. Tampilan bisa benar di Indonesia atau Jepang, tetapi rusak saat daylight saving time di Amerika Serikat, penutupan bulan di Eropa, offset 30 menit di India, atau perbedaan timezone server dan browser. Jika Anda hanya meminta Claude Code “implement date handling”, hasilnya mungkin rapi secara format, tetapi storage policy, kontrak API, dan boundary test belum tentu aman.

Gunakan Claude Code sebagai pair engineer untuk memperjelas spesifikasi waktu, bukan sekadar generator kode. Panduan ini fokus pada aplikasi web untuk booking, billing, notifikasi, support SLA, dan dashboard admin yang melewati batas timezone. Untuk strategi testing yang lebih luas, baca Claude Code testing strategies. Untuk perubahan schema, gunakan bersama database migration with Claude Code.

Sebelum implementasi, cek sumber resmi. Untuk tampilan, gunakan MDN Intl.DateTimeFormat. Untuk status dan konsep Temporal, cek TC39 Temporal proposal dan MDN Temporal. Untuk perilaku PostgreSQL, baca PostgreSQL Date/Time Types. Untuk checks otomatis setelah edit, pakai Claude Code hooks.

Tetapkan istilah dan storage policy lebih dulu

Sebelum meminta Claude Code menulis kode, samakan istilah di tim. Tanpa itu, review mudah berubah menjadi klaim longgar seperti “kita simpan UTC, jadi aman” atau “produk lokal, jadi satu timezone cukup”.

IstilahArti sederhanaAturan praktis
instantSatu momen global, misalnya 2026-06-02T00:00:00ZSimpan sebagai timestamp berbasis UTC
local dateTanggal kalender untuk user atau aturan bisnisSimpan sebagai YYYY-MM-DD, terpisah dari jam
wall clock timeJam yang dilihat manusia, misalnya meeting 09:00Simpan bersama ID timezone IANA
IANA timezoneNama region seperti Asia/Jakarta atau America/New_YorkJangan ganti dengan offset tetap
DSTDaylight saving time; beberapa hari lokal punya 23 atau 25 jamTest hari transisi secara eksplisit

Dalam proyek nyata, tulis tiga aturan ini di AGENTS.md atau CLAUDE.md sebelum implementasi.

  1. Timestamp API untuk event yang sudah terjadi harus berupa string ISO 8601 dengan Z atau offset eksplisit.
  2. Jadwal masa depan harus menyimpan localDate, localTime, dan timeZone sebagai field terpisah.
  3. UI harus selalu mengirim locale dan timeZone ke Intl.DateTimeFormat; jangan bergantung pada default runtime.

Batasnya bisa dipikirkan seperti ini.

flowchart LR
  A["Client: local date/time input"] --> B["API contract: localDate + localTime + timeZone"]
  B --> C["Server: validate and convert when needed"]
  C --> D["Database: instant in timestamptz + original timeZone"]
  D --> E["UI: format with Intl.DateTimeFormat"]
  E --> A

Buat dasar aman dengan Intl.DateTimeFormat

Untuk tampilan, mulai dari API standar Intl.DateTimeFormat. MDN mendokumentasikannya sebagai API bawaan untuk format tanggal dan waktu sesuai bahasa, dengan opsi timeZone eksplisit. Beri Claude Code dua batasan: jangan memakai toLocaleString() tanpa argumen, dan jangan parse YYYY-MM-DD dengan Date ketika nilai itu berarti tanggal kalender lokal.

Module berikut tanpa dependency. Simpan sebagai src/lib/date-policy.ts dan pakai ulang di UI, API, dan tests.

// src/lib/date-policy.ts
export const TIME_POLICY = {
  defaultLocale: 'id-ID',
  defaultTimeZone: 'Asia/Jakarta',
} as const;

type FormatOptions = {
  locale?: string;
  timeZone?: string;
  includeWeekday?: boolean;
};

function toDate(input: string | Date): Date {
  const date = input instanceof Date ? input : new Date(input);

  if (!Number.isFinite(date.getTime())) {
    throw new Error(`Invalid date value: ${String(input)}`);
  }

  return date;
}

export function toUtcIso(input: string | Date): string {
  if (typeof input === 'string' && !/(Z|[+-]\d{2}:?\d{2})$/i.test(input)) {
    throw new Error('Timestamp must include Z or an explicit UTC offset.');
  }

  return toDate(input).toISOString();
}

function dateParts(date: Date, timeZone: string): Record<string, string> {
  const parts = new Intl.DateTimeFormat('en-US', {
    timeZone,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
  }).formatToParts(date);

  return Object.fromEntries(
    parts
      .filter((part) => part.type !== 'literal')
      .map((part) => [part.type, part.value]),
  );
}

export function dayKeyInTimeZone(
  input: string | Date,
  timeZone = TIME_POLICY.defaultTimeZone,
): string {
  const parts = dateParts(toDate(input), timeZone);
  return `${parts.year}-${parts.month}-${parts.day}`;
}

export function formatInstant(
  input: string | Date,
  {
    locale = TIME_POLICY.defaultLocale,
    timeZone = TIME_POLICY.defaultTimeZone,
    includeWeekday = true,
  }: FormatOptions = {},
): string {
  return new Intl.DateTimeFormat(locale, {
    timeZone,
    weekday: includeWeekday ? 'short' : undefined,
    year: 'numeric',
    month: 'short',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    hourCycle: 'h23',
    timeZoneName: 'short',
  }).format(toDate(input));
}

Tujuannya bukan menyembunyikan semua operasi tanggal di utility. Tujuannya memisahkan instant, key tanggal lokal, dan label tampilan. Sebelum Claude Code menambah helper baru, minta ia menjelaskan requirement itu masuk kategori yang mana.

Konversi waktu lokal masa depan secara eksplisit

Intl.DateTimeFormat bagus untuk output, tetapi bukan alat yang tepat untuk mengubah 2026-11-01 01:30 America/New_York menjadi UTC instant yang aman. Pilih satu library di level proyek dan cek dokumentasi resminya. Luxon dan API docs mendokumentasikan API timezone eksplisit. date-fns kuat untuk utility tanggal berbasis fungsi, tetapi kebutuhan timezone harus dicek di docs resmi terbaru. Temporal sudah Stage 4 di TC39, tetapi target runtime dan polyfill tetap harus diputuskan.

Dalam form booking, user memasukkan tanggal dan jam lokal; server mengubahnya menjadi instant untuk disimpan.

// src/lib/schedule-time.ts
import { DateTime } from 'luxon';

type LocalScheduleInput = {
  localDate: string; // YYYY-MM-DD
  localTime: string; // HH:mm
  timeZone: string; // IANA time zone, for example "America/New_York"
};

export function scheduleToUtcIso(input: LocalScheduleInput): string {
  const rawLocal = `${input.localDate}T${input.localTime}`;
  const local = DateTime.fromISO(rawLocal, { zone: input.timeZone });

  if (!local.isValid) {
    throw new Error(local.invalidExplanation ?? `Invalid local time: ${rawLocal}`);
  }

  const roundTrip = local.setZone(input.timeZone).toFormat("yyyy-MM-dd'T'HH:mm");
  if (roundTrip !== rawLocal) {
    throw new Error(`Nonexistent local time in ${input.timeZone}: ${rawLocal}`);
  }

  const iso = local.toUTC().toISO({ suppressMilliseconds: true });
  if (!iso) {
    throw new Error(`Could not convert local time to UTC: ${rawLocal}`);
  }

  return iso;
}

Helper ini tidak otomatis menyelesaikan jam 01:00 yang muncul dua kali saat DST berakhir. Produk harus punya aturan: pilih offset lebih awal, offset lebih akhir, atau minta konfirmasi user. Minta Claude Code menulis tests untuk local time yang tidak ada, waktu ambigu, akhir bulan, dan leap day.

Pisahkan batas client, server, dan database

Kesalahan paling umum adalah memasukkan nilai ke Date tanpa memutuskan apakah interpretasinya milik browser atau server. Input browser, payload API, kolom database, email, dan export CSV adalah batas yang berbeda.

Review desain dengan minimal tiga use case berikut.

  • Sistem booking: input memakai waktu lokal venue, storage memakai UTC instant, tampilan memakai timezone viewer atau venue.
  • Cutoff billing: “hari terakhir bulan pukul 23:59” adalah aturan local date pada timezone kontrak customer; jangan dibuat dengan menambah blok 24 jam.
  • Support SLA: business day, hari libur, dan office hour berbeda per region; simpan deadline instant dan konteks lokal yang mudah dibaca.

Dokumentasi resmi PostgreSQL menjelaskan bahwa timestamp with time zone dikonversi ke UTC dan timezone asal tidak disimpan. Artinya timestamptz saja tidak bisa menunjukkan bahwa user memilih America/New_York. Jika produk butuh informasi itu, simpan di kolom terpisah.

create table scheduled_events (
  id uuid primary key,
  title text not null,
  starts_at timestamptz not null,
  original_time_zone text not null check (original_time_zone <> ''),
  local_date date not null,
  local_time time not null,
  created_at timestamptz not null default now()
);

create index scheduled_events_starts_at_idx
  on scheduled_events (starts_at);

Jangan mengira memasukkan 2026-06-02T09:00:00+09:00 ke timestamp without time zone akan mempertahankan offset. PostgreSQL menentukan tipe terlebih dahulu; untuk nilai without time zone, indikasi timezone diabaikan. Tambahkan “apakah tipe kolom datetime cocok dengan kontrak API?” ke checklist review Claude Code.

Tulis test DST dengan instant tetap

Tests tidak boleh bergantung pada “hari ini”, jam saat ini, atau timezone mesin developer. Tetapkan input sebagai UTC instant, lalu assert local day atau label yang diharapkan. Dengan Vitest, mulai dari file ini. Untuk pola lebih lanjut, baca Claude Code Vitest advanced.

// src/lib/date-policy.test.ts
import { describe, expect, it } from 'vitest';
import { dayKeyInTimeZone, formatInstant, toUtcIso } from './date-policy';

describe('date/time policy', () => {
  it('requires an explicit offset for API timestamps', () => {
    expect(() => toUtcIso('2026-06-02T09:00:00')).toThrow(/offset/);
    expect(toUtcIso('2026-06-02T09:00:00+09:00')).toBe('2026-06-02T00:00:00.000Z');
  });

  it('calculates a local day key across the UTC date boundary', () => {
    expect(dayKeyInTimeZone('2026-03-31T15:01:00Z', 'Asia/Tokyo')).toBe('2026-04-01');
    expect(dayKeyInTimeZone('2026-04-01T00:30:00Z', 'America/Los_Angeles')).toBe('2026-03-31');
  });

  it('formats a DST transition instant in the requested time zone', () => {
    const label = formatInstant('2026-03-08T07:30:00Z', {
      locale: 'en-US',
      timeZone: 'America/New_York',
    });

    expect(label).toMatch(/03:30|3:30/);
    expect(label).toMatch(/EDT|GMT-4/);
  });
});

Test ini menerima EDT atau GMT-4 karena data ICU bisa berbeda antar CI environment. Sebaliknya, key tanggal lokal dan hasil konversi UTC adalah business logic, jadi harus ketat.

Cegah regresi dengan prompt dan hooks

Berikan constraint ke Claude Code sebelum implementasi. Prompt yang panjang tidak masalah jika menyebut batas berbahaya secara jelas.

Before implementing date/time changes, read date-policy.ts and the database schema.

Constraints:
- API timestamps for completed events must be ISO strings with Z or an explicit offset
- Future bookings must keep localDate, localTime, and timeZone separate
- Intl.DateTimeFormat must always receive locale and timeZone
- Do not use new Date('YYYY-MM-DD') for local calendar dates
- Add Vitest cases for DST start, DST end, month end, and leap day
- Explain the PostgreSQL timestamp/timestamptz difference in the review notes

Done when:
- npm test -- --run date-time passes
- Updated API response examples are added to README

Untuk tim, gunakan Claude Code hooks agar test deterministic berjalan setelah edit. Docs resmi menunjukkan hooks dapat menjalankan shell command pada lifecycle event. Alur lengkapnya ada di Claude Code hooks guide.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npm test -- --run date-time"
          }
        ]
      }
    ]
  }
}

Pilih library berdasarkan jenis waktu

Jangan memilih date library hanya dari popularitas. Pilih berdasarkan jenis waktu yang ditangani produk. Intl.DateTimeFormat cocok untuk tampilan lokal, date-fns untuk utility tanggal terfokus, Luxon untuk scheduling dengan IANA timezone, dan Temporal untuk desain yang ingin memisahkan Instant, PlainDate, dan ZonedDateTime. Walaupun Temporal sudah Stage 4, cek runtime support dan polyfill sebelum meminta Claude Code menulis ulang kode production.

OpsiPaling cocokCatatan
IntlTampilan lokal dengan timezone eksplisitBukan alat konversi local time ke instant
date-fnsDate math, import per fungsi, utility kecilCek docs resmi untuk kebutuhan timezone
LuxonIANA timezone scheduling, relative time, ISO conversionWaktu DST ambigu tetap butuh aturan produk
TemporalMemisahkan Instant, PlainDate, ZonedDateTimeCompatibility dan polyfill penting

Dari sisi konten dan monetisasi, daftar library generik kurang kuat. Pembaca perlu tahu apa yang disimpan, di mana konversi dilakukan, dan apa yang harus diuji. Jika tim ingin memasukkan policy ini ke CLAUDE.md, hooks, PR review, dan migration, halaman Claude Code training dan konsultasi adalah langkah berikutnya. Developer solo bisa menambahkan prompt di atas ke cheatsheet gratis sebagai guardrail yang bisa dipakai ulang.

Catatan verifikasi praktik

Catatan Masa: pemeriksaan paling berguna adalah mengunci satu UTC instant, memformatnya di Tokyo, New York, dan Los Angeles, lalu menguji local date key saat melewati batas hari. Bug paling mudah direproduksi adalah memperlakukan YYYY-MM-DD sebagai tanggal lokal user, mengubahnya menjadi Date, lalu melihatnya menjadi hari sebelumnya di timezone lain. Policy artikel ini mempertahankan local date sebagai string dan hanya mengonversi stored instant serta label tampilan secara eksplisit, sehingga diff dari Claude Code jauh lebih mudah direview.

#Claude Code #tanggal #timezone #Intl #testing
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.