How to format fractional seconds in POSIXct in r
Because Timestamp
has a :
between whole seconds and fractional seconds, and there isn't a time parsing string ("conversion specification", e.g. %Y
) for fractions of seconds without the whole, you need to change the last :
to a .
so you can parse it with %OS
. sub
can take care of it, looking for
- a colon
:
- followed by 3 digits
\\d{3}
, captured(...)
- followed by the end of the line
$
,
and replacing it with
- a period
.
- followed by the captured group.
Further, if you want to see the fractional seconds that it's parsing, you'll need to set the digits.secs
option:
options(digits.secs = 3)
strptime(sub(':(\\d{3})$', '.\\1', fx$Timestamp), '%Y%m%d %H:%M:%OS')
# [1] "2007-03-13 07:01:04.762 EDT" "2007-03-13 07:01:07.608 EDT" "2007-03-13 07:01:08.700 EDT"
# [4] "2007-03-13 07:01:11.275 EDT" "2007-03-13 07:01:13.884 EDT" "2007-03-13 07:01:16.588 EDT"
Note that strptime
inserts the local timezone (EDT
for me at the moment), but you can set that to whatever you like (or whatever it should be for your data) with its tz
argument.
Date-Time Conversion in R with fractional seconds
The basic idea is to convert your character string to a valid POSIX*t
object, and then convert that to a numeric
value:
## Set a couple of printing options
options(digits = 12)
options(digits.secs = 3)
## Convert from character to POSIXlt to numeric
(a <- strptime(t, format="%H:%M:%OS", tz="GMT"))
# [1] "2013-04-09 00:00:00.00 GMT" "2013-04-09 00:00:00.34 GMT"
(b <- as.numeric(a))
# [1] 1365465600.00 1365465600.34
Note that, when converting back from numeric to POSIX*t
, there are floating point issues that can change how those objects are printed. (See here for more discussion of that issue.)
## It _looks_ like you've lost 1/100 second on the second time object
(c <- as.POSIXct(as.numeric(b), origin = "1970-01-01", tz="GMT"))
# [1] "2013-04-09 00:00:00.00 GMT" "2013-04-09 00:00:00.33 GMT"
## Here's a workaround for nicer printing.
as.POSIXct(as.numeric(b+1e-6), origin = "1970-01-01", tz="GMT")
# [1] "2013-04-09 00:00:00.00 GMT" "2013-04-09 00:00:00.34 GMT"
How to extract floating point second from POSIXct object in R?
From ?strftime
the following is noted:
Specific to R is
%OSn
, which for output gives the seconds
truncated to0 <= 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 = 0
).
Hence we can recover up to 6 decimal places, although there seems to be some change in this information:
> tm <- as.POSIXct("2017-07-10 09:03:32.26876", tz = "BRT")
> tm
[1] "2017-07-10 09:03:32.268 BRT"
> format(tm, "%OS5")
[1] "32.26875"
> format(tm, "%OS6")
[1] "32.268759"
POSIXct micro-seconds inconsistencies in R
This question has gone on far too long -- especially considering that the question itself links to the answer.
This is an output representation problem, and is well-known. Rounding time values has implications. You cannot just round the subsecond values without getting incorrect results in some cases.
The solution is here (as linked in the question): How R formats POSIXct with fractional seconds
Stealing directly from Aaron's excellent answer:
myformat.POSIXct <- function(x, digits=0) {
x2 <- round(unclass(x), digits)
attributes(x2) <- attributes(x)
x <- as.POSIXlt(x2)
x$sec <- round(x$sec, digits)
format.POSIXlt(x, paste("%Y-%m-%d %H:%M:%OS",digits,sep=""))
}
x <- as.POSIXct("2012-12-14 15:42:04.577895 EDT")
What you are attempting:
as.POSIXlt(as.POSIXct(sprintf("%s",(format(x, "%Y-%m-%d %H:%M:%OS6")))))$sec
## [1] 4.577894
Aaron's code:
myformat.POSIXct(x, 6)
## [1] "2012-12-14 15:42:04.577895"
One might think to use sprintf
with a format string of %.06f
to format the subsecond value, but this will fail if the value is slightly below an integer:
sprintf('%.06f', .9999999)
## [1] "1.000000"
Converting to a POSIXlt causes the proper rollover into seconds, minutes, etc., if the subsecond value is rounded up.
To show you that this is not a data problem:
y <- as.numeric(x)
y
## [1] 1355521324.5778949261
sprintf('%06f', y - floor(y))
## [1] "0.577895"
Formatting date in R with fractional seconds and AM/PM indicator
You probably need %I
From the document,
%I - Hours as decimal number (01–12).
and
%H -Hours as decimal number (00–23).
as.POSIXct("7/30/2009 9:18:35.000000 PM", format = "%m/%d/%Y %I:%M:%OS %p")
# [1] "2009-07-30 21:18:35 IST"
Reading in a time with fractional seconds and AM/PM
For fractional seconds use %OS
format (it isn't well documented, but it is one of the examples in ?strptime
). You should also remember to use %I
(instead of %H
) when combined with %p
. Also, don't forget to set tz
if needed.
as.POSIXct("2014/10/20 3:00:49.324 PM", format = "%Y/%m/%d %I:%M:%OS %p")
## "2014-10-20 15:00:49 IDT"
Related Topics
Calculate Cumulative Sum (Cumsum) by Group
Selecting Only Numeric Columns from a Data Frame
How to Remove Outliers from a Dataset
Custom Legend For Multiple Layer Ggplot
Format Numbers With Million (M) and Billion (B) Suffixes
Ggplot2 Change Axis Limits For Each Individual Facet Panel
R Shiny - Add Tabpanel to Tabsetpanel Dynamically (With the Use of Renderui)
Replace All Particular Values in a Data Frame
Turning Off Some Legends in a Ggplot
Dplyr Summarise: Equivalent of ".Drop=False" to Keep Groups With Zero Length in Output
Dplyr Filter: Get Rows With Minimum of Variable, But Only the First If Multiple Minima