1

I extract information from a database using the library RODBC.

library(RODBC)
stats <- function(user, pswd){
  qry <- " select mydatetime from bar"
  cn <- odbcConnect("A", uid=user, pwd= pswd)
  rst <- sqlQuery(cn, qry, stringsAsFactors = F)
  odbcClose(cn)
  rm(list = c("cn", "qry"))
  rst
}
my_list <- stats("a", "b")

I'm puzzled by the output. This is a POSIXct datetime. When I my_list$mydatetime the list, it is presented like this:

  [1] "2018-01-19 14:54:23 CET" "2018-01-19 14:53:22 CET" "2018-01-19 14:52:53 CET" "2018-01-19 14:51:50 CET"
  [5] "2018-01-12 11:32:44 CET" "2018-01-12 11:32:02 CET" "2018-01-19 06:53:35 CET" "2018-01-19 06:52:06 CET"
  [9] "2018-01-16 08:50:46 CET" "2018-01-16 08:49:59 CET" "2018-01-16 08:51:47 CET" "2018-01-15 05:31:53 CET"

Notice the CET, which is the correct time zone. When I run attr(my_list$mydatetime,"tzone") I get "".

My question is not how to add a time zone, rather why is a time zone presented when the list is printed- this is confusing, as i assume that it is treated as a CET datetime, when in fact it seems to be a date time with out time zone?

Preston
  • 7,399
  • 8
  • 54
  • 84
  • 1
    It seems you are right to be puzzled. When I read from DB same thing happens, it seems time zone is set to system time zone. Similar discussion here: https://stackoverflow.com/questions/37688509/determine-and-set-timezone-in-posixct-posixlt-strptime-etc-in-r. However when I set a new `POSIXct` object `library(lubridate);testTime1<-ymd_hm("2018-01-01 00:00")` time zone is set to UTC – Antonios Feb 20 '18 at 16:25

1 Answers1

1

Looking at the source for print.POSIXct we see the following:

print.POSIXct <- function (x, tz = "", usetz = TRUE, ...) 
{
  max.print <- getOption("max.print", 9999L)
  FORM <- if (missing(tz)) 
    function(z) format(x, usetz = usetz)
  else function(z) format(x, tz = tz, usetz = usetz)
  if (max.print < length(x)) {
    print(FORM(x[seq_len(max.print)]), ...)
    cat(" [ reached getOption(\"max.print\") -- omitted", 
      length(x) - max.print, "entries ]\n")
  }
  else print(if (length(x)) 
    FORM(x)
  else paste(class(x)[1L], "of length 0"), ...)
  invisible(x)
}

The key point here is that, regardless of whether or not the "tzone" attribute is populated, x is formatted using format.POSIXct. Delving down another layer, we can see that format.POSIXct looks like this:

format.POSIXct <- function (x, format = "", tz = "", usetz = FALSE, ...) 
{
  if (!inherits(x, "POSIXct")) 
    stop("wrong class")
  if (missing(tz) && !is.null(tzone <- attr(x, "tzone"))) 
    tz <- tzone
  structure(format.POSIXlt(as.POSIXlt(x, tz), format, usetz, 
    ...), names = names(x))
}

Again, if the "tzone" attribute exists, it is propagated through. Whether or not it exists, the POSIXct object is coerced into a POSIXlt object before printing. Now we drop off a cliff because as.POSIXlt has an internal call directly to the R interpreter so we can't debug the source code easily.

We can, however, read the documentation for the POSIXlt class (?POSIXlt) and we find out that:

"POSIXlt" objects will often have an attribute "tzone", a character vector of length 3 giving the time zone name from the TZ environment variable and the names of the base time zone and the alternate (daylight-saving) time zone. Sometimes this may just be of length one, giving the time zone name.

So, POSIXlt objects do have a default timezone, taken from the system wide TZ environment variable. Additionally, we read the next paragraph:

"POSIXct" objects may also have an attribute "tzone", a character vector of length one. If set to a non-empty value, it will determine how the object is converted to class "POSIXlt" and in particular how it is printed. This is usually desirable, but if you want to specify an object in a particular time zone but to be printed in the current time zone you may want to remove the "tzone" attribute (e.g., by c(x)).

So the "tzone" attribute in the POSIXct class is to tell the class what timezone to use when converting to POSIXlt (such as for printing) if you do not want it to use the default behavior of using the local timezone.

Eumenedies
  • 1,618
  • 9
  • 13