Dear list,
When using as.POSIXlt with times measured down to microseconds the default format.POSIXlt seems to cause some possibly undesirable behaviour:

According to the code in format.POSIXlt the maximum accuracy of printing fractional seconds is 1 microsecond, but if I do;

options( digits.secs = 6 )
as.POSIXlt( 1.000002 , tz="", origin="1970-01-01")
as.POSIXlt( 1.999998 , tz="", origin="1970-01-01")
as.POSIXlt( 1.999999 , tz="", origin="1970-01-01")

I return respectively:
[1] "1970-01-01 01:00:01.000002 BST"
[1] "1970-01-01 01:00:01.999998 BST"
[1] "1970-01-01 01:00:01 BST"

If options( digits.secs = 6 ) should I not expect to be able to print 1.999999 seconds? This seems to be caused by the following code fragment in format.POSIXlt:

np <- getOption("digits.secs")
        if (is.null(np))
            np <- 0L
        else np <- min(6L, np)
        if (np >= 1L)
            for (i in seq_len(np) - 1L) if (all(abs(secs - round(secs,
                i)) < 1e-06)) {
                np <- i
                break
            }

Specifically
            for (i in seq_len(np) - 1L) if (all(abs(secs - round(secs,
                i)) < 1e-06))
Which in the case of 1.999999 seconds will give:

options( scipen = 10 )
np <- 6
sapply( seq_len(np) - 1L , function(x) abs(1.999999 - round(1.999999, x)) )

         [,1]     [,2]     [,3]     [,4]     [,5]     [,6]
[1,] 0.000001 0.000001 0.000001 0.000001 0.000001 0.000001

The logical test all( ... < 1e-06)  should evaluate to FALSE but due to floating point precision it evaluates TRUE:

sprintf( "%.20f" , abs(1. 999999  - round(1. 999999,5)))
[1] "0.00000099999999991773"

If instead of:

            for (i in seq_len(np) - 1L) if (all(abs(secs - round(secs,
                i)) < 1e-06))

in format.POSIXlt we had a comparison value that was half the minimum increment:

            for (i in seq_len(np) - 1L) if (all(abs(secs - round(secs,
                i)) < 5e-07))

This behaviour disappears:

mod.format.POSIXlt( as.POSIXlt( 1.999999 , tz="", origin="1970-01-01") )
[1] "1970-01-01 01:00:01.999999"

But I am unsure if the original behaviour is what I should expect given the documentation (I have read it and I can't see a reason to expect 1.999999 to round down to 1). And also if changing the formatting function would have other undesirable consequences?

My sessionInfo():
R version 3.0.0 (2013-04-03)
Platform: x86_64-w64-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=English_United Kingdom.1252
[2] LC_CTYPE=English_United Kingdom.1252
[3] LC_MONETARY=English_United Kingdom.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United Kingdom.1252

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base



Thank you,


Simon


------------------------------------
Simon O'Hanlon
Postgraduate Researcher

Helminth Ecology Research Group
Department of Infectious Disease Epidemiology
Imperial College London
St. Mary's Hospital, Norfolk Place,
London, W2 1PG, UK

Office: +44 (0) 20 759 43229
------------------------------------


	[[alternative HTML version deleted]]

