tidyverse / lubridate

Make working with dates in R just that little bit easier
https://lubridate.tidyverse.org
GNU General Public License v3.0
724 stars 207 forks source link

Cannot compute `<date> + lubridate::year(1)` when `<date>` is a leap day. #1159

Open Dreznel opened 5 months ago

Dreznel commented 5 months ago

Happy leap-day 😅

Notes

I'm using lubridate 1.8.0

Problem

Usually, I'm able to run lubridate::today() + lubridate::years(1) + 7 to get the date that is exactly one week from the day that is a year from today. Maybe not the best way to do that, but that's not the actual point.

I noticed today, February 29, 2024, that lubridate::today() + lubridate::years(1) returns NA.

Expectation

On the one hand, the current behavior makes sense if you see the function as "increment the year by one," but I think I was expecting the logic to be more complex and to account for leap days. Something like: "X + lubridate::years(Y) adds 365*Y days, plus 1 day for each leap day included in the date-range [X, Z) where Z is the resulting date (but exclusive of the resulting date)".

In other words, I think I would've wanted February 29, 2024 + 1 Year to be equal to March 1st, 2025 and February 29, 2024 + 4 Years to be equal to February 29, 2028

Reproducible example

lubridate::date("2024-02-28") + lubridate::years(1)
lubridate::date("2024-02-28") + 1
lubridate::date("2024-02-29") + lubridate::years(1) # NA
lubridate::date("2024-02-29") + lubridate::years(4) # Works
lubridate::date("2024-02-29") + 1
lubridate::date("2024-03-01") + lubridate::years(1)
lubridate::date("2024-03-01") + 1

Some other thoughts

I understand that my expected implementation is perhaps a bit more risky (maybe out of the ISO spec?). However, as it is, it's not possible (without writing workarounds) to write something that uses Date X + lubridate::year(Y) and increments Date X across a four-year span.

Anyway, I realize date times are a complex domain, so feel free to close if I'm off the mark here.

adwals commented 1 month ago

I think "Note" under the Detail section may help explain: https://lubridate.tidyverse.org/reference/period.html. The %m+% function may be what you need: https://lubridate.tidyverse.org/reference/mplus.html

mdy("02-29-2024") %m+% months(12)
"2025-02-28"`