[Rd] as.character.POSIXt in R devel

Suharto Anggono Suharto Anggono @uh@rto_@nggono @end|ng |rom y@hoo@com
Sun Oct 2 10:42:50 CEST 2022


With r82904, 'as.character.POSIXt' in R devel is changed. The NEWS item:
as.character(<POSIXt>) now behaves more in line with the
   methods for atomic vectors such as numbers, and is no longer
   influenced by options().

Part of the code:

       s <- trunc(x$sec)
        fs <- x$sec - s
        r1 <- sprintf("%d-%02d-%02d", 1900 + x$year, x$mon+1L, x$mday)
      if(any(n0 <- time != 0)) # add time if not 0
            r1[n0] <- paste(r1[n0],
                        sprintf("%02d:%02d:%02d%s", x$hour[n0], x$min[n0], s[n0],
                                substr(as.character(fs[n0]), 2L, 32L)))


* Wrong:
The result is wrong when as.character(fs[n0]) has scientific notation.
Example (modified from https://bugs.r-project.org/show_bug.cgi?id=9819):
op <- options(scipen = 0, OutDec = ".") # (default setting)
x <- as.POSIXlt("2007-07-27 16:11:03.000002")
as.character(x)
# "2007-07-27 16:11:03.99999999983547e-06"
as.character(x$sec - trunc(x$sec))
# "1.99999999983547e-06"
options(op)

'as.character.POSIXt' could temporarily set option 'scipen' large enough to prevent scientific notation in as.character(fs[n0]) .


* Too much precision:
In some cases with fractional seconds with seconds close to 60, the result has many decimal places while there is an accurate representation with less decimal places. It is actually OK, just unpleasant.
Example (modified from https://bugs.r-project.org/show_bug.cgi?id=14693):
op <- options(scipen = 0, OutDec = ".") # (default setting)
x <- as.POSIXlt("2011-10-01 12:34:56.3")
x$sec == 56.3 # TRUE
print(x$sec, 17)
# [1] 56.299999999999997
as.character(x)
# "2011-10-01 12:34:56.299999999999997"
format(x, "%Y-%m-%d %H:%M:%OS1") # short and accurate
# "2011-10-01 12:34:56.3"
ct <- as.POSIXct(x, tz = "UTC")
identical(ct,
as.POSIXct("2011-10-01 12:34:56.3", tz = "UTC"))
# TRUE
print(as.numeric(ct), 17)
# [1] 1317472496.3
lct <- as.POSIXlt(ct)
lct$sec == 56.3 # FALSE
print(lct$sec, 17)
# [1] 56.299999952316284
as.character(ct)
# "2011-10-01 12:34:56.299999952316284"
options(op)

The "POSIXct" case is a little different because some precision is already lost after converted to "POSIXct".

In 'as.character.POSIXt', using 'as.character' on the seconds (not separating the fractional part) might be good enough, but a leading zero must be added as necessary.


* Different from 'format':

- With fractional seconds, the result is influenced by option 'OutDec'.

- From "Printing years" in ?strptime: "For years 0 to 999 most OSes pad with zeros or spaces to 4 characters, and Linux outputs just the number."
Because (1900 + x$year) is formatted with %d in 'as.character.POSIXt', years 0 to 999 is output without padding. It is different from 'format' in OSes other than Linux.


* Behavior with "improper" "POSIXlt" object:

- "POSIXlt" object with out-of-bounds components is not normalized.
Example (modified from regr.tests-1d.R):
op <- options(scipen = 0) # (default setting)
x <- structure(
list(sec = 10000, min = 59L, hour = 18L,
mday = 6L, mon = 11L, year = 116L,
wday = 2L, yday = 340L,
isdst = 0L, zone = "CET", gmtoff = 3600L),
class = c("POSIXlt", "POSIXt"), tzone = "CET")
as.character(x)
# "2016-12-06 18:59:10000"
format(x)
# "2016-12-06 21:45:40"
options(op)

- With "POSIXlt" object where sec, min, hour, mday, mon, and year components are not all of the same length, recycling is not handled.
Example (modified from regr.tests-1d.R):
op <- options(scipen = 0) # (default setting)
x <- structure(
list(sec = c(1,  2), min = 59L, hour = 18L,
mday = 6L, mon = 11L, year = 116L,
wday = 2L, yday = 340L,
isdst = 0L, zone = "CET", gmtoff = 3600L),
class = c("POSIXlt", "POSIXt"), tzone = "CET")
as.character(x)
# c("2016-12-06 18:59:01", "NA NA:NA:02")
format(x)
# c("2016-12-06 18:59:01", "2016-12-06 18:59:02")
options(op)




More information about the R-devel mailing list