lubridate
lubridate copied to clipboard
update and make_datetime handling of Februray 29
Hi I have found a bug in update, the roll argument does not seem to be doing anything. Even when set to FALSE it is returning the next valid point instead of NA for non existing date-times.
Similarly make_datetime rolls to the next date by default, with no option to change this which would be desirable.
library(lubridate)
LeapYearDate <- as.POSIXct("2016-02-29, 02:00", tz = "UTC")
update(LeapYearDate, years = 2015,roll = FALSE)
#> [1] "2015-03-01 UTC"
update(LeapYearDate, years = 2015,roll = TRUE)
#> [1] "2015-03-01 UTC"
make_datetime(year = 2015, month = 2, day = 29)
#> [1] "2015-03-01 UTC"
Created on 2019-05-28 by the reprex package (v0.3.0)
So looking at this for the TDD there are two issues here, the first is that roll doesn't seem to be returning NA when false. The second, as far as I can tell looking at the make_datetime code is doesn't appear to have any checks to see if the date is a valid date?
Looks like another issue fixed by timechange:
library(lubridate, warn.conflicts = FALSE)
x <- as.POSIXct("2016-02-29, 02:00", tz = "UTC")
update(x, years = 2015)
#> [1] "2015-03-01 UTC"
update(x, years = 2015, roll = FALSE)
#> [1] "2015-03-01 UTC"
timechange::time_update(x, year = 2015)
#> [1] "2015-03-01 UTC"
timechange::time_update(x, year = 2015, roll_month = "NA")
#> [1] NA
Created on 2019-11-19 by the reprex package (v0.3.0)
This is an error by default in clock, which provides multiple ways to resolve the invalid date:
library(clock)
x <- as.POSIXct("2016-02-29, 02:00", tz = "UTC")
# Error by default
set_year(x, 2015)
#> Error: Invalid date found at location 1.
#> ℹ Resolve invalid date issues by specifying the `invalid` argument.
# If you want to throw this out
set_year(x, 2015, invalid = "NA")
#> [1] NA
# Next moment in time
set_year(x, 2015, invalid = "next")
#> [1] "2015-03-01 UTC"
# Previous moment in time
set_year(x, 2015, invalid = "previous")
#> [1] "2015-02-28 23:59:59 UTC"
Created on 2021-05-25 by the reprex package (v1.0.0)
roll argument wasn't affecting rolling behavior of month days. It was controling only the DST skipped behavior. There are new arguments in lubridate roll_month and roll_dst which allow for full control of rolling and updating.
> leap <- ymd_hms("2016-02-29 02:00:00", tz = "UTC")
> update(leap, years = 2015, roll_month = "postday")
[1] "2015-03-01 02:00:00 UTC"
> update(leap, years = 2015, roll_month = "preday")
[1] "2015-02-28 02:00:00 UTC"
> update(leap, years = 2015, roll_month = "boundary")
[1] "2015-03-01 UTC"