Dodavanje meseci datumu je teže nego što zvuči

Dodati 7 dana datumu je jednostavno. Imaš broj, dodaš 7, gotovo. Dodavanje meseca je potpuno drugačiji problem.

Problem je u tome što meseci nemaju istu dužinu. Januar ima 31 dan. Februar ima 28, ponekad 29. Ako si na 31. januaru i dodaš jedan mesec, dobijaš 31. februar — a taj datum ne postoji.

Svaka biblioteka kalendara, svaka tabela i svaka baza podataka ima svoje mišljenje o tome šta treba uraditi.

Šta radi većina alata

Najčešće ponašanje je da se datum “spusti” na poslednji dan ciljnog meseca. 31. januar + 1 mesec = 28. februar (ili 29 u prestupnoj godini). 31. mart + 1 mesec = 30. april.

Ovo se zove ograničavanje na kraj meseca (end-of-month clamping) i to je ono što Excel, Google Sheets, Python dateutil i većina biblioteka za datume rade podrazumevano.

Razumno je, ali pravi suptilan problem: operacija nije reverzibilna. Ako dodaš jedan mesec na 31. januar, dobiješ 28. februar. Ako zatim oduzmeš jedan mesec, dobiješ 28. januar — ne 31. januar. Izgubio si tri dana.

Pristup sa “prelivanjem”

Neki sistemi dopuštaju da se datum “prelije” u sledeći mesec umesto da se ograniči. 31. januar + 1 mesec = 3. mart (ili 2. mart u prestupnoj godini, jer februar tada ima 29 dana).

Ovo čuva ukupan broj dana, ali rezultat završava u potpuno drugom mesecu nego što si nameravao. Iznenađujuće je i uglavnom pogrešno iz perspektive korisnika.

SQL INTERVAL sintaksa u nekim bazama to radi u zavisnosti od konfiguracije. Lako je da se opečeš ako ne znaš koje ponašanje koristiš.

Dodavanje godina ima isti problem

29. februar postoji samo u prestupnim godinama. Dodaj jednu godinu na 29. februar 2024. i dobijaš 29. februar 2025 — a to ne postoji. Ograničavanje te dovodi na 28. februar 2025.

Isto ponašanje, isti kompromisi.

Kada ovo zaista pravi bagove

Pretplate i naplata su klasičan primer. Korisnik se prijavi 31. januara. Sledeći datum naplate je 28. februar. Zatim 28. mart. Zatim 28. april. Svakog meseca posle prvog, naplata se pomera 2–3 dana ranije nego što bi očekivali.

Ponovljeni događaji u kalendaru imaju isti problem. “Svakog meseca 31.” tiho postaje “svakog meseca poslednjeg dana” za mesece koji nemaju 31 dan.

Rasporedi otplate kredita, datumi isplate plata i sve što ima “mesečno” ponavljanje pre ili kasnije naleti na ovaj rubni slučaj.

Dodavanje dana nema ovaj problem

Ako želiš da izraziš “za 30 dana” umesto “za jedan mesec”, samo dodaj 30 dana. Rezultat je jednoznačan i reverzibilan.

Razlika je bitna: ciklus naplate od 30 dana i mesečni ciklus naplate nisu isto i brzo se razilaze kroz vreme.

Šta treba proveriti u alatu ili biblioteci

Pre nego što se osloniš na dodavanje datuma u bilo kom sistemu, vredi znati:

  • Da li na kraju meseca ograničava ili “preliva”?
  • Da li čuva dan u mesecu kroz više dodavanja ili ponovo ograničava svaki put?
  • Kod prestupnih godina, šta se dešava sa 29. feb + 1 godina?

Date Calculator ti pokazuje tačan rezultat za bilo koji datum i pomeraj — korisno za proveru pre nego što se obavežeš na računanje u kodu.

Сродни чланци