0

I would like to calculate the time difference considering ONLY the days and months. For example:

> as.Date("2018-12-15")-as.Date("2018-12-16")
Time difference of -1 days

> as.Date("2008-12-15")-as.Date("2018-12-16")
Time difference of -3653 days

I want both of them to return -1.

Edit: Leap years should not be considered as we just want an approximation and the return value do not need to be exact.

Jesper.Lindberg
  • 313
  • 1
  • 5
  • 14

4 Answers4

2

As suggested by @Omry Atia we can set the years component to same year and then calculate the difference.

library(lubridate)

get_difference_without_years <- function(x, y) {
    x <- ymd(x)
    year(x) <- 2018
    y <- ymd(y)
    year(y) <- 2018
    x - y
}


get_difference_without_years("2018-12-15", "2018-12-16")
#Time difference of -1 days

get_difference_without_years("2008-12-15", "2018-12-16")
#Time difference of -1 days

To keep it in base R

get_difference_without_years <- function(x, y) {
  x <- as.Date(paste0("2018-", format(as.Date(x), "%m-%d")))
  y <- as.Date(paste0("2018-", format(as.Date(y), "%m-%d")))
  x - y
}

get_difference_without_years("2008-12-15", "2018-12-16")
#Time difference of -1 days
get_difference_without_years("2018-12-15", "2018-12-16")
#Time difference of -1 days
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
1

The question is not well defined for the case that the dates straddle the end of Feb and one year is a leap year and one is not but ignoring this we can replace the year in each date with a leap year if either is a leap year (year 2000) and a non-leap year (year 1999) otherwise and then subtract:

library(lubridate)

d1 <- "2008-12-15"
d2 <- "2018-12-16"

yr <- 1999 + (leap_year(as.Date(d1)) || leap_year(as.Date(d2)))
as.Date(sub("....", yr, d1)) - as.Date(sub("....", yr, d2))
## Time difference of -1 days

ADDED

In a comment the poster indicated that we can ignore the problems introduced by leap years. In that case we can just pick a leap year as the date to substitute in so that it always returns an answer. We do that below. We no longer need lubridate to check whether the dates are leap years or not.

as.Date(sub("....", 2000, d1)) - as.Date(sub("....", 2000, d2))
## Time difference of -1 days

(Alternately we could pick a year that is not a leap year and since most years are not leap years that would more likely not be one day off for straddled dates; however, it would be at the cost of failing if one of the dates is Feb 29th.)

G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
1

If we're allowed to be a bit more approximate, ignoring leap-years, we can simplify things a bit by using %j (day of year) in format().

yd_diff <- function(x, y=NULL) {
    x <- as.integer(format(x, "%j"))
    if (is.null(y)) {
        diff(x)
    } else {
        x - as.integer(format(y, "%j"))
    }
}

d1 <- as.Date("2008-12-15")
d2 <- as.Date("2018-12-16")
yd_diff(d1, d2)
# 0

set.seed(1)
rd <- as.Date(sample(1:10000, 5), origin="1970-01-01")
yd_diff(rd)
# -30  180   65 -123

And even simpler, we can convert the date to integer and take the modulo days in a year. Graciously, R lets you use modulo with non-integers.

(as.integer(d1) %% 365.24) - (as.integer(d2) %% 365.24)
# -0.6

diff(as.integer(rd) %% 365.24)
# -30.72  180.80   64.84 -123.44
AkselA
  • 8,153
  • 2
  • 21
  • 34
0

Another solution might be to extract only the day-of-year from each date, and then do the maths op, especially if leap-years are important.

For example, the DoY for the following:

DayOfYear(2020, 12, 15) = 350   # leap year
DayOfYear(2018, 12, 15) = 349
DayOfYear(2016, 12, 15) = 350   # leap year
DayOfYear(2011, 12, 16) = 350

You can find lots of suggestions on how to get the DoY from extract day number of year from dates and How do you convert POSIX date to day of year in R?.

phase21
  • 11
  • 1