Как учитывать високосные годы?

У меня есть некоторые сомнения относительно високосных лет, как я могу быть уверен, что, используя формулу вроде этого

add.years= function(x,y){    
if(!isTRUE(all.equal(y,round(y)))) stop("Argument \"y\" must be an integer.\n")
x <- as.POSIXlt(x)
x$year <- x$year+y
as.Date(x)
}

он будет учитывать високосные годы, добавляя, например, 100 лет к моему набору данных наблюдения? Как я могу это контролировать?

У меня есть набор временных рядов с 50-летними наблюдениями:

   date    obs
1995-01-01 1.0
1995-01-02 2.0
1995-01-03 2.5
...
2045-12-30 0.2
2045-12-31 0.1

набор данных + 100 лет

   date    obs
2095-01-01 1.0
2095-01-02 2.0
2095-01-03 2.5
...
2145-12-30 0.2
2145-12-31 0.1

После базовой проверки я заметил, что количество строк одинаково для оригинала и 100 лет после набора данных. Я не уверен, будет ли то, что было до 29-го февраля в високосном году, будет теперь общепринятым для 1 марта в не-високосный год и т.д.

Я могу проверить високосные годы, используя chron library функцию leap.year, однако я хотел бы знать, есть ли более простой способ сделать это, чтобы убедитесь, что строки с пропущенными днями 29-го февраля, которые не существуют 100 лет спустя, будут удалены, а новые дни 29 февраля добавлены с значениями NA.

Ответы

Ответ 1

Вы можете проверить, год ли високосный год с leap_year от lubridate.

years <- 1895:2005
years[leap_year(years)]

Этот пакет также будет обрабатывать не генерировать невозможное 29 февраля.

ymd("2000-2-29") + years(1)    # NA
ymd("2000-2-29") %m+% years(1) # "2001-02-28"

Оператор %m+% "добавить месяцы", как указано @VitoshKa, возвращает дату до конца предыдущего месяца, если фактический день не существует.

Ответ 2

Год - это високосный год, если:

  • Делится на 4.
  • Нет, если он делится на 100.
  • Но если он делится на 400.

Вот почему 2000 год был високосным годом (хотя он делится на 100, он также делится на 400).

Но в целом, если у вас есть библиотека, которая может принимать вычисления даты/времени, то используйте ее. Очень сложно делать эти расчеты и легко ошибаться, особенно с древними датами (календарными реформами) и временными часами.

Ответ 3

Ваши подозрения действительно правильны:

x <- as.POSIXlt("2000-02-29")
y <- x
y$year <- y$year+100
y
#[1] "2100-03-01"

Странно, что другие части y остаются неизменными, поэтому вы не можете использовать их для сравнения:

y$mday
#[1] 29
y$mon
#[1] 1

Но вы можете использовать strftime:

strftime(x,"%d")
#[1] "29"
strftime(y,"%d")
#[1] "01"

Итак, как насчет:

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)
   } 

Затем вы можете подмножить свои данные с помощью [ и is.na, чтобы избавиться от дублированных дат 1 марта. Хотя, поскольку эти даты кажутся последовательными, вы можете рассмотреть решение, которое использует seq.Date и избегать удаления данных.