Сгенерировать последовательность последнего дня месяца за два года

#r #date

#r #Дата #lubridate

Вопрос:

Я использую lubridate и подумал, что это будет так просто

 ymd("2010-01-31") months(0:23)
  

Но посмотрите, что получается. Все перепутано!

  [1] "2010-01-31 UTC" "2010-03-03 UTC" "2010-03-31 UTC" "2010-05-01 UTC" "2010-05-31 UTC" "2010-07-01 UTC" "2010-07-31 UTC" "2010-08-31 UTC" "2010-10-01 UTC"
[10] "2010-10-31 UTC" "2010-12-01 UTC" "2010-12-31 UTC" "2011-01-31 UTC" "2011-03-03 UTC" "2011-03-31 UTC" "2011-05-01 UTC" "2011-05-31 UTC" "2011-07-01 UTC"
[19] "2011-07-31 UTC" "2011-08-31 UTC" "2011-10-01 UTC" "2011-10-31 UTC" "2011-12-01 UTC" "2011-12-31 UTC"
  

Затем я прочитал, как lubridate учитывает такие явления, как интервал, длительность и период. Итак, хорошо, я понимаю, что месяц — это фактически количество дней, определенное (365*4 1)/48 = 30.438 дней. Поэтому я попытался поумнеть и переписать ее как

 ymd("2010-01-31")  as.period(months(0:23))
  

Но это просто выдало ошибку.

 Error in as.period.default(months(0:23)) : 
  (list) object cannot be coerced to type 'double'
  

Ответ №1:

Да, вы нашли правильный трюк: вернуться на день назад с первого числа следующего месяца.

Здесь в виде однострочной строки в базе R:

 R> seq(as.Date("2010-02-01"), length=24, by="1 month") - 1
 [1] "2010-01-31" "2010-02-28" "2010-03-31" "2010-04-30" "2010-05-31"
 [6] "2010-06-30" "2010-07-31" "2010-08-31" "2010-09-30" "2010-10-31"
[11] "2010-11-30" "2010-12-31" "2011-01-31" "2011-02-28" "2011-03-31"
[16] "2011-04-30" "2011-05-31" "2011-06-30" "2011-07-31" "2011-08-31"
[21] "2011-09-30" "2011-10-31" "2011-11-30" "2011-12-31"
R> 
  

Поэтому нет необходимости в lubridate, который (будучи прекрасным пакетом) не нужен для такой простой задачи, как эта. Кроме того, его перегрузка существующих базовых функций по-прежнему кажется мне несколько опасной…

Ответ №2:

Удивительно, как ввод вопроса фокусирует творческую энергию. Я думаю, что я разработал ответ. Я могу также опубликовать это здесь для следующей бедной души, которая считает, что тратит время впустую.

 ymd("2010-02-01")  months(0:23)-days(1)
  

Просто укажите первый день следующего месяца и сгенерируйте из него последовательность, но вычтите из нее 1 день, чтобы получить последний день предыдущего месяца.

 [1] "2010-01-31 UTC" "2010-02-28 UTC" "2010-03-31 UTC" "2010-04-30 UTC" "2010-05-31 UTC" "2010-06-30 UTC" "2010-07-31 UTC" "2010-08-31 UTC" "2010-09-30 UTC"
[10] "2010-10-31 UTC" "2010-11-30 UTC" "2010-12-31 UTC" "2011-01-31 UTC" "2011-02-28 UTC" "2011-03-31 UTC" "2011-04-30 UTC" "2011-05-31 UTC" "2011-06-30 UTC"
[19] "2011-07-31 UTC" "2011-08-31 UTC" "2011-09-30 UTC" "2011-10-31 UTC" "2011-11-30 UTC" "2011-12-31 UTC"
  

Кстати, как мне избавиться от надоедливых обозначений «UTC». Часовые пояса спасают жизнь, когда они необходимы. В остальное время они доставляют неудобства.

Комментарии:

1. используется strftime(date) , чтобы избавиться от часового пояса. это strftime('2010-10-31 UTC') дало бы вам 2010-10-31 .

2. @SachaEpskamp: Stackoverflow позволит мне принять мой ответ только через два дня. Я думаю, это довольно умно. Может быть другой обходной путь, который является более элегантным.

3. @Ramnath strftime дает мне дату предыдущего дня, потому что там, где я живу, полночь по Гринвичу фактически равна 19:00 предыдущего дня. Я нахожусь в восточном часовом поясе. strftime(ymd(«2010-02-01») месяцы(0:23)-дни(1)) [1] «2010-01-30 19:00:00» «2010-02-27 19:00:00» «2010-03-30 20:00:00» и т.д.