Menambah bulan pada tarikh lebih sukar daripada yang disangka

Menambah 7 hari pada tarikh adalah mudah. Anda dapat satu nombor, tambah 7, siap. Menambah satu bulan pula adalah masalah yang berbeza sepenuhnya.

Masalahnya ialah bulan mempunyai bilangan hari yang berbeza. Januari ada 31 hari. Februari ada 28, kadang-kadang 29. Jika anda berada pada 31 Januari dan menambah satu bulan, anda akan sampai ke 31 Februari — yang tidak wujud.

Setiap pustaka kalendar, hamparan (spreadsheet), dan pangkalan data ada pendapat tentang apa yang perlu dilakukan seterusnya.

Apa yang kebanyakan alat lakukan

Kelakuan yang paling biasa ialah “snap” ke hari terakhir bulan sasaran. 31 Januari + 1 bulan = 28 Februari (atau 29 pada tahun lompat). 31 Mac + 1 bulan = 30 April.

Ini dipanggil end-of-month clamping dan itulah yang Excel, Google Sheets, Python dateutil, dan kebanyakan pustaka tarikh lakukan secara lalai.

Ia masuk akal, tetapi ia mewujudkan masalah halus: operasi ini tidak boleh diterbalikkan. Jika anda tambah satu bulan pada 31 Januari, anda dapat 28 Februari. Jika anda kemudian tolak satu bulan, anda dapat 28 Januari — bukan 31 Januari. Anda telah “kehilangan” tiga hari.

Pendekatan overflow

Sesetengah sistem membenarkan tarikh “overflow” ke bulan seterusnya daripada melakukan clamping. 31 Januari + 1 bulan = 3 Mac (atau 2 Mac pada tahun lompat, kerana Februari ada 29 hari).

Ini mengekalkan jumlah bilangan hari, tetapi hasilnya jatuh dalam bulan yang berbeza sama sekali daripada yang anda maksudkan. Ia mengejutkan dan biasanya salah dari perspektif pengguna.

Sintaks INTERVAL SQL dalam sesetengah pangkalan data boleh berkelakuan begini bergantung pada konfigurasi. Mudah untuk tersilap jika anda tidak sedar kelakuan mana yang anda gunakan.

Menambah tahun mempunyai isu yang sama

29 Februari hanya wujud pada tahun lompat. Tambah satu tahun pada 29 Februari 2024, anda akan dapat 29 Februari 2025 — yang tidak wujud. Clamping akan memberi anda 28 Februari 2025.

Kelakuan yang sama, pertukaran (tradeoff) yang sama.

Bila ini benar-benar menyebabkan pepijat

Pengebilan langganan ialah contoh klasik. Seorang pengguna mendaftar pada 31 Januari. Tarikh bil seterusnya ialah 28 Februari. Kemudian 28 Mac. Kemudian 28 April. Setiap bulan selepas bulan pertama, mereka dibilkan 2–3 hari lebih awal daripada yang mereka jangkakan.

Acara kalendar berulang mempunyai isu yang sama. “Setiap bulan pada 31” secara senyap menjadi “setiap bulan pada hari terakhir” bagi bulan yang tidak sampai 31.

Jadual bayaran balik pinjaman, tarikh gaji, dan apa-apa yang berulang secara “bulanan” semuanya akan menemui kes tepi ini akhirnya.

Menambah hari tidak mempunyai masalah ini

Jika anda perlu menyatakan “30 hari dari sekarang” bukannya “satu bulan dari sekarang,” hanya tambah 30 hari. Hasilnya jelas dan boleh diterbalikkan.

Perbezaannya penting: kitaran bil 30 hari dan kitaran bil bulanan bukan perkara yang sama, dan ia akan cepat berbeza dari masa ke masa.

Apa yang perlu disemak dalam alat atau pustaka anda

Sebelum bergantung pada penambahan tarikh dalam mana-mana sistem, berbaloi untuk tahu:

  • Adakah ia clamp atau overflow pada tarikh hujung bulan?
  • Adakah ia mengekalkan hari-dalam-bulan (day-of-month) merentas beberapa penambahan, atau melakukan clamping semula setiap kali?
  • Untuk kes tepi tahun lompat, apa yang berlaku pada 29 Feb + 1 tahun?

Date Calculator menunjukkan hasil tepat untuk sebarang tarikh dan offset — berguna untuk semak kewarasan sebelum anda komited pada pengiraan dalam kod.

Artikel berkaitan