Satu momen di dunia ini memiliki banyak penampilan: 10:30 di Jakarta adalah 03:30 di UTC. Praktik yang lazim menyarankan penyimpanan dan pertukaran data dalam UTC, lalu konversi ke waktu lokal hanya pada lapisan tampilan. Konversi di .NET memiliki dua jalur: ToLocalTime dan ToUniversalTime yang mengikuti zona mesin, atau TimeZoneInfo.ConvertTimeToUtc dan ConvertTimeFromUtc yang memakai zona eksplisit pilihan kita.

Konversi dengan Zona Eksplisit #

csharp
TimeZoneInfo jakarta = TimeZoneInfo.FindSystemTimeZoneById("Asia/Jakarta");

DateTime lokal = new DateTime(2025, 8, 17, 10, 30, 0, DateTimeKind.Unspecified);

DateTime utc = TimeZoneInfo.ConvertTimeToUtc(lokal, jakarta);
Console.WriteLine(utc.ToString("yyyy-MM-dd HH:mm 'UTC'", CultureInfo.InvariantCulture));
Console.WriteLine(utc.Kind);

DateTime kembali = TimeZoneInfo.ConvertTimeFromUtc(utc, jakarta);
Console.WriteLine(kembali.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture));

Output yang Dihasilkan:

text
2025-08-17 03:30 UTC
Utc
2025-08-17 10:30

Mari kita bedah baris demi baris:

  1. Baris 3 (DateTimeKind.Unspecified): nilai 10:30 dinyatakan tanpa zona; artinya angka tersebut dianggap milik zona yang kita kirim pada langkah berikutnya.
  2. Baris 5 (ConvertTimeToUtc(lokal, jakarta)): runtime mengurangi offset 7 jam dan menghasilkan 03:30; properti Kind hasil konversi otomatis menjadi Utc.
  3. Baris 8 (ConvertTimeFromUtc): konversi balik mengembalikan 10:30 dengan arah yang seimbang, membuktikan round-trip zona berjalan utuh.
  4. Format 'UTC': tanda kutip tunggal pada pola format mencetak teks UTC sebagai literal, bukan penentu format.

Aturan praktisnya dapat dirangkum tiga langkah: terima payload lengkap dengan offset atau DateTimeOffset, simpan sebagai UTC, lalu konversi ke zona pengguna hanya saat menampilkan. Dengan pola tersebut, data historis tetap akurat meski aturan zona berubah, dan dua server di zona berbeda tidak pernah menyimpan waktu yang saling bertentangan.