-1

Let's say there is the vector of date/times in R:

l<-c("2011-01-01 00:00:00", "2011-01-01 01:00:00", "2011-01-01 02:00:00")

I would like to add the certain amount of time(f.e. 1 hour) to each element of this vector. First of all, I converted the elements to POSIXlt:

l1<-as.POSIXlt(l)

then I tried to use sapply and add hours as described in How to add/subtract time from a POSIXlt time while keeping its class in R?:

f<-function(dt, hour){
  dt$hour<-dt$hour + hour
  return(dt)
}
sapply(l1, function(x) f(x,1))

However, executing this code gives the error: Error in dt$hour : $ operator is invalid for atomic vectors

Debugging tells that class(dt) is numeric and not POSIXt

How can I solve this problem?

Community
  • 1
  • 1
sovo2014
  • 487
  • 7
  • 17

5 Answers5

1

As it says in the answer to the question you linked to, POSIXlt is already a list. So you're looping over the elements of the POSIXlt list, which themselves do not have hour elements.

R> unclass(l1)
$sec
[1] 0 0 0

$min
[1] 0 0 0

$hour
[1] 0 1 2

$mday
[1] 1 1 1

$mon
[1] 0 0 0

$year
[1] 111 111 111

$wday
[1] 6 6 6

$yday
[1] 0 0 0

$isdst
[1] 0 0 0

attr(,"tzone")
[1] "UTC"

So you're applying f to sec, then min, ..., isdst.

Again, as it says in the answer to the question you linked to, you should not change the internal element values of a POSIXlt object and expect the time to make any sense. Convert to POSIXct and add hour * 3600 to it.

Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
0
f<-function(dt = POSIXlt(), hour){
    dt$hour<-dt$hour + hour
    return(dt)
}
Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
Datium
  • 93
  • 1
  • 7
0

If you are just looking for an easy way to add hours, check out the package lubridate:

library(lubridate)
##
Timestamps <- c("2011-01-01 00:00:00", 
                "2011-01-01 01:00:00", "2011-01-01 02:00:00")
dT.lt <- as.POSIXlt(
  Timestamps,
  format="%Y-%m-%d %H:%M:%S",
  tz="America/New_York")
##
> dT.lt + hours(1)
[1] "2011-01-01 01:00:00 EST" "2011-01-01 02:00:00 EST" "2011-01-01 03:00:00 EST"

The package has similar utility functions for adding / subtracting seconds, minutes, months, etc..., and the functions are vectorized so you don't have to explicitly use an *apply function (or even worse, a for loop).

nrussell
  • 18,382
  • 4
  • 47
  • 60
  • Or, as @Joshua Ulrich suggested, convert to the `POSIXct` class (this is what I typically use) and just use the appropriate conversion factor for seconds -> hours. – nrussell Sep 06 '14 at 15:45
0

With lubridate, it's really easy to change the hour with the hour<- assignment function.

> x <- as.POSIXlt(c("2011-01-01 00:00:00", "2011-01-01 01:00:00", 
                    "2011-01-01 02:00:00"))
> library(lubridate)
> hour(x) <- hour(x) + 1
> x
# [1] "2011-01-01 01:00:00 PST" "2011-01-01 02:00:00 PST"
# [3] "2011-01-01 03:00:00 PST"
Rich Scriven
  • 97,041
  • 11
  • 181
  • 245
0

To add one hour, you have to add 3600 (60 seconds times 60 minutes).

> as.POSIXlt(l) + 3600
[1] "2011-01-01 01:00:00 CET" "2011-01-01 02:00:00 CET" "2011-01-01 03:00:00 CET"

There's no need for sapply in this case.

Sven Hohenstein
  • 80,497
  • 17
  • 145
  • 168