How do I add / subtract time from POSIXlt while keeping my class in R?
I am manipulating some DateTime objects POSIXlt
. For example, I would like to add an hour:
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"
I want to new.lt
be an object POSIXlt
. I know I could use as.POSIXlt
to convert it back to POSIXlt
, but is there a more elegant and efficient way to achieve this?
source to share
Short answer: No
Long answer:
Objects
POSIXct
and POSIXlt
are two concrete types of a more general class POSIXt
(not in the sense of object-oriented inheritance, but in the sense of a quasi-object oriented implementation). The code switches freely between them. When you add an object POSIXlt
, the actual function used +.POSIXt
, not the one for POSIXlt
. Inside this function, the argument is converted to POSIXct
and then processed (appended).
Also, POSIXct
it is the number of seconds since a specific date and time. POSIXlt
- a list of date details (seconds, minutes, hours, day of month, month, year, day of the week, day of the year, DST info), so adding to this directly doesn't make sense. Converting it to a few seconds ( POSIXct
) and adding to it makes sense.
source to share
POSIXct
-classified objects are internally a numeric value that allows numeric calculations. POSIXlt
-objects are internal lists. Unfortunately for your desires Ops.POSIXt
(this is what gets called when "+" is used) coercive POSIXct with this code:
if (inherits(e1, "POSIXlt") || is.character(e1))
e1 <- as.POSIXct(e1)
Luckily, if you just want an hour, there is a convenient alternative to adding 3600. Use a list structure instead and add element 1 to the hour element:
> my.lt$hour <- my.lt$hour +1
> my.lt
[1] "2010-01-09 23:00:00"
This approach comes in very handy when you want to avoid the thorny questions about DST changes, at least if you want to add days to give you the same time of day.
Edit (adding @sunt's code demonstrating being Ops.POSIXlt
careful about 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"
source to share
It might not be significantly more elegant, but
seq.POSIXt( from=Sys.time(), by="1 hour", length.out=2 )[2]
IMHO more clearly than
Sys.time()+3600; # 60 minutes * 60 seconds
because the doc code itself indicates that you are going to "POSIX" "seq" uquance "for 1 hour", but that's a matter of taste. Works well on POSIXlt, but note that it returns POSIXct anyway. Also works for "days". See the help (seq.POSIXt) for details on how it handles months, daylight savings time, etc.
source to share
?POSIXlt
tells you that:
Any conversion that needs to go between the two time classes requires a time zone: a conversion from "POSIXlt" to "POSIXct" will check the time in the selected time zone.
So i think 3600 is not an object POSIXlt
, there is an automatic conversion.
I would stick with a simple one:
new.lt = as.POSIXlt(my.lt + 3600)
class(new.lt)
[1] "POSIXlt" "POSIXt"
It's not much of a hassle to add time as.POSIXlt
before your surgery.
source to share