Формат дата-время в R

Узнаем дату, запросив её у системы:

Sys.Date()
## [1] "2019-05-31"

Если попробуем обойтись без модуля Sys, получим сразу и дату, и время, и день недели:

date()
## [1] "Fri May 31 18:24:39 2019"

Те элементы, которые мы получили, имеют разные типы: первый результат имеет особый тип Date, который можно преобразовать в число (число секунд, например, отсюда double в typeof()), а второй является обычной строкой.

class(Sys.Date())
## [1] "Date"
typeof(Sys.Date())
## [1] "double"
class(date())
## [1] "character"

Тот же строковый тип мы получим, если посмотрим на обычную дату, сохраненную как текст:

class("2019-04-25")
## [1] "character"

Если мы хотим работать с датами и временем, такой формат данных нам неудобен: мы не сможем вычесть из одной строки другую и понять, сколько времени прошло с одного момента времени до другого. Можно, конечно, написать свою функцию, которая будет разделять строку с датой-временем на части и приводить все к числовому виду, но это неудобно и нерационально. В R есть специальная функция as.Date(), которая приводит строку к типу Date:

date1 <- as.Date("2019-04-25")
date1
## [1] "2019-04-25"
str(date1)
##  Date[1:1], format: "2019-04-25"

По умолчанию считается, что на первом месте указан год, на втором — месяц, на третьем — день. Если порядок будет иным, функция сломается:

as.Date("27-05-2019")
## [1] "0027-05-20"

Ошибки нет, но результат странный. Чтобы этого избежать, формат можно задать самостоятельно: написать текстовый шаблон, который бы описывал нужный формат даты. Сообщим R, что на первом месте год, на втором — месяц, на третьем — день, плюс, напомним, что разделителем является дефис:

date2 <- as.Date("27-05-2019", format = "%d-%m-%Y")
date2
## [1] "2019-05-27"

Узнать, какие ещё существуют обозначения и чему они соответствуют, можно здесь.

Задание: преобразовать в тип Date следующие даты:

Решения:

as.Date("05-13-19", format = "%m-%d-%y")
## [1] "2019-05-13"
as.Date("апр 25 2019", format = "%B %d %Y")
## [1] "2019-04-25"
as.Date("май-25-2019", format = "%b-%d-%Y")
## [1] "2019-05-25"
as.Date("четверг фев 21 2019", format = "%A %b %d %Y")
## [1] "2019-02-21"

Также с датами можно выполнять вычисления. Посчитаем разницу между date2 и date1 и наоборот:

date2 - date1
## Time difference of 32 days
date1 - date2
## Time difference of -32 days

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

difftime(date1, date2, units = "weeks")  # в неделях
## Time difference of -4.571429 weeks
difftime(date1, date2, units = "secs")  # в секундах
## Time difference of -2764800 secs

Полный список опций такой:

units <- c("auto", "secs", "mins", "hours", "days", "weeks")

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

three.dates <- as.Date(c("2010-07-22", "2011-04-20", "2012-10-06"))
diff(three.dates)  # для трех, в днях
## Time differences in days
## [1] 272 535

Последовательности из дат также легко создавать автоматически — достаточно зафиксировать стартовую точку, сообщить длину нужной последовательности и единицы измерения (секунд/минут/дней/недель и так далее):

days10 <- seq(date1, length = 10, by = "day")
days10  # 10 элементов, шаг 1 день (итого 10 дней)
##  [1] "2019-04-25" "2019-04-26" "2019-04-27" "2019-04-28" "2019-04-29"
##  [6] "2019-04-30" "2019-05-01" "2019-05-02" "2019-05-03" "2019-05-04"
weeks5 <- seq(date1, length = 5, by = "week")
weeks5  # 5 элементов, шаг 1 неделя
## [1] "2019-04-25" "2019-05-02" "2019-05-09" "2019-05-16" "2019-05-23"
days3 <- seq(date1, length = 5, by = "3 day")
days3  # 5 элементов, шаг 3 дня
## [1] "2019-04-25" "2019-04-28" "2019-05-01" "2019-05-04" "2019-05-07"

Если нужно двитаться в обратную сторону, можно поставить минус перед единицей измерения:

seq(date1, length = 5, by = "-3 day")
## [1] "2019-04-25" "2019-04-22" "2019-04-19" "2019-04-16" "2019-04-13"
seq(date1, length = 5, by = "-1 week")
## [1] "2019-04-25" "2019-04-18" "2019-04-11" "2019-04-04" "2019-03-28"

На этом пока всё.