jsonlite icon indicating copy to clipboard operation
jsonlite copied to clipboard

toJSON dropping POSIX timezone data

Open ieaves opened this issue 8 years ago • 7 comments

The timezone aware portion of POSIX datetimes appear to be being dropped during JSON encoding.

for example:

Browse[2]> as.POSIXlt(Sys.time(), tz= 'UTC')
[1] "2017-04-13 19:12:10 UTC"

But,

Browse[2]> jsonlite::toJSON(as.POSIXlt(Sys.time(), tz= 'UTC'))
["2017-04-13 19:13:19"] 

ieaves avatar Apr 13 '17 19:04 ieaves

In R, the tz just controls the rendering of the date-time, not the instant it refers to. In JSON, all date-times will be rendered as UTC.

hadley avatar Apr 21 '17 13:04 hadley

The asJSON.POSIXt method has a parameters time_format which you can use to customise the date format, as well as UTC to control if dates get printed in local time or UTC:

> x <- Sys.time()
> jsonlite::toJSON(x)
["2017-04-21 09:46:03"]
> jsonlite::toJSON(x, UTC = TRUE)
["2017-04-21 13:46:03"]

jeroen avatar Apr 21 '17 13:04 jeroen

It doesn't use UTC by default, eeek!

hadley avatar Apr 21 '17 14:04 hadley

The shiny wrapper does use UTC = TRUE by default.

It can be surprising to users that timestamps get converted to UTC when printing in JSON. E.g. if you read text data with a timestamp column and then convert to JSON, the output values will depend on which timezone you're in.

str <- "2017-04-21 15:16:04"
time <- as.POSIXct(str)
toJSON(str, UTC = TRUE)

jeroen avatar Apr 21 '17 14:04 jeroen

Although the timezone piece is primarily a rendering component it's useful when communicating across multiple services (potentially in different timezones).

I'm not as comfortable in R as I am in other languages so I was reluctant to make code suggestions (so be gentle :)) but there appears to be a tzone attribute attached to POSIXlt objects that might provide an additional piece of logic to the UTC flag?

  if(is.null(time_format)){
    time_format <- if(POSIXt == "string"){
      ""
    } else if (!is.null(attr(x, 'tzone'))) {
       "%Y-%m-%dT%H:%M:%SZ"
    } else if(isTRUE(UTC)){
      "%Y-%m-%dT%H:%M:%SZ"
    } else {
      "%Y-%m-%dT%H:%M:%S"
    }
  }

This way, if a user explicitly provides a timezone it isn't implicitly cast to another value.

ieaves avatar Apr 21 '17 15:04 ieaves

Generally, I think it's best to always send date-times between systems as UTC.

hadley avatar Apr 21 '17 16:04 hadley

Definitely agreed, that's not the only use case for timezone aware datetimes though. It just seems natural that the json encoding would respect the underlying data rather than coercing it where possible.

ieaves avatar Apr 21 '17 16:04 ieaves