In testing, I noted that this problem still exists for 32bit R 3.01 and that this is due to truncation of floating-point data, which is typical for 32-bit implementation of print statements, format and as.character for POSIXlt.
The underlying data was not saved in another type, which causes truncation in one case (32 bits) and not another (64 bits), but “print”, “format” and “as.character” are functions for the POSIXlt type, which used to display POSIXlt data as a displayed string.
While the documented behavior is that these functions truncate (ignore) extra digits (as @Gavin Simpson mentioned), this is not so true for 32-bit and 64-bit versions. To demonstrate; we will generate 1000 times and perform some comparison operations:
> options(digits.sec=3) > x = as.POSIXlt("13:29:56.061", format='%H:%M:%OS', tz='UTC') > for (i in 0:999) { > x[i+1] = as.POSIXlt(paste0("13:29:56.",sprintf("%03d",i)),format='%H:%M:%OS',tz='UTC') > } > sum(x[2:1000]>x[1:999]) [1] 999
In both 32-bit and 64-bit comparison operators are consistent, however under 32 bit I see:
> x[1:6] [1] "2015-10-16 13:29:56.000 UTC" "2015-10-16 13:29:56.000 UTC" [3] "2015-10-16 13:29:56.002 UTC" "2015-10-16 13:29:56.003 UTC" [5] "2015-10-16 13:29:56.003 UTC" "2015-10-16 13:29:56.005 UTC"
So this is clearly a display issue. Looking at the actual numbers in the POSIXlt data type, especially in seconds, we can see what happens:
> y = (x[1:6]$sec) > y [1] 56.000 56.001 56.002 56.003 56.004 56.005 > trunc(y*1000)/1000 [1] 56.000 56.001 56.002 56.003 56.004 56.005 > trunc((y-floor(y))*1000)/1000 [1] 0.000 0.000 0.002 0.003 0.003 0.005
I would suggest that this is a bug that needs to be fixed in the base base library, but as a temporary fix you can rewrite the functions "print", "as.character" and "format" to change the output to your desired output, eg
format.POSIXlt = function(posix) { return(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ", sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec))) } print.POSIXlt = function(posix) { print(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ", sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec))) } as.character.POSIXlt = function(posix) { return(paste0(posix$year+1900,"-",sprintf("%02d",posix$mon+1),"-",sprintf("%02d",posix$mday)," ", sprintf("%02d",posix$hour),":",sprintf("%02d",posix$min),":",sprintf("%002.003f",posix$sec))) }