AlSub
AlSub

Reputation: 1155

How to adjust a customized function to get the difference between years?

I am trying to define a customized function to get the difference in years between two dates,

Here's what I got so far:

library(lubridate)

## function to get the difference between years ##
set_dif_years <- function(end_date, start_date){
  return(lubridate :: year(end_date)- lubridate :: year(start_date))
}

## testing function ##
set_dif_years(end_date=format(as.Date('01/08/2019', format='%d/%m/%Y'), "%d/%m/%Y"),
               start_date=format(as.Date('28/08/2019', format='%d/%m/%Y'), "%d/%m/%Y"))

Console output:

# -27

For this case expected function output should be 0. However I can't figure out what is missing in the function,

Is there any way to adjust the function in order to get desired result?

Upvotes: 1

Views: 25

Answers (1)

r2evans
r2evans

Reputation: 160407

When you get illogical results, look at all intermediate objects.

format(as.Date('01/08/2019', format='%d/%m/%Y'), "%d/%m/%Y")
# [1] "01/08/2019"
lubridate::year(format(as.Date('01/08/2019', format='%d/%m/%Y'), "%d/%m/%Y"))
# [1] 1

Does that make sense? Let's look at the other one.

format(as.Date('28/08/2019', format='%d/%m/%Y'), "%d/%m/%Y")
# [1] "28/08/2019"
lubridate::year(format(as.Date('28/08/2019', format='%d/%m/%Y'), "%d/%m/%Y"))
# [1] 28

This is because you lubridate::year is using as.POSIXlt, with no candidate date formats, which thinks that the first number is the year. (Don't confuse human-eyes-obvious with machine-obvious/unambiguous.)

as.POSIXlt(format(as.Date('01/08/2019', format='%d/%m/%Y'), "%d/%m/%Y"))
# [1] "0001-08-20 LMT"

as.POSIXlt(format(as.Date('28/08/2019', format='%d/%m/%Y'), "%d/%m/%Y"))
# [1] "0028-08-20 LMT"

Fixes:

  • don't go back and forth and back again between Date and Class; if you want to do year-arithmetic, just convert to the Date class and stick with it

    set_dif_years(end_date=as.Date('01/08/2019', format='%d/%m/%Y'),
                  start_date=as.Date('28/08/2019', format='%d/%m/%Y'))
    
  • if you must use character, however, since year does not accept format= that most date/datetime functions allow, you need to make it an unambiguous string up-front:

    set_dif_years(end_date=format(as.Date('01/08/2019', format='%d/%m/%Y'), "%Y/%m/%d"),
                  start_date=format(as.Date('28/08/2019', format='%d/%m/%Y'), "%Y/%m/%d"))
    

Upvotes: 2

Related Questions