Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Milliseconds puzzle when calling strptime in R

Tags:

r

strptime

options(digits.secs = 3);

> strptime("2007-03-30 15:00:00.007", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.007"
> strptime("2007-03-30 15:00:00.008", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.008"
> strptime("2007-03-30 15:00:00.009", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.008"
> strptime("2007-03-30 15:00:00.010", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.01"
> strptime("2007-03-30 15:00:00.011", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.010"
> strptime("2007-03-30 15:00:00.999", format = "%Y-%m-%d %H:%M:%OS");
[1] "2007-03-30 15:00:00.998"

I'm confused why there's one millisecond's difference from "009", then again from "011".

like image 676
sunt Avatar asked Jan 17 '12 04:01

sunt


1 Answers

This is related to R-FAQ 7.31, though it takes a different-than-usual guise.

The behavior you are seeing results from a combination of: (a) the inexact representation of (most) decimal values by binary computers; and (b) the documented behavior of strftime and strptime, which is to truncate rather than round the fractional parts of seconds, to the specified number of decimal places.

From the ?strptime help file (the key word being 'truncated'):

Specific to R is ‘%OSn’, which for output gives the seconds truncated to ‘0 <= n <= 6’ decimal places (and if ‘%OS’ is not followed by a digit, it uses the setting of ‘getOption("digits.secs")’, or if that is unset, ‘n = 3’).

An example will probably illustrate what's going on more effectively than further explanation:

strftime('2011-10-11 07:49:36.3', format="%Y-%m-%d %H:%M:%OS6")
[1] "2011-10-11 07:49:36.299999"

strptime('2012-01-16 12:00:00.3', format="%Y-%m-%d %H:%M:%OS1")
[1] "2012-01-16 12:00:00.2"

In the example above, the fractional '.3' must be best approximated by a binary number that is slightly less than '0.300000000000000000' -- something like '0.29999999999999999'. Because strptime and strftime truncate rather than round to the specified decimal place, 0.3 will be converted to 0.2, if the number of decimal places is set to 1. The same logic holds for your example times, of which half exhibit this behavior, as would (on average) be expected.

like image 155
Josh O'Brien Avatar answered Sep 28 '22 06:09

Josh O'Brien