Create a regular sequence of date-times (POSIXct) using seq()
Asked Answered
P

6

22

My goal is to create a vector of POSIXct time stamps given a start, an end and a delta (15min, 1hour, 1day). I hoped I could use seq for this, but I have a problem converting between the numeric and POSIXct representation:

now <- Sys.time()
now
# [1] "2012-01-19 10:30:39 CET"
as.POSIXct(as.double(now), origin="1970-01-01", tz="CET")
# [1] "2012-01-19 09:30:39 CET"
as.POSIXct(as.double(now), origin=as.POSIXct("1970-01-01", tz="CET"), tz="CET")
# [1] "2012-01-19 09:30:39 CET"

One hour gets lost during this conversion. What am I doing wrong?

Pusey answered 19/1, 2012 at 10:3 Comment(0)
H
28

There is a seq() method for objects of class "POSIXt" which is the super class of the "POSIXlt" and "POSIXct" classes. As such you don't need to do any conversion.

> now <- Sys.time()
> tseq <- seq(from = now, length.out = 100, by = "mins")
> length(tseq)
[1] 100
> head(tseq)
[1] "2012-01-19 10:52:38 GMT" "2012-01-19 10:53:38 GMT"
[3] "2012-01-19 10:54:38 GMT" "2012-01-19 10:55:38 GMT"
[5] "2012-01-19 10:56:38 GMT" "2012-01-19 10:57:38 GMT"
Hausfrau answered 19/1, 2012 at 10:53 Comment(2)
And this is pointed out in the documentation of seq(), where I should have looked in the first place. Thank you!Pusey
see @RichieCotton's answer below if you need it by a regular interval like "10 min"Ginkgo
A
10

You have to be aware that when converting from POSIXct to numeric, R takes the timezone into account but always starts counting from a GMT origin :

> xgmt <- as.POSIXct('2011-01-01 14:00:00',tz='GMT')
> xest <- as.POSIXct('2011-01-01 14:00:00',tz='EST')
> (as.numeric(xgmt) - as.numeric(xest)) / 3600
[1] -5

As you see, the time in EST is conceived to be five hours earlier than the time in GMT, which is the time difference between both timezones. It's that value that is saved internally.

The as.POSIXCT() function just adds an attribute containing the timezone. It doesn't alter the value, so you get the time presented in GMT time, but with an attribute telling it is EST. This also means that once you go from POSIXct to numeric, you should treat your data as if it's GMT time. (It's a whole lot more complex than that, but it's the general idea). So you have to calculate the offset as follows:

> nest <- as.numeric(xest)
> origin <- as.POSIXct('1970-01-01 00:00:00',tz='EST')
> offset <- as.numeric(origin)
> as.POSIXct(nest-offset,origin=origin)
[1] "2011-01-01 14:00:00 EST"

This works whatever the timezone is in your locale (in my case, that's actually CET). Also note that behaviour of timezone data can differ between systems.

Adel answered 19/1, 2012 at 12:11 Comment(0)
S
9

These time zone issues are always fiddly, but I think the problem is that your origin is being calculated in the wrong time zone (since the string only specifies the date).

Try using origin <- now - as.numeric(now).

Alternatively, use lubridate::origin, which is the string "1970-01-01 UTC".


A full solution, again using lubridate.

start <- now()
seq(start, start + days(3), by = "15 min")
Silverpoint answered 19/1, 2012 at 10:45 Comment(4)
You have to be careful though, as this only works when converting to your own current locale. A more general solution is given in my answer. The idea is the same, but is independent of your own locale.Adel
@Richie Using the lubridate example, I am getting invalid string for "by"Earnestineearnings
@BrianVanover Double check your typing, and if you still have a problem then post a new question.Silverpoint
@RichieCotton bet you he wrote 'minutes' and not 'min'. I say that because that's exactly what I did.Ginkgo
R
4

I do not have an answer to your problem, but I do have an alternative way of creating vectors of POSIXct objects. If, for example, you want to create a vector of 1000 timestamps from now with a delta_t of 15 minutes:

now = Sys.time()
dt = 15 * 60 # in seconds
timestamps = now + seq(0, 1000) * dt
> head(timestamps)
[1] "2012-01-19 11:17:46 CET" "2012-01-19 11:32:46 CET"
[3] "2012-01-19 11:47:46 CET" "2012-01-19 12:02:46 CET"
[5] "2012-01-19 12:17:46 CET" "2012-01-19 12:32:46 CET"

The trick is you can add a vector of seconds to a POSIXct object.

Revelatory answered 19/1, 2012 at 10:18 Comment(0)
U
4

An alternative to using seq.POSIXt is xts::timeBasedSeq, which allows you to specify the sequence as a string:

library(xts)
now <- Sys.time()
timeBasedSeq(paste("2012-01-01/",format(now),"/H",sep=""))  # Hourly steps
timeBasedSeq(paste("2012-01-01/",format(now),"/d",sep=""))  # Daily steps
Underglaze answered 19/1, 2012 at 14:10 Comment(0)
P
1

You need to use seq(from=start,to=end, by=step). Note that in step you can either use "days" or an integer defining how many seconds elapse from item to item.

Piston answered 9/11, 2015 at 15:13 Comment(1)
You need to read the other answers before posting a new one 3 years later. This was already provided in at least two earlier answers.Araminta

© 2022 - 2024 — McMap. All rights reserved.