Skip to content

Bug 17350 - Formatting fractions of a second for POSIXt #83

Closed
@hturner

Description

@hturner

The original report for Bug 17350 queried whether fractions of a second for a POSIXct were displayed correctly when printed. The discussion started to pin down some issues which I explore further here.

We'll use Sebastian Meyer's (@bastistician's) example code:

x <- as.POSIXct("2009-08-03 12:01:59") + 0:3/10

As Sebastian notes, print.POSIXct(x) calls format.POSIXct(x) which is a wrapper around format.POSIXlt(). If we check the seconds after converting x to POSIXct, we see there are lots of digits due to the floating point arithmetic (i.e. adding 0, 0.1, 0.2, 0.3 does not give exactly 59.0, 59.1, 59.2, 59.3).

secs <- as.POSIXlt(x)$sec
print(secs, digits = 15)
# [1] 59.0000000000000 59.0999999046326 59.2000000476837 59.2999999523163

Main Bug: inconsistent formatting of digits for fractional seconds

As documented in ?format.POSIXlt the default format is "%Y-%m-%d %H:%M:%S" when the global option digits.secs is NULL (or 0). In other words, no fractional seconds are displayed.

options(digits.secs = 0)
format(x)
# [1] "2009-08-03 12:01:59" "2009-08-03 12:01:59" "2009-08-03 12:01:59" "2009-08-03 12:01:59"

If we use the "%OS" format, 0:6 digits are used for the fractional seconds, with the number taken from the global option digits.secs, e.g.

options(digits.secs = 3)
format(x, "%Y-%m-%d %H:%M:%OS")
# [1] "2009-08-03 12:01:59.000" "2009-08-03 12:01:59.099" "2009-08-03 12:01:59.200"
# [4] "2009-08-03 12:01:59.299"

If we have set the global option digit.sec > 0 and use the default format, however, we only get 1 decimal place:

options(digits.secs = 3)
format(x)
# [1] "2009-08-03 12:01:59.0" "2009-08-03 12:01:59.0" "2009-08-03 12:01:59.2" "2009-08-03 12:01:59.2"

The same happens if the global option is at the default and we set digits = 3

options(digits.secs = 0)
format(x, digits = 3)
# [1] "2009-08-03 12:01:59.0" "2009-08-03 12:01:59.0" "2009-08-03 12:01:59.2" "2009-08-03 12:01:59.2"

This is due to a block of code in format.POSIXlt() (L385-400) that is only run when the default format is used (format == "") and adjusts the number of digits to avoid trailing zeroes.

The task here is to discuss how format.POSIXlt(x) could be modified to be more consistent and to prepare a corresponding patch.

Side issue: digits ignored when "%OS" format used

A side issue here is that when specifying "%OS" format directly, only the global digit.secs option has an effect:

options(digits.secs = 3)
format(x, "%Y-%m-%d %H:%M:%OS", digits = 2)
# [1] "2009-08-03 12:01:59.000" "2009-08-03 12:01:59.099" "2009-08-03 12:01:59.200"
# [4] "2009-08-03 12:01:59.299"
options(digits.secs = 0)
format(x, "%Y-%m-%d %H:%M:%OS", digits = 2)
# [1] "2009-08-03 12:01:59" "2009-08-03 12:01:59" "2009-08-03 12:01:59"
# [4] "2009-08-03 12:01:59"

This is inconsistent with how options in R usually behave, e.g.

options(digits = 2)
print(secs)
# [1] 59 59 59 59
print(secs, digits = 15)
# 59.0000000000000 59.0999999046326 59.2000000476837 59.2999999523163

and is due to the C code looking up the option to get the digits datetime.c#L986, rather than taking an argument.

So, an extension to this task could be adjusting the R or C code to respect the digits argument.

Other

Potentially the help file for format.POSIXlt() needs to be updated to document the behaviour of the function, e.g. the help for the format and digits arguments could be reviewed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    I/OIssues related to the input/output systemLatinR 2024RIssue should require knowledge of R onlyneeds patchImplement the agreed fix and prepare a patch for review

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions