Как добавить/вычесть время из 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 перед вашей операцией времени.