Общие представления

Анализ данных, содержащих даты и время, может сопровождаться приличной головной болью. Причин этому может быть несколько:
  • разные годы начинаются в разные дни недели;
  • високосные годы имеют дополнительный день в феврале;
  • американцы и европейцы по разному представляют даты (например, 8/9/2011 будет 9-м августа 2011 г. для первых и 8-м сентября 2011 г. для вторых);
  • в некоторые годы добавляется т.н. "секунда координации";
  • страны различаются по временным поясам и в ряде случаев применяют переход на "зимнее" и "летнее" время.

К счастью, система дат и времени в R такова, что многие из указанных проблем относительно легко преодолеваются. С форматом представления дат и времени в R можно ознакомиться, выполнив команду Sys.time()

[1] "2011-09-06 00:38:04 EEST"

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

Отдельные элементы из этого результата можно извлечь при помощи функции substr() (от substring - часть строки), указав позиции первого и последнего элементов извлекаемой строки:

substr(as.character(Sys.time()), 1, 10)
[1] "2011-09-06"

или

substr(as.character(Sys.time()), 12, 19)
[1] "00:38:04"

Функция date() позволяет выяснить текущую дату:

[1] "Tue Sep 06 01:02:24 2011"

Если выполнить команду

unclass(Sys.time())
[1] 1315258719

то получим время, выраженное в секундах, прошедших с 1 января 1970 г. Это т.н. Unix-время (по названию операционной системы). Второе название этого формата - POSIX. В R имеется два POSIX-класса. Класс POSIXct служит для педставления времени в виде секунд, истекших с 1 января 1970 г. Такой "машинный" формат  удобен для включения в таблицы данных. Для человека все же более удобным является представление времени при помощи класса POSIXlt. Объекты этого класса представляют собой списки, включающие такие элементы, как секунды, минуты, часы, дни, месяцы, и годы.

Мы можем конвертировать системное время в объект POSIXlt класса следующим образом:

date <- as.POSIXlt(Sys.time())

Из списка date далее легко можно извлечь такие содержащиеся в нем элементы, как sec (секунды), min (минуты), hour (часы), mday (день месяца), mon (месяц), year (год), wday (день недели, начиная с воскресенья = 0), yday (день года, начиная с 1 января = 0), и isdst ("is daylight savings time in operation?" - логическая переменная,  обозначающая, используется ли режим перехода на "зимнее" и "летнее" время; 1 если TRUE и 0 если FALSE), например:

date$wday
[1] 2

date$yday
[1] 248

Используйте функцию unclass() в сочетании с unlist() для просмотра всего содержимого списка date:

unlist(unclass(date))
sec         min       hour       mday      mon         
29.97798    26.00000  12.00000   6.00000   8.00000

year        wday      yday       isdst
111.00000   2.00000   248.00000  1.00000


Вычисления с датами и временем

В R можно выполнять следующие типы операций с датами и временем:
  • число + время;
  • время - число;
  • время1 - время2
  • время1 "логический оператор" время2 (в качестве логического оператора могут использоваться ==, !=, <=, <, > или >=).
Важной особенностью является то, что перед выполнением любых вычислений с датами или временем необходимо конвертировать их в объекты класса POSIXlt. Например, количество дней между 15 сентября 2011 г. и 15 сентября 2000 года можно найти следующим образом:

t1 <- as.POSIXlt("2011-09-15")
t2 <- as.POSIXlt("2000-09-15")
t1 - t2
Time difference of 4017 days

Разницу во времени, выраженную в часах, можно рассчитать так:


t3<-as.POSIXlt("2010-09-22 08:30:30")
t4<-as.POSIXlt("2010-09-22 22:25:30")
t4-t3
Time difference of 13.91667 hours

Еще проще разницу между двумя датами можно найти при помощи готовой функции difftime() (от difference - разница, и time - время):

difftime("2011-09-22", "2010-06-22")
Time difference of 457 days

Чтобы извлечь непосредственно количество дней из результата выполнения предыдущей команды используйте функцию as.numeric():

as.numeric(difftime("2011-09-22", "2010-06-22"))
[1] 457

Обратите внимание: в R отсуствует возможность для сложения двух дат.

Функция strptime()

Функция
strptime() (от strip - раздевать, оголять, и time - время) позволяет извлекать даты и время из текстовых выражений класса POSIXlt или POSIXct (см. выше). При этом важно верно указать формат (при помощи аргумента format), в котором приведены временные величины. Приняты следующие условные обозначения для формата дат и времени (приведены наиболее часто используемые; детали доступны по команде ?strptime):


%a сокращенное название для недели (англ. яз.)
%A полное название для недели (англ. яз.)
%b сокращенное название месяца (англ. яз.)
%B полное название месяца (англ. яз.)
%d день месяца (01–31)
%H часы от 00 до 23
%I часы от 01 до 12
%j порядковый номер дня года (001–366)
%m порядковый номер месяца (01–12)
%M минуты (00–59)
%S секунды (00–61, с возможностью добавить "високосную секунду")
%U неделя года (00–53), используя первое вокресенье как первый день первой недели
%w порядковый номер дня недели (0–6, воскресенье - 0)
%W неделя года (00–53), используя первый понедельник как первый день первой недели
%Y год с указанием века
%y год без указания века

Рассмотрим пример. Предположим, у нас имеется текстовый вектор, в котором хрянятся даты в формате программы Microsoft Excel:

dates.excel <- c("25/02/2008", "24/04/2009", 
"14/06/2009", "25/07/2010", "04/03/2011")

Требуется преобразовать эти текстовые выражения в даты формата R. Формат имеющихся Excel-дат таков, что сначала идет день месяца, затем порядковый номер самого месяца и, наконец, год с указанием века. Используя приведенные выше обозначения, принятые в R, этот формат можно представить в виде %d/%m/%Y. Тогда команда для преобразования Excel-дат в R-даты будет выглядеть следующим образом:

strptime(dates.excel, format = "%d/%m/%Y")
[1] "2008-02-25" "2009-04-24" "2009-06-14"
[2] "2010-07-25" "2011-03-04"

Вот еще один пример, в котором год приведен без указания века, а месяцы приведены в виде их сокращенных названий:

example2 <- c("1jan79", "2jan99", "31jan04", "30aug05")
strptime(other.dates, "%d%b%y")
[1] "1979-01-01" "1999-01-02" "2004-01-31" "2005-08-30"

--
Основным источником для написания данной статьи послужил раздел "Dates and Times in R" из книги Майкла Кроули (Michael Crawley) "The R Book".

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

Unknown написал(а)…
есть дата "2018-3-11 08:35"
Как вернуть время?
Костя написал(а)…
t <- strptime("2018-3-11 08:35", format = "%Y-%m-%d %H:%M")
# Как фрагмент текста
substr(as.character(t), 12, 16)
# Или как элементы списка
t$hour
t$min
Новые Старые