3

The difftime() function makes it easy to compute the difference between two dates in days or in weeks but there is no option to compute the difference in months or in years. Is there any reason for that ? Would you know any function which would perform this task ?

PAC
  • 5,178
  • 8
  • 38
  • 62
  • Can you explain 'difference in months'? – TheComeOnMan Oct 30 '13 at 15:46
  • 1
    The problem is that neither months nor years have a fixed length. – Roland Oct 30 '13 at 15:47
  • 6
    months and years aren't precise time units, that is, their lengths vary. If you want to fix a value for them, e.g., month = 30 days, year = 365 days, you can just divide your difference in days to get the units you want. Or you just want the number complete months between two dates, ` length(seq(from=date1, to=date2, by='month')) - 1` – Matthew Plourde Oct 30 '13 at 15:50
  • 1
    See also http://stackoverflow.com/questions/14454476/in-r-get-the-difference-between-dates-in-terms-of-weeks-months-quarters-years – plannapus Oct 30 '13 at 18:37

2 Answers2

15

From the comments: Months and years aren't precise time units, that is, their lengths vary (months can have 28, 29, 30, 31 days. Years can have 365 or 366). If you want to fix a value for one of these units (e.g., month = 30 days, year = 365 days), you can just divide your difftimes in days by the fixed value to get the difference in the units you want. Or if you just want something like the number of complete months between two dates, you could do this

date1 = as.Date('2012-1-2')
date2 = as.Date('2012-7-5')
length(seq(from=date1, to=date2, by='month')) - 1
# [1] 6

or for weeks:

length(seq(from=date1, to=date2, by='week')) - 1
# [1] 26
Matthew Plourde
  • 43,932
  • 7
  • 96
  • 113
4

The POSIXlt datetime-class is a list with several extraction methods including months and quarter. (The months function returns a character value so you need to extract the mon item from the list which is an integer.) If you want to subtract the months values from successive items in a vector it would be something along the lines of:

PLvec <- as.POSIXlt(vec)
PLvec[-1]$mon - PLvec[-length(PLvec)]$mon

vec <- seq(from = as.Date('2012-1-2'),
           to = as.Date('2012-7-5'), 
           by="60 days")
 PLvec <- as.POSIXlt(vec)
 PLvec[-1]$mon - PLvec[-length(PLvec)]$mon
#[1] 2 2 1

You should educate yourself about POSIXlt classed items, because they are really lists and do not play well with data.frame storage.

dput(as.POSIXlt(Sys.time()))
structure(list(sec = 24.0051879882812, min = 5L, hour = 9L, mday = 30L, 
    mon = 9L, year = 113L, wday = 3L, yday = 302L, isdst = 1L), .Names = c("sec", 
"min", "hour", "mday", "mon", "year", "wday", "yday", "isdst"
), class = c("POSIXlt", "POSIXt"), tzone = c("", "PST", "PDT"
))
IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • If you wrap the code in a function you can keep the data.frame column as `POSIXct`. I try to avoid storing `POSIXlt` data. – Roland Oct 30 '13 at 16:16
  • I only use POSIXlt for output. I advised not using with data.frame storage. – IRTFM Oct 30 '13 at 16:17