Jebakan Timezone Unix Timestamp dan Cara Menghindarinya
Unix timestamp seharusnya sederhana: satu integer, mewakili detik sejak 1 Januari 1970 UTC. Tanpa timezone. Tanpa ambiguitas. Hanya sebuah angka.
Namun demikian, bug terkait timezone dalam penanganan timestamp ada di mana-mana. Mereka muncul sebagai event yang dicatat pada waktu yang salah, janji kalender yang bergeser beberapa jam, atau query database yang mengembalikan baris yang salah. Sebagian besar dari mereka berasal dari kumpulan kecil kesalahan yang sama.
Artikel ini membahas mode kegagalan umum dan cara menghindarinya. Unix Timestamp Converter memungkinkan Anda memeriksa timestamp apa pun terhadap waktu UTC dan waktu lokal secara berdampingan.
Mengapa Timestamp Tampak Aman Timezone — Sampai Mereka Tidak
Unix timestamp itu sendiri tidak memiliki timezone. 1714000000 adalah momen yang sama di mana pun. Masalah dimulai ketika Anda mengonversinya ke atau dari tanggal yang dapat dibaca manusia, karena konversi itu selalu melibatkan timezone — sering kali timezone implisit yang tidak Anda pilih.
Sebagian besar bahasa pemrograman defaultnya menggunakan timezone lokal sistem saat mengonversi. Jika server Anda diatur ke UTC, semuanya terlihat baik. Jika diatur ke waktu New York, setiap konversi timestamp-ke-tanggal meleset 5 jam. Jika laptop pengembang berada di Berlin, hasilnya berbeda dari server CI di AS. Timestamp konsisten; interpretasinya tidak.
Jebakan 1: Membangun Timestamp Dari String Tanggal Lokal
Ini adalah bug paling umum. Anda memiliki string tanggal seperti "2024-04-25 09:00:00" dan Anda mengonversinya menjadi timestamp:
JavaScript: `js new Date("2024-04-25 09:00:00").getTime() / 1000 `
Python: `python from datetime import datetime datetime(2024, 4, 25, 9, 0, 0).timestamp() `
Keduanya memperlakukan input sebagai waktu lokal. Jika Anda berada di UTC+2, timestamp yang dihasilkan mewakili 07:00 UTC, bukan 09:00 UTC. Timestamp Anda meleset dua jam.
Cara memperbaikinya selalu dengan menentukan UTC secara eksplisit:
// JavaScript — tambahkan Z atau gunakan Date.UTC()
new Date("2024-04-25T09:00:00Z").getTime() / 1000
// atau
Date.UTC(2024, 3, 25, 9, 0, 0) / 1000
# Python — gunakan timezone.utc
from datetime import datetime, timezone
datetime(2024, 4, 25, 9, 0, 0, tzinfo=timezone.utc).timestamp()
Perbedaannya terlihat kecil secara lokal tetapi rusak parah ketika kode Anda berjalan di lingkungan yang berbeda.
Jebakan 2: Menampilkan Timestamp Tanpa Menentukan Timezone
Kebalikan dari jebakan 1. Anda mengonversi timestamp yang disimpan kembali ke tanggal yang dapat dibaca untuk ditampilkan:
new Date(1714000000 * 1000).toLocaleString()
// "4/25/2024, 7:46:40 AM" (pada mesin UTC-4)
// "4/25/2024, 1:46:40 PM" (pada mesin UTC+2)
Timestamp yang sama menampilkan waktu yang berbeda di mesin yang berbeda. Ini sering kali perilaku yang benar untuk tanggal yang menghadap pengguna — menampilkan waktu lokal kepada setiap pengguna masuk akal. Tetapi itu salah untuk log, catatan audit, respons API, dan apa pun yang perlu konsisten di seluruh sistem.
Untuk konsistensi, selalu render ke UTC atau tentukan timezone secara eksplisit:
new Date(1714000000 * 1000).toISOString()
// "2024-04-25T11:46:40.000Z" — selalu UTC, selalu konsisten
from datetime import datetime, timezone
datetime.fromtimestamp(1714000000, tz=timezone.utc).isoformat()
# "2024-04-25T11:46:40+00:00"
Jebakan 3: Daylight Saving Time di Batas-Batasnya
Transisi daylight saving time (DST) menyebabkan dua masalah spesifik.
"Jam yang diulang." Ketika jam mundur, jendela satu jam terjadi dua kali. Jika sistem Anda mencatat waktu lokal tanpa informasi timezone dan Anda mencoba mengonversi entri log tersebut ke timestamp, beberapa entri ambigu. 2:30 AM pada malam jatuh-mundur bisa menjadi kemunculan pertama atau kedua — dua timestamp yang berbeda.
"Jam yang terlewat." Ketika jam maju, satu jam tidak ada dalam waktu lokal. Job terjadwal pada 2:30 AM pada malam maju akan memicu lebih awal, memicu lambat, atau tidak memicu sama sekali, tergantung bagaimana penjadwal menangani celah tersebut.
Tidak satu pun dari masalah ini mempengaruhi Unix timestamp — penghitungan timestamp terus berlanjut tanpa gangguan melalui DST. Masalah hanya muncul ketika Anda mengonversi antara timestamp dan string waktu lokal. Cara memperbaikinya adalah menyimpan dan memproses timestamp di UTC di seluruh sistem Anda, hanya mengonversi ke waktu lokal di layer presentasi.
Jebakan 4: Kolom Database Menyimpan Format yang Salah
PostgreSQL memiliki dua jenis timestamp: TIMESTAMP WITHOUT TIME ZONE dan TIMESTAMP WITH TIME ZONE (juga dieja TIMESTAMPTZ).
TIMESTAMP WITHOUT TIME ZONE menyimpan string apa pun yang Anda berikan dan tidak melakukan penyesuaian timezone. Jika Anda memasukkan "2024-04-25 09:00:00" dari klien lokal, itulah yang disimpan — bahkan jika itu 09:00 di Chicago dan Anda mengharapkan 14:00 UTC.
TIMESTAMPTZ mengonversi ke UTC saat penulisan dan mengonversi kembali ke timezone sesi saat membaca. Ini biasanya apa yang Anda inginkan, tetapi ini berarti nilai yang ditampilkan bergantung pada SET TIME ZONE dalam sesi.
Untuk aplikasi yang perlu menghindari kompleksitas ini, menyimpan timestamp sebagai integer biasa (Unix detik) melewati layer timezone database sepenuhnya. Anda mengendalikan interpretasi di layer aplikasi.
DATETIME vs TIMESTAMP MySQL memiliki perbedaan serupa. TIMESTAMP mengonversi ke UTC pada penyimpanan dan kembali pada pengambilan. DATETIME menyimpan secara harfiah dan tidak melakukan apa pun dengan timezone.
Jebakan 5: Ketidakcocokan Milidetik vs Detik di API
Ini kurang tentang timezone dan lebih tentang skala, tetapi menghasilkan kategori bug timestamp yang membingungkan.
Date.now() JavaScript mengembalikan milidetik. Sebagian besar bahasa sisi server dan alat Unix menggunakan detik. Timestamp dalam detik saat ini adalah angka 10 digit (~1.714.000.000). Dalam milidetik, itu 13 digit (~1.714.000.000.000).
Ketika frontend JavaScript mengirim timestamp ke backend yang mengharapkan detik, hasilnya adalah tanggal tahun 57.000. Ketika backend mengirim detik ke JavaScript dan frontend menginterpretasinya sebagai milidetik, tanggal muncul di Januari 1970.
Unix Timestamp Converter mendeteksi format secara otomatis berdasarkan jumlah digit, yang berguna untuk pemeriksaan akal sehat nilai dari sistem yang berbeda.
Konvensi API teraman adalah mendokumentasikan secara eksplisit apakah timestamp dalam detik atau milidetik, dan memvalidasi nilai yang masuk di sisi server. Pemeriksaan rentang sederhana (tolak apa pun di bawah 1970 atau di atas 2100 dalam UTC) menangkap sebagian besar nilai yang tidak sesuai skala sebelum mereka merusak catatan.
Jebakan 6: Mengurai String Tanggal Ambigu
Tidak semua string tanggal menentukan timezone. "April 25, 2024", "04/25/2024", "2024-04-25" — tidak satu pun dari ini memiliki informasi timezone. Parser yang berbeda menanganinya secara berbeda.
JavaScript sangat tidak konsisten di sini. new Date("2024-04-25") memperlakukan input sebagai tengah malam UTC. new Date("04/25/2024") memperlakukannya sebagai tengah malam lokal. Format ISO 8601 dengan string tanggal saja adalah satu-satunya pengecualian untuk perilaku default lokal.
datetime.strptime("2024-04-25", "%Y-%m-%d") Python menghasilkan datetime naif (tidak ada timezone). Memanggil .timestamp() padanya menggunakan waktu lokal. Jika Anda berjalan di UTC, itu menghasilkan jawaban yang benar. Jika Anda berada di zona yang berbeda, itu tidak.
Aturan praktis: jangan pernah mengonversi string tanggal ke timestamp tanpa secara eksplisit mengetahui dan menentukan timezone apa yang diwakili string tanggal itu.
Pendekatan Konsisten yang Menghindari Semua Ini
Sebagian besar bug timestamp terkait timezone memiliki akar penyebab yang sama: informasi timezone masuk atau keluar dari sistem secara implisit. Konvensi berikut menghilangkan hampir semuanya:
1. Simpan timestamp sebagai UTC. Baik sebagai integer (Unix detik) atau sebagai TIMESTAMPTZ dalam database, simpan di UTC di seluruh. 2. Konversi ke waktu lokal hanya di layer presentasi. Lakukan konversi setelah mungkin, di UI, menggunakan preferensi timezone pengguna. 3. Gunakan ISO 8601 dengan offset eksplisit untuk timestamp apa pun yang Anda transmisikan sebagai string. 2024-04-25T11:46:40Z atau 2024-04-25T13:46:40+02:00 — keduanya tidak ambigu. 4. Validasi skala timestamp yang masuk. Tolak nilai yang akan menghasilkan tanggal di luar rentang yang masuk akal.
Untuk konversi sekali pakai dan pemeriksaan akal sehat, Unix Timestamp Converter menampilkan interpretasi UTC bersama dengan timestamp, yang memudahkan untuk memverifikasi bahwa nilai yang disimpan atau diterima sesuai dengan tanggal yang Anda harapkan.


