9

I have three time (POSIXct) objects t1, t2, t3 which specify the time duration to complete a task.

I found t1, t2, t3 by doing the following:

t1 <- as.POSIXct("2016-10-30 13:53:34") - as.POSIXct("2016-10-30 13:35:34")
t2 <- as.POSIXct("2016-10-30 14:53:34") - as.POSIXct("2016-10-30 14:35:34")
t3 <- as.POSIXct("2016-10-30 15:50:34") - as.POSIXct("2016-10-30 15:40:34")

I want to find the ratios t1/t3 and t2/t3. However, I get the following error:

t1/t3
# Error in `/.difftime`(t1, t3) : 
#   second argument of / cannot be a "difftime" object

I understood that two difftime objects cannot be divided. Is there any way that I could find the result of dividing two difftime objects?

MichaelChirico
  • 33,841
  • 14
  • 113
  • 198
Katherine
  • 107
  • 1
  • 9

3 Answers3

10

To divide by a difftime you must convert it to numeric. If, as you stated in a comment, you would like the answer to be expressed in seconds, you can specify the 'secs' units. For example:

t1/as.double(t3, units='secs')

As @JonathanLisic notes, as.double does not generally take a units parameter, and this won't work for generic time classes. It is the S3 method for difftime which takes the parameter.

Matthew Lundberg
  • 42,009
  • 6
  • 90
  • 112
  • 1
    It's important to note that this conversion is not necessarily relevant to other DateTimeClasses. e.g. `a1 <- strptime("2016-10-30 13:53:34", format="%Y-%m-%d %H:%M:%S"); as.double(a1,units="days")` still returns seconds from epoch. – Jonathan Lisic Oct 24 '16 at 21:27
  • 1
    @JonathanLisic True, thank you for the addition. The reason it works here is that `as.double` is an `S3` method for `difftime`. – Matthew Lundberg Oct 24 '16 at 21:32
  • 1
    I'm quite surprised that `as.double` is S3 generic, but `as.numeric` is _not_! First case I've seen in R of actually requiring `as.double`... – MichaelChirico Oct 20 '17 at 09:02
4

As of today's date (9/2018), you can use as.numeric() to turn your difftime values into numeric values. ie, if you were to take

as.numeric(t3)

R will return 10 as desired.

obewanjacobi
  • 458
  • 2
  • 12
3

@MatthewLundberg's answer is more correct, but I'll suggest an alternative just to help illustrate the underlying structures of time-based objects in R are always just numbers:

unclass(t1)/unclass(t3)
# [1] 1.8
# attr(,"units")
# [1] "mins"

Note that, in terms of units, the approach of t1/as.double(t3, units = 'secs') doesn't make much sense, since the units of the output are min/sec, whereas this answer is unit-free.

Note further that this approach is a bit dangerous, since by default, -.POSIXt (which is ultimately called when you define t1, t2, and t3) automatically chooses the units of the output (at core, -.POSIXt here will call difftime with the default units = "auto"). In this case, we are (maybe) lucky that all 3 are given units, but consider t4:

t4 = as.POSIXct('2017-10-21 12:00:35') - as.POSIXct('2017-10-21 12:00:00')
t4
# Time difference of 35 secs

Again, if we use t4 in a ratio, we'll probably get the wrong units.

We can avoid this by explicitly calling difftime and declaring the units upfront:

t1 = difftime("2016-10-30 13:53:34", "2016-10-30 13:35:34", units = 'mins')
t2 = difftime("2016-10-30 14:53:34", "2016-10-30 14:35:34", units = 'mins')
t3 = difftime("2016-10-30 15:50:34", "2016-10-30 15:40:34", units = 'mins')
t4 = difftime('2017-10-21 12:00:35', '2017-10-21 12:00:00', units = 'mins')
t4
# Time difference of 0.5833333 mins
MichaelChirico
  • 33,841
  • 14
  • 113
  • 198
  • Any idea why we cannot take a ratio of ``difftime`` objects (and get unit-free number)? Is it an oversight in the implementation of ``\`` or there is some fundamental difficulty? – PatrickT Sep 24 '18 at 15:37
  • 1
    @PatrickT it's a good question but I don't know the answer. seems like an oversight to me – MichaelChirico Sep 24 '18 at 16:07