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

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

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 февраля в високосный год, будет теперь значением obs для 1 марта в не високосный год и т. Д.

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

4 ответа

Решение

Вы можете проверить, является ли год високосным 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, откатывает дату обратно к концу предыдущего месяца, если фактический день не существует.

Следуя предложению DarkDust и Dirk Eddelbuettel, вы можете легко бросить свой собственный leap_year функция:

leap_year <- function(year) {
  return(ifelse((year %%4 == 0 & year %%100 != 0) | year %%400 == 0, TRUE, FALSE))
}

и применить его к векторным данным:

years = 2000:2050
years[leap_year(years)]

[1] 2000 2004 2008 2012 2016 2020 2024 2028 2032 2036 2040 2044 2048

Год является високосным, если:

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

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

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

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

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 и избегайте сброса данных.

Другие вопросы по тегам