18

For logging purposes, how can an R script get the current date and time, in the UTC time zone, as an ISO 8601 string in this format:

2015-12-31T14:26:56.600374+00:00

as.POSIXlt seems to be the solution, and the documentation claims that it accepts a format parameter, but I can't make that work (on R version 3.1.3):

> as.POSIXlt(Sys.time(), "UTC", "%Y-%m-%dT%H:%M:%S")
[1] "2015-04-08 14:37:58 UTC"
> as.POSIXlt(Sys.time(), tz="UTC", format="%Y-%m-%dT%H:%M:%S")
[1] "2015-04-08 14:38:02 UTC"
> as.POSIXct(Sys.time(), tz="UTC", format="%Y-%m-%dT%H:%M:%S")
[1] "2015-04-08 11:38:22 BRT"
Fernando Correia
  • 21,803
  • 13
  • 83
  • 116

2 Answers2

26

as.POSIXlt (and as.POSIXct) are for input. Use either format or strftime for output. See ?strftime for details on format strings:

 tm <- as.POSIXlt(Sys.time(), "UTC")
 strftime(tm , "%Y-%m-%dT%H:%M:%S%z")
#[1] "2015-04-08T15:11:22+0000"

The third parameter of as.POSIXlt, format, is used when the first parameter is a string-like value that needs to be parsed. Since we are passing in a Date value from Sys.time, the format is ignored.

I don't think that the colon in the timezone output is requirement of the ISO 8601 format but I could be wrong on that point. The help page says the standard is POSIX 1003.1. May need to put in the colon with a regex substitution if needed.

After looking at http://dotat.at/tmp/ISO_8601-2004_E.pdf I see that there is no colon in the "basic" format" timezone representation, but there is one in the "extended format".

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • 2
    Oh, that makes sense. Still, the "format" (3rd) parameter of `as.POSIXlt` doesn't seem to make a difference. Changing it, even removing the time part, didn't change the output. This seems to work: `strftime(as.POSIXlt(Sys.time(), "UTC"), "%Y-%m-%dT%H:%M:%S%z")`. – Fernando Correia Apr 08 '15 at 15:22
  • 2
    Right. You code is what I did except you omitted the intermediate variable creation. When you use unnamed argument positional matching is used so when we gave it a numeric value, it matched that format to the "..." parameter of the `as.POSIXlt.POSIXct` function. And then it basically ignored it, anyway. It doesn't get passed to the internal function. – IRTFM Apr 08 '15 at 15:32
  • I think what OP is confused about here is the fact that `as.POSIXlt(x=Sys.time(), tz="UTC", format="%Y-%m-%d")` and `as.POSIXlt(x=Sys.time(), tz="UTC")` return exactly the same thing. This is a confusing result of polymorphism with the `x` parameter. The `format` parameter is completely ignored unless `x` is string-like. – 7yl4r Feb 15 '21 at 22:55
  • 1
    @7yl4r Thanks. You are quite right that my earlier code had a superfluous parameter in the context of a "Date"-classed value. – IRTFM Feb 16 '21 at 21:45
  • The format `"%Y-%m-%dT%H:%M:%S%z"` appears to fall between the `basic` and `extended` ISO formats. The date and time parts have punctuation, but the time zone offset does not. This is rejected by SQL Server as a valid date/time for `datetimeoffset` data type. the suggestion about adding the colon into the offset with a regex substitution seems to be necessary in this case. I would appreciate an example of an effective way to do this. – sch56 Jul 21 '21 at 02:06
  • This appears to work where x is in the format above: `sub('(+[0-9]{2})([0-9]{2}$)','\\1:\\2', x , fixed=FALSE)` – sch56 Jul 21 '21 at 02:25
  • For file names, `"%Y%m%dT%H%M%S"` seems fair enough to me, maybe `paste0` a `"Z"` if UTC/GMT was used. _Example:_ `"20230326T183011Z"`. – jay.sf Mar 26 '23 at 18:31
7

The package parsedate recognizes and parses Dates in various formats, including all ISO 8601 Formats:

format_iso_8601(Sys.time())
# [1] "2017-09-01T10:59:22+00:00"
Enrique Pérez Herrero
  • 3,699
  • 2
  • 32
  • 33