Как учитывать високосные годы? - PullRequest
15 голосов
/ 13 декабря 2011

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

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 library функцию leap.year , однако я хотел бы знать, есть ли более простой способ сделать это, чтобы быть уверенным что строки со днями пропуска 29 февраля, которые не существуют 100 лет спустя, будут удалены, а новые дни 29 февраля добавлены со значениями NA.

Ответы [ 4 ]

14 голосов
/ 13 декабря 2011

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

3 голосов
/ 13 декабря 2011

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

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

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

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

1 голос
/ 13 декабря 2011

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

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

0 голосов
/ 29 августа 2018

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