Как добавить/вычесть время из POSIXlt, сохраняя свой класс в R?
Я манипулирую некоторыми объектами DateTime POSIXlt
. Например, я хотел бы добавить час:
my.lt = as.POSIXlt("2010-01-09 22:00:00")
new.lt = my.lt + 3600
new.lt
# [1] "2010-01-09 23:00:00 EST"
class(new.lt)
# [1] "POSIXct" "POSIXt"
Я хочу, чтобы new.lt
был объектом POSIXlt
. Я знаю, что я мог бы использовать as.POSIXlt
, чтобы преобразовать его обратно в POSIXlt
, но есть ли более элегантный и эффективный способ достичь этого?
Ответы
Ответ 1
Короткий ответ: Нет
Длинный ответ:
Объекты POSIXct
и POSIXlt
- это два конкретных типа более общего класса POSIXt
(не в смысле объектно-ориентированного наследования, а в смысле реализации, ориентированном на квази-объект). Код свободно переключается между ними. Когда вы добавляете объект POSIXlt
, фактическая используемая функция +.POSIXt
, а не одна для POSIXlt
. Внутри этой функции аргумент преобразуется в POSIXct
, а затем обрабатывается (добавляется).
Кроме того, POSIXct
- это количество секунд с определенной даты и времени. POSIXlt
- список деталей даты (секунды, минуты, часы, день месяца, месяц, год, день недели, день года, информация DST), поэтому добавление к этому напрямую не имеет смысла. Преобразование его в несколько секунд (POSIXct
) и добавление к нему имеет смысл.
Ответ 2
POSIXct
-классифицированные объекты внутренне представляют собой числовое значение, которое допускает числовые вычисления. POSIXlt
-объекты являются внутренними списками. К сожалению, для ваших желаний Ops.POSIXt
(это то, что вызывается при использовании "+" ), коэрцирует POSIXct с помощью этого кода:
if (inherits(e1, "POSIXlt") || is.character(e1))
e1 <- as.POSIXct(e1)
К счастью, если вы просто хотите и час, есть удобная альтернатива добавлению 3600. Вместо этого используйте структуру списка и добавьте элемент 1 в элемент часа:
> my.lt$hour <- my.lt$hour +1
> my.lt
[1] "2010-01-09 23:00:00"
Этот подход очень удобен, когда вы хотите избежать острых вопросов о изменениях DST, по крайней мере, если вы хотите добавить дни, чтобы дать вам одно и то же время суток.
Изменить (добавление кода @sunt, демонстрирующего, что Ops.POSIXlt
осторожно относится к переполнению времени.))
my.lt = as.POSIXlt("2010-01-09 23:05:00")
my.lt$hour=my.lt$hour+1
my.lt
# [1] "2010-01-10 00:05:00"
Ответ 3
Возможно, он не будет значительно более элегантным, но
seq.POSIXt( from=Sys.time(), by="1 hour", length.out=2 )[2]
ИМХО более наглядно, чем
Sys.time()+3600; # 60 minutes * 60 seconds
потому что сам код документа указывает, что вы собираетесь на "POSIX" "seq" uquance "на 1 час", но это вопрос вкуса. Хорошо работает на POSIXlt, но обратите внимание, что он возвращает POSIXct в любом случае. Также работает для "дней". См. Справку (seq.POSIXt) для получения подробной информации о том, как она обрабатывает месяцы, экономию летнего времени и т.д.
Ответ 4
?POSIXlt
сообщает вам, что:
Любое преобразование, которое необходимо пройти между двумя классами времени, требует часовой пояс: преобразование из "POSIXlt" в "POSIXct" будет проверять время в выбранном часовом поясе.
Итак, я думаю, что 3600 не является объектом POSIXlt
, есть автоматическое преобразование.
Я бы придерживался простого:
new.lt = as.POSIXlt(my.lt + 3600)
class(new.lt)
[1] "POSIXlt" "POSIXt"
Это не так много хлопот, чтобы добавить as.POSIXlt
перед вашей операцией времени.