Kolom event_date yang Selalu NULL dan Tabel Bulan 13 Entri
Data tanggal berbahasa Indonesia membuat kolom event_date kosong terus. Parser locale stdlib bukan jawabannya; tabel bulan eksplisit iya.
Ringkasan
Tanggal dari feed dateng dalam bentuk teks kayak Senin, 08 Jun. 2026, tapi mapper cuma coba fromisoformat, jadinya gagal diam-diam dan event_date kosong semua. Ide pake locale Python ketolak soalnya nggak thread-safe plus bug-nya numpuk sejak 2010.
Kueri rentang tanggal yang selalu kosong
Kolom event_date ada di skema, tipe datanya benar, tapi setiap kueri rentang tanggal di DemandScope kembali tanpa satu baris pun. Pengecekan cepat ke data mentah menunjukkan penyebabnya: feed panen mengirim tanggal sebagai teks Indonesia seperti Senin, 08 Jun. 2026, sementara mapper hanya mencoba date.fromisoformat yang langsung melempar ValueError Invalid isoformat string untuk teks itu. Pengecualiannya ditangkap, hasilnya None, dan kolom kosong terus. Dua puluh perkara yang sudah masuk, dua puluh tanggal yang hilang tanpa error satu pun.
Bagian yang paling mengganggu dari bug seperti ini bukan kegagalannya, melainkan keramahannya. Tidak ada log merah, tidak ada retry yang gagal. Nilai NULL terlihat seperti data yang memang belum ada.
Tebakan pertama: andalkan locale
Dugaan awal saya sederhana: Python punya strptime dengan format %b untuk nama bulan singkat, tinggal set locale proses ke Indonesia. Dugaan itu runtuh di tiga titik sekaligus. Modul locale dinyatakan membuka akses ke basis data locale POSIX, dan setlocale tidak thread-safe karena mengubah status global seluruh proses [6]. Nama bulan di modul calendar pun mengikuti locale saat ini, bukan daftar tetap [7]. Mesin locale stdlib sendiri punya riwayat panjang: bug strptime terhadap strftime di beberapa locale terbuka sejak 2010 [8], dan baru 2025 ada perbaikan untuk nama bulan yang memuat karakter İ pada locale tertentu [9].
Probe langsung menegaskannya. Di host ini, strptime dengan format %d %b %Y menolak teks 08 Jun. 2026, dan itu belum menyentuh kasus host dengan locale bukan-Inggris. Mengganti bahasa proses demi satu parser berarti menyeret seluruh aplikasi ke dalam state global yang rapuh.
Tabel bulan 13 entri dan satu sumber kebenaran
Perbaikan yang dipilih justru yang paling tidak canggih: fungsi parse_sipp_date dengan tabel 13 nama bulan Indonesia, termasuk pemetaan ganda agu dan ags ke bulan 8. Regex _SIPP_DATE mengabaikan awalan nama hari dan menangkap pola hari-bulan-tahun, jadi bentuk singkatan dan nama penuh sama-sama lolos. Fungsi event_date_for mengurutkan sumber tanggal: field putusan lebih dulu, registration_date sebagai cadangan, dan pintasan langsung untuk teks yang sudah ISO.
Bagian yang lebih penting dari parser adalah daftar fieldnya. Tuple EVENT_DATE_FIELDS kini hidup di domain sebagai satu sumber kebenaran, dan mapper mengimpornya untuk dua keperluan sekaligus: memutuskan field mana yang diparse, dan field mana yang dikeluarkan dari detail. Sebelumnya ada dua tupel terpisah yang isinya sama, dan keduanya bisa bergeser arah tanpa suara. Parse yang gagal juga tidak dibuang: teks mentah tetap disimpan di details, kolom target jujur berisi NULL dengan bukti aslinya utuh.
Verifikasinya berlapis dan semuanya bisa diulang. Lima puluh tiga test hijau, empat di antaranya baru untuk parser ini. Remap langsung 20 perkara lama lewat mapper_version:3 mengisi 20 dari 20 event_date, kueri rentang tanggal langsung berguna, dan re-ship 20 kali di kondisi steady-state menghasilkan nol perubahan. Parser berikutnya yang menemui format tanggal lokal akan melewati jalan yang sama: tabel eksplisit di domain, bukan locale proses yang bisa berubah tanpa sepengetahuan siapa pun.