I have some doubts about the leap years, how can I be sure that by using a formula like this
add.years= function(x,y){
if(!isTRUE(all.equal(y,round(y))))
A year is a leap year if:
That is why 2000 was a leap year (although it's divisible by 100, it's also divisible by 400).
But generally, if you have a library that can take of date/time calculations then use it. It's very complicated to do these calculations and easy to do wrong, especially with ancient dates (calendar reforms) and timezones involved.
You can check if a year is a leap year with leap_year
from lubridate
.
years <- 1895:2005
years[leap_year(years)]
This package will also handle not generating impossible 29ths of February.
ymd("2000-2-29") + years(1) # NA
ymd("2000-2-29") %m+% years(1) # "2001-02-28"
The %m+%
"add months" operator, as mentioned by @VitoshKa, rolls the date back to the end of the previous month if the actual day doesn't exist.
Following the suggestion of DarkDust and Dirk Eddelbuettel, you can easily roll your own leap_year
function:
leap_year <- function(year) {
return(ifelse((year %%4 == 0 & year %%100 != 0) | year %%400 == 0, TRUE, FALSE))
}
and apply it to vector data:
years = 2000:2050
years[leap_year(years)]
[1] 2000 2004 2008 2012 2016 2020 2024 2028 2032 2036 2040 2044 2048
Your suspicions are indeed correct:
x <- as.POSIXlt("2000-02-29")
y <- x
y$year <- y$year+100
y
#[1] "2100-03-01"
The strange thing is that other parts of y
remain unchanged so you can't use these for comparison:
y$mday
#[1] 29
y$mon
#[1] 1
But you can use strftime
:
strftime(x,"%d")
#[1] "29"
strftime(y,"%d")
#[1] "01"
So how about:
add.years <- function(x,y){
if(!isTRUE(all.equal(y,round(y)))) stop("Argument \"y\" must be an integer.\n")
x.out <- as.POSIXlt(x)
x.out$year <- x.out$year+y
ifelse(strftime(x,"%d")==strftime(x.out,"%d"),as.Date(x.out),NA)
}
You can then subset your data using [
and is.na
to get rid of the otherwise duplicate 1st March dates. Though as these dates seem to be consecutive, you might want to consider a solution that uses seq.Date
and avoid dropping data.