rempsyc
rempsyc

Reputation: 1018

lubridate: Strip milliseconds when reading datetime objects

I have a situation where dates are written like this, with milliseconds:

2021/03/04 11:15:19.000
2021/03/04 11:15:19.999

I convert them to datetimes with lubridate and they look good and exactly the same:

> library(lubridate)
> as_datetime("2021/03/04 11:15:19.000")
[1] "2021-03-04 11:15:19 UTC"
> as_datetime("2021/03/04 11:15:19.999")
[1] "2021-03-04 11:15:19 UTC"

However, when I compare them they are not equivalent:

> as_datetime("2021/03/04 11:15:19.000") == as_datetime("2021/03/04 11:15:19.999")
[1] FALSE

But if simple dates, they are:

> as_date("2021/03/04 11:15:19.000") == as_date("2021/03/04 11:15:19.999")
[1] TRUE

Which creates problems for my workflow. It is particularly difficult to troubleshoot because there is no way to know that the milliseconds were different when simply looking at the processed dates because milliseconds don't show. Is there a way to have them read as equivalent datetimes?

My best workaround is to transform to character because they are equivalent in their character form:

> as.character(as_datetime("2021/03/04 11:15:19.000")) == 
  as.character(as_datetime("2021/03/04 11:15:19.999"))
[1] TRUE

From this we can convert to datetimes again:

> as_datetime(as.character(as_datetime("2021/03/04 11:15:19.000"))) ==
  as_datetime(as.character(as_datetime("2021/03/04 11:15:19.999")))
[1] TRUE

But this solution seems really convoluted. Surely there is a cleaner way to do this?

Upvotes: 2

Views: 831

Answers (1)

Dirk is no longer here
Dirk is no longer here

Reputation: 368191

R stores datetime objects as a double counting the fractional seconds since the epoch (i.e Jan 1, 1970). Note that we said fractional seconds. Your two observations were different when you read them, so R is quite correct in telling you that they are not equal.

But converting to Date (which is a count of days rather than seconds since the epoch) you are doing a lossy conversion. A simpler way would have been trunc(). As @akrun and @Dave2e hinted in the comments above, none of this has anything to do with lubridate -- it is simply how R does business.

> d1 <- as.POSIXct("2021/03/04 11:15:19.000")
> d2 <- as.POSIXct("2021/03/04 11:15:19.999")
> d1 == d2
[1] FALSE
> trunc(d1) == trunc(d2)
[1] TRUE
> 

Upvotes: 5

Related Questions