How to add/subtract time from a POSIXlt time while keeping its class in R?

て烟熏妆下的殇ゞ 提交于 2019-11-30 06:42:30

Short answer: No

Long answer:

POSIXct and POSIXlt objects are two specific types of the more general POSIXt class (not in a strictly object oriented inheritance sense, but in a quasi-object oriented implementation sense). Code freely switches between these. When you add to a POSIXlt object, the actual function used is +.POSIXt, not one specifically for POSIXlt. Inside this function, the argument is converted into a POSIXct and then dealt with (added to).

Additionally, POSIXct is the number of seconds from a specific date and time. POSIXlt is a list of date parts (seconds, minutes, hours, day of month, month, year, day of week, day of year, DST info) so adding to that directly doesn't make any sense. Converting it to a number of seconds (POSIXct) and adding to that does make sense.

POSIXct-classed objects are internally a numeric value that allows numeric calculations. POSIXlt-objects are internally lists. Unfortunately for your desires, Ops.POSIXt (which is what is called when you use "+") coerces to POSIXct with this code:

if (inherits(e1, "POSIXlt") || is.character(e1)) 
        e1 <- as.POSIXct(e1)

Fortunately, if you just want to and an hour there is a handy alternative to adding 3600. Instead use the list structure and add 1 to the hour element:

> my.lt$hour <- my.lt$hour +1
> my.lt
[1] "2010-01-09 23:00:00"

This approach is very handy when you want to avoid thorny questions about DST changes, at least if you want adding days to give you the same time-of-day.

Edit (adding @sunt's code demonstrating that Ops.POSIXlt is careful with time "overflow".))

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"

It may not be significantly more elegant, but

seq.POSIXt( from=Sys.time(), by="1 hour", length.out=2 )[2]

IMHO is more descriptive than

Sys.time()+3600;  # 60 minutes * 60 seconds

because the code itself documents that you're going for a "POSIX" "seq"uence incremented "by 1 hour", but it's a matter of taste. Works just fine on POSIXlt, but note that it returns a POSIXct either way. Also works for "days". See help(seq.POSIXt) for details on how it handles months, daylight savings, etc.

Pierre Lapointe

?POSIXlt tells you that:

Any conversion that needs to go between the two date-time classes requires a timezone: conversion from "POSIXlt" to "POSIXct" will validate times in the selected timezone.

So I guess that 3600 not being a POSIXlt object, there is an automatic conversion.

I would stick with simple:

new.lt = as.POSIXlt(my.lt + 3600)
class(new.lt)
[1] "POSIXlt" "POSIXt"

It's not that much of a hassle to add as.POSIXlt before your time operation.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!