Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP


Math on interval objects #105

kenahoo opened this Issue · 4 comments

2 participants

Ken Williams Garrett Grolemund
Ken Williams

If I'm given an interval object, I'd like to know how many days/hours/whatevers it represents between its start & stop. The only way I can see to do it currently is to use difftime() in a pretty awkward way:

> ival
[1] 2011-01-01 03:00:46 -- 2011-10-21 18:33:44
> class(ival)
[1] "interval" "numeric"

> difftime(attr(ival, "start") + as.numeric(ival), attr(ival, "start"), 'days')
Time difference of 293.6479 days

An as.difftime.interval(x, units) method would be helpful, interested in a patch? Or is there another way I'm not thinking of?

Garrett Grolemund


Our intention was that you could do this sort of thing with division:

ival <- ymd_hms("2011-01-01 03:00:46") %--% ymd_hms("2011-10-21 18:33:44")
ival # 2011-01-01 03:00:46 UTC--2011-10-21 18:33:44 UTC
ival / ddays(1) # 293.6479
ival / dyears(1) # 0.8045148


Ken Williams

That almost works, but since it's a duration, those 2 examples are really just checking how many 86400-second periods and 31536000-second periods can fit in the given interval. I was looking for something that knows about actual date math, so that (for example) the following 2 calculations have the same answer:

> (ymd("2011-02-01") - ymd("2012-02-01")) / dyears(1)
[1] 1
> (ymd("2012-02-01") - ymd("2013-02-01")) / dyears(1)
[1] 1.00274

For another example - "lubridate knows" that 2012-02-01 plus 1 year is 2013-02-01, but it doesn't know that 2013-02-01 minus 2012-02-01 is also 1 year:

> x <- ymd("2012-02-01"); ((x + years(1)) - x) / dyears(1)
[1] 1.00274

To solve that last case, as a user, it's tempting to use years(1), but that's just rounding:

> x <- ymd("2012-02-01"); ((x + years(1)) - x) / years(1)
estimate only: convert periods to intervals for accuracy
[1] 1
> x <- ymd("2012-02-01"); ((x + years(1) + days(1)) - x) / years(1)
estimate only: convert periods to intervals for accuracy
[1] 1
Ken Williams

Oh, I should clarify - after I wrote the initial ticket, I discovered that difftime() is also not what I wanted:

Garrett Grolemund

Yes, difftimes and durations are similar in that respect. You could just convert the interval to a period

as.period(ival) # 9 months, 20 days, 15 hours, 32 minutes and 58 seconds 
as.period(ymd("2012-02-01") %--% ymd("2013-02-01")) # 1 year

You can also do integer division or modulo division

ival %/% months(1) # 9
ival %% months(1) # 2011-10-01 03:00:46 UTC--2011-10-21 18:33:44 UTC

(I apologize because I realize these are all from the new version which isn't on cran yet. I'm sending it to cran today so it should be up in a couple of days).

I don't think its possible to do any better than an estimate for periods. Even if I could calculate that ival was 9.3 months long , this would require some implicit estimation/judgement. How many seconds does it take to be 0.3 months? Where do I assume the remainder takes place at? A month at the end of the interval may be 31 days, but a month at the beginning may be 28 days. What if the interval is negative (new version)? I wouldn't be able to have both of the following work

int_start(ival) + answer = int_end(ival), and
int_end(ival) - answer = int_start(ival).

I'd rather be upfront about the estimation that occurs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.