Cara Menambah Atau Mengurangi Tanggal: Model Mental Inti
Jika Anda perlu menambah atau mengurangi tanggal, 30 detik pertama menentukan apakah hasil Anda benar. Jawaban yang aman: gunakan alat atau fungsi yang membedakan antara durasi tetap (hari 24 jam) dan unit kalender (bulan, tahun dengan panjang variabel). Untuk pemeriksaan sekali pakai, Kalkulator Tambah/Kurang Tanggal kami menyelesaikan keduanya sambil menghormati tahun kabisat.
Di balik setiap kalkulator ada model mental. Tanggal adalah label dalam sistem kalender, bukan kuantitas fisik. Menambahkan ‘5 hari’ adalah penambahan bilangan bulat pada hitungan hari. Menambahkan ‘1 bulan’ adalah transformasi berbasis aturan karena bulan berkisar antara 28 hingga 31 hari. Saya belajar ini dengan cara yang sulit ketika skrip penggajian menambahkan timedelta(days=30) untuk gaji ‘bulanan’ dan bergeser ke akhir pekan, memicu perselisihan lembur.
Hal yang tidak diberitahukan siapa pun kepada Anda tentang pengurangan tanggal adalah bahwa ‘kurangi satu bulan’ ambigu di dekat akhir bulan. 31 Januari dikurangi satu bulan bisa menjadi 31 Desember, 30 Desember, atau bahkan 28 Desember tergantung pada sistemnya. Ambiguitas tunggal itu menyebabkan lebih banyak bug produksi daripada kesalahan zona waktu yang pernah saya lihat. Selalu perjelas niat sebelum membuat kode.
Ada dua jenis matematika tanggal: kronologis (waktu berlalu tetap) dan sipil (sejajar kalender). Gunakan kronologis untuk usia, interval sensor, dan SLA yang diukur dalam jam. Gunakan sipil untuk kontrak, ulang tahun penagihan, dan tenggat waktu manusia. Mencampurnya adalah akar dari sebagian besar kesalahan.
Wawasan lain: pengurangan kronologis dua tanggal menghasilkan durasi, tetapi hasilnya hanya bermakna jika keduanya berada di zona waktu yang sama. Penerbangan berangkat dari New York pukul 10 malam 1 Jan dan tiba di London pukul 10 pagi 2 Jan adalah perjalanan 11 jam, bukan 12 jam, karena offset UTC. Selalu konversi ke UTC sebelum mengurangi stempel waktu.
Di bawah ini adalah matriks keputusan cepat yang saya berikan kepada pengembang junior. Ini tidak lengkap, tetapi mencegah 80% insiden.
| Skenario | Metode yang disarankan | Mengapa |
|---|---|---|
| Penundaan tenggat waktu 10 hari | Penambahan hari kalender | Manusia mempersepsikan tanggal di kalender |
| Perpanjangan langganan bulanan | Penambahan bulan dengan penjepit akhir bulan | Hindari 3 Maret dari awal 31 Januari |
| Usia dalam tahun | Total hari / 365,25 atau pemeriksaan ulang tahun | Tahun kabisat merusak pengurangan sederhana |
| Delta log mesin | Selisih mikrodetik epoch Unix | Zona waktu tidak relevan, presisi diperlukan |
Perhatikan bahwa tidak satu pun di atas menyebutkan ‘cukup kurangi angka-angkanya.’ Pendekatan naif itu gagal saat Anda melewati batas bulan.
Mengapa Aritmetika Tanggal Rusak: Tahun Kabisat, Luapan Bulan, Dan Zona Waktu
Ketika saya pertama kali membangun sistem penagihan berulang pada tahun 2018, saya mengurangi 30 hari dari 31 Januari untuk menghitung prorata pengembalian dana. Kode PHP lama mengembalikan 31 Desember, tetapi ekspor Excel hilir menggesernya ke 1 Desember karena memperlakukan ‘pengurangan bulan’ sebagai ‘hari 31 minus 30 = hari 1.’ Ketidakcocokan itu membuat kami kehilangan akhir pekan untuk rekonsiliasi. Akar penyebabnya adalah mengabaikan semantik kalender.
Tahun kabisat mengikuti aturan bahwa tahun yang habis dibagi 4 adalah kabisat, kecuali abad yang tidak habis dibagi 400. Menurut Institut Standar dan Teknologi Nasional, ini menjaga kalender sipil sejajar dengan orbit Bumi. Jika Anda mengkodekan keras ‘Februari memiliki 28 hari,’ Anda akan meleset satu hari pada 29 Feb 2024, 2028, dan setiap tahun keempat setelahnya.
Kalender Gregorian diadopsi pada waktu yang berbeda oleh negara yang berbeda; untuk tanggal historis sebelum 1752 di Inggris, Anda mungkin perlu kalender Julian. Pustaka seperti dateutil Python tidak menangani pra-Gregorian secara otomatis. Jika Anda menghitung usia dokumen tahun 1700-an, konsultasikan dengan sejarawan daripada mempercayai fungsi.
Luapan bulan adalah pembunuh diam-diam. Menambahkan satu bulan ke 31 Januari seharusnya menghasilkan 28 Februari (atau 29). Beberapa bahasa seperti objek Date asli JavaScript malah bergulir ke 3 Maret. Perilaku itu didokumentasikan tetapi mengejutkan pendatang baru. Selalu uji tepi akhir bulan dengan pengujian unit.
Zona waktu menambah lapisan lain. Jika Anda menyimpan tanggal sebagai ‘2023-03-12’ di New York dan mengurangi satu hari tanpa konteks zona waktu, Anda mungkin melewati batas waktu musim panas dan mendapatkan interval 23 jam atau 25 jam. Untuk tanggal murni (tanpa waktu), gunakan tipe khusus tanggal; untuk stempel waktu, gunakan UTC secara internal dan konversi di tepi.
Aturan hari kerja adalah dimensi terpisah. Mengurangi lima ‘hari’ dari Jumat memberi Rabu jika Anda menghitung hari kalender, tetapi jika Anda bermaksud lima hari kerja, Anda mendarat pada Jumat berikutnya. WORKDAY Excel dan numpy busday_offset Python menangani ini; pengurangan mentah tidak. Standar ISO 8601 merekomendasikan format yang tidak ambigu tetapi tidak mendefinisikan matematika hari kerja.
Jebakan tersembunyi lainnya: masalah Tahun 2038. Sistem yang menyimpan waktu sebagai bilangan bulat 32-bit bertanda akan meluap pada 19-01-2038. Jika Anda menghitung tanggal jauh di masa depan (hipotek, model iklim), gunakan tipe 64-bit atau pustaka tanggal asli.
Cara Menambah Atau Mengurangi Tanggal Di Excel Dan Google Sheets
Spreadsheet menyimpan tanggal sebagai nomor seri. Sistem tanggal 1900 default Excel dimulai pada 1 Januari 1900 sebagai hari 1, tetapi secara keliru memperlakukan 1900 sebagai tahun kabisat—bug yang diwarisi dari Lotus 1-2-3. Google Sheets menggunakan sistem serupa yang berlabuh pada 30 Desember 1899. Untuk tanggal modern ini jarang penting, tetapi menjelaskan mengapa DATE(1900,2,29) valid di Excel.
Untuk menambah hari, cukup gunakan =A1+30. Untuk mengurangi, =A1-15. Ini adalah aritmetika kronologis dan aman karena hari seragam. Sel hasil mungkin menampilkan angka; format sebagai Tanggal untuk melihat nilai kalender.
Untuk bulan kalender, gunakan EDATE(A1,1) untuk menambah satu bulan, EDATE(A1,-3) untuk mengurangi tiga. EDATE menjepit ke akhir bulan: EDATE(‘2023-01-31’,1) mengembalikan 2023-02-28. Itu perilaku yang kebanyakan bisnis inginkan. Saya pernah mengaudit lembar di mana analis menggunakan DATE(YEAR(A1),MONTH(A1)+1,DAY(A1)) dan mendapatkan 3 Maret untuk 31 Jan; kesalahan itu tidak terdeteksi selama dua kuartal.
Untuk tahun, gunakan EDATE(A1,12) atau DATE(YEAR(A1)+1,MONTH(A1),DAY(A1)). Yang terakhir rusak pada ulang tahun kabisat 29 Feb; DATE(2024,2,29) baik-baik saja tetapi DATE(2025,2,29) error. Lebih suka EDATE untuk ketahanan.
Perlu hari kerja? WORKDAY(A1,5) menambah lima hari kerja melewati akhir pekan. WORKDAY.INTL memungkinkan Anda mendefinisikan hari akhir pekan khusus—kritis untuk kalender Timur Tengah di mana Jumat-Sabtu adalah non-kerja. NETWORKDAYS(mulai,akhir) mengembalikan jumlah hari kerja antara dua tanggal, berguna untuk perencanaan sprint.
Ada juga DATEDIF, fungsi Excel yang tidak terdokumentasi tetapi didukung yang menghitung perbedaan dalam hari, bulan, atau tahun. DATEDIF(A1,B1,’m’) mengembalikan bulan penuh antara tanggal. Ini berguna tetapi gagal jika tanggal mulai lebih lambat dari tanggal akhir, mengembalikan kesalahan #NUM. Saya menggunakannya untuk perhitungan masa kerja. Google Sheets mendukung DATEDIF juga, dengan sintaks identik, tetapi kedua alat memperlakukan bulan parsial sebagai nol bulan, yang mengejutkan pengguna yang mengharapkan ‘1 bulan 1 hari’ untuk dibulatkan ke atas.
Jebakan umum: pemformatan. Jika hasil Anda menampilkan angka seperti 45012, sel diformat sebagai Umum. Klik kanan, format sebagai Tanggal. Saya pernah melihat analis menempel nilai ke SQL sebagai bilangan bulat dan bertanya-tanya mengapa join gagal. Juga, Excel di Windows dan Mac mungkin menggunakan dasar tanggal berbeda jika sistem 1904 diaktifkan—periksa File > Opsi.
Panduan Pengembang: Aritmetika Tanggal Di Python, SQL, Dan JavaScript
Python: Gunakan Relativedelta Untuk Matematika Kalender
Fungsi bawaan Python datetime.timedelta hanya menerima hari (dan detik). timedelta(days=30) bukan ‘satu bulan.’ Ketika pertama kali saya mengotomatiskan pembuatan laporan, saya menggunakan timedelta(days=30) untuk siklus ‘bulanan’ dan meleset 5 hari selama setahun. Perbaikannya adalah dateutil.relativedelta: from dateutil.relativedelta import relativedelta; d + relativedelta(months=1) dengan benar mengembalikan penjepitan akhir bulan.
Untuk zona waktu, gunakan zoneinfo (Python 3.9+) atau pytz. Selalu simpan UTC dan terapkan zona waktu hanya untuk tampilan. Mengurangkan datetime yang sadar zona menghasilkan timedelta yang menghormati offset DST. Pustaka seperti Pendulum menyederhanakan ini: pendulum.parse(‘2023-01-31’).add(months=1) menghasilkan 28 Feb.
Pandas menggunakan Timestamp dan Timedelta; menambahkan satu bulan tidak didukung secara langsung—Anda harus menggunakan DateOffset(months=1) yang menghormati akhir bulan. Tetapi waspadalah: DateOffset dapat menghasilkan indeks non-monoton jika diterapkan pada Series dengan panjang bulan yang campur. Saya telah mengajukan bug tentang ini; solusinya adalah menerapkan melalui lambda dengan relativedelta.
SQL: Penanganan Interval Khusus Dialek
Di PostgreSQL, SELECT ‘2023-01-31’::date + INTERVAL ‘1 month’ menghasilkan 2023-02-28. DATE_ADD(‘2023-01-31′, INTERVAL 1 MONTH) MySQL melakukan hal yang sama. DATEADD(month,1,’2023-01-31’) SQL Server juga menjepit. Tetapi date(‘2023-01-31′,’+1 month’) SQLite juga menjepit. Jeratnya adalah mengasumsikan semua dialek menangani interval negatif atau batas tahun secara identik—selalu tulis unit test untuk 31 Des + 1 bulan = 31 Jan.
ADD_MONTHS Oracle adalah standar emas untuk penjepitan, tetapi perilakunya dengan ulang tahun kabisat eksplisit: ADD_MONTHS(DATE ‘2024-02-29’, 12) mengembalikan 2025-02-28. Itu didokumentasikan. Sementara itu, PERIOD_ADD MySQL ada untuk periode YYYYMM, bukan tanggal lengkap. Pilih fungsi yang dibuat khusus untuk tanggal, bukan manipulasi string.
Untuk hari kerja di SQL, Anda sering memerlukan tabel kalender. Saya memelihara tabel tanggal yang dihasilkan dengan flag is_weekday dan is_holiday; lalu join lateral menghitung ke depan. Itu bertele-tele tetapi transparan dan menghindari ketergantungan fungsi proprietary.
JavaScript: Perangkap Overflow Bulan
New Date(2023, 0, 31) adalah 31 Jan. Mengatur bulan ke 1 (Februari) dengan tanggal 31 menggulung ke 3 Maret. Untuk menambahkan bulan dengan aman, gunakan pustaka seperti date-fns addMonths atau Luxon’s plus({months:1}), yang menjepit. Jika Anda harus menggunakan Date asli, kurangi overflow hari secara manual. Bug tunggal ini telah merusak banyak penghitung waktu mundur.
Intl.DateTimeFormat modern dapat memformat hasilnya, tetapi tidak melakukan aritmatika. Untuk manipulasi tanggal berat di Node, saya merekomendasikan Luxon karena Immutable DateTime.plus({months:1}) mengembalikan objek baru dan tidak pernah mengubah. Mutasi Date asli melalui setMonth adalah sumber umum race condition dalam kode async. Juga perhatikan bahwa getFullYear, getMonth (berindeks 0), dan getDate JavaScript adalah waktu lokal; gunakan varian getUTCDate saat bekerja dengan timestamp server. Referensi Date MDN mendokumentasikan keanehan ini secara rinci.
Teknik Perhitungan Mental Manual (Tanpa Alat)
Anda tidak selalu memiliki laptop. Ini trik lapangan yang saya gunakan: konversi tanggal mulai menjadi ‘hari tersisa dalam bulan,’ lalu bawa overflow seperti penjumlahan dasar. Butuh 10 detik setelah berlatih.
- Langkah 1: Catat hari-bulan dan hari dalam bulan itu (30 untuk Apr/Jun/Sep/Nov, 31 lainnya, 28/29 Feb).
- Langkah 2: Tambahkan hari target Anda. Jika jumlah melebihi panjang bulan, kurangi panjang bulan, pindah ke bulan berikutnya.
- Langkah 3: Untuk bulan, hitung mundur dari Desember jika mengurangkan; ingat Feb kabisat memiliki 29.
Contoh: Tambahkan 45 hari ke 15 Jan. Jan memiliki 31, jadi 16 hari tersisa di Jan (31-15). 45-16=29 ke Feb. 29 Feb (tahun kabisat) jadi hasilnya 29 Feb. Jika tidak kabisat, 28 Feb dan 1 hari tumpah ke 1 Mar. Ini cocok dengan apa yang EDATE hasilkan untuk hari 15 plus satu bulan plus 14 hari.
Mari berlatih yang lebih sulit: kurangi 100 hari dari 20 Mei. Mei memiliki 31, jadi hari tersisa di Mei setelah 20 = 11. 100-11=89 ke Apr (30) menyisakan 59, Mar (31) menyisakan 28, Feb (28 di non-kabisat) menyisakan 0, jadi kita masih perlu menempatkan 28 hari di Jan? Tunggu, hitung ulang: Mundur: 20 Mei minus 20 hari = 30 Apr (menyisakan 80). 30 lagi ke 31 Mar (menyisakan 50). 31 lagi ke 28 Feb (menyisakan 19). 19 hari mundur dari 28 Feb = 9 Feb. Jadi hasilnya 9 Feb. Latihan membangun kepercayaan diri.
Untuk mengurangkan bulan secara mental, jangkar pada nomor hari yang sama; jika hari itu tidak ada, jepret ke hari terakhir. Itu aturan yang digunakan EDATE, dan itu default yang masuk akal. Saya menyebutnya aturan ‘penjepit hari-terakhir.’ Kebanyakan orang tidak menyadari bahwa alternatif (menggulung ke depan) adalah pilihan desain, bukan kebenaran universal.
Lembar contekan cepat panjang bulan: ‘Tiga puluh hari memiliki September, April, Juni, dan November…’ masih berfungsi. Untuk matematika tahun, ingat 365 hari biasanya, 366 di kabisat. Untuk mengurangkan tahun dari ulang tahun kabisat (29 Feb), konvensi hukum di banyak yurisdiksi adalah menggunakan 28 Feb di tahun non-kabisat untuk tujuan usia.
Kasus Penggunaan Dunia Nyata Dan Lembar Contekan Cepat
Jadwal proyek: Jika tonggak meleset 10 hari kerja, gunakan WORKDAY bukan +10. Saya pernah menggeser tanggal peluncuran dengan hari kalender dan melewatkan jendela regulasi karena hari libur di antaranya. Peluncuran produk tertunda seminggu lagi karena dokumen.
Perhitungan usia: Kurangi tanggal lahir dari hari ini menggunakan total hari / 365,25, bukan mengurangkan tahun secara langsung, untuk memperhitungkan tahun kabisat. Usia hukum sering menggunakan tahun kalender tepat (ulang tahun). Misalnya, anak yang lahir 29 Feb 2020 berusia empat tahun pada 28 Feb 2024 di banyak negara bagian AS, tetapi pada 1 Mar di yang lain—periksa hukum setempat.
Siklus penagihan: Langganan diperbarui pada ‘hari yang sama bulan depan.’ Jika dimulai 31 Jan, pembaruan Februari harus 28 Feb, bukan 3 Mar. Di sinilah Kalkulator Tambah/Kurang Tanggal atau logika EDATE mencegah penagihan berlebih. Saya pernah melihat faktur SaaS untuk ‘3 Mar’ menyebabkan churn karena pelanggan merasa ditipu.
Uji klinis: Protokol sering menentukan ‘plus 28 hari’ dari dosis. Itu durasi tetap, bukan bulan. Menggunakan penambahan bulan akan meleset dengan kalender. Selalu petakan kata-kata protokol ke jenis aritmatika yang benar.
Batas imigrasi: Visa ‘berlaku 90 hari’ berarti hari kronologis, bukan tiga bulan. Mengurangkan tiga bulan dari tanggal kedaluwarsa bisa memberikan hari ekstra secara ilegal. Gunakan penambahan hari secara eksklusif.
Periode garansi: ‘1 tahun dari pembelian’ adalah penambahan kalender; ‘365 hari’ adalah tetap. Tahun kabisat yang disisipkan membuatnya berbeda satu hari. Sistem ritel sering memilih 365 hari untuk menyederhanakan kueri basis data, tetapi itu bisa merugikan pelanggan satu hari di tahun kabisat. Hal yang kebanyakan orang tidak sadari adalah bahwa hukum perlindungan konsumen kadang mewajibkan tahun kalender.
Aturan praktis: Jika manusia menulis tanggal di kontrak, gunakan aritmatika kalender. Jika sensor membubuhkan timestamp, gunakan durasi tetap.
Tabel referensi cepat fungsi lintas platform:
| Platform | Tambah hari | Tambah bulan (aman) | Hari kerja |
|---|---|---|---|
| Excel/Sheets | =A1+30 | =EDATE(A1,1) | =WORKDAY(A1,5) |
| Python | d + timedelta(days=30) | d + relativedelta(months=1) | np.busday_offset |
| SQL (Postgres) | date + 30 | date + interval ‘1 month’ | tabel kalender |
| JavaScript | new Date(d.getTime()+864e5) | date-fns addMonths | loop khusus |
Perangkap Umum Dan Cara Mengaudit Logika Tanggal Anda
Kesalahan format: ‘2023-04-01′ vs ’04/01/2023’ (AS vs UE) membalik bulan dan hari. Parse dengan string format eksplisit; jangan pernah mengandalkan default lokal. Di Python, gunakan datetime.strptime(date_str, ‘%Y-%m-%d’). Di SQL, gunakan TO_DATE dengan mask format.
Tanggal negatif: Beberapa sistem mengizinkan tahun nol atau negatif (astronomis), tetapi Excel rusak sebelum 1900. Ketahui rentang valid domain Anda. Perangkat lunak silsilah sejarah sering menggunakan ISO 8601 diperluas untuk tahun sebelum 1000 dengan nol di depan.
Dengan asumsi 52 minggu = 364 hari: Tahun memiliki 365 atau 366 hari, jadi ‘menambahkan 52 minggu’ bergeser satu hari. Gunakan fungsi bulan/tahun untuk peringatan. Saya pernah melihat laporan tahunan meleset satu hari karena seseorang menambahkan 52*7 hari.
Penggabungan string: Jangan pernah membuat tanggal dengan menggabungkan tahun+’-‘+bulan+1. Itu menghasilkan ‘2023-2-1’ yang beberapa parser tolak. Gunakan format dengan padding.
Karakter Unicode dalam string tanggal (misalnya, spasi non-breaking) menyebabkan kegagalan parsing yang senyap. Saya pernah men-debug CSV di mana tanggal terlihat seperti ‘2023-01-01 ‘ tetapi memiliki spasi trailing U+00A0; parser tidak melempar error, hanya mengembalikan null. Trim dan normalisasi sebelum parsing.
Daftar periksa audit yang saya jalankan sebelum merilis kode tanggal apa pun: (1) Uji 31 Januari ± bulan; (2) Uji 29 Februari di tahun kabisat dan non-kabisat; (3) Uji batas DST; (4) Konfirmasi penyimpanan zona waktu; (5) Verifikasi definisi akhir pekan untuk hari kerja; (6) Periksa batas tahun 2038 jika menggunakan int 32-bit. Jika semua lolos, kemungkinan besar Anda aman.
Terakhir, dokumentasikan pilihan Anda. Komentar seperti ‘menggunakan penambahan bulan kalender, menjepit ke akhir bulan’ menyelamatkan insinyur berikutnya dari ‘memperbaikinya’ menjadi 3 Maret. Logika tanggal tidak terlihat sampai menjadi salah secara katastropik.
