[Rd] Another issue with Sys.timezone

Stephen Berman stephen.berman at gmx.net
Sun Oct 15 01:53:12 CEST 2017


(I reported the test failure mentioned below to R-help but was advised
that this list is the right one to address the issue; in the meantime I
investigated the matter somewhat more closely, including searching
recent R-devel postings, since I haven't been following this list.)

Last May there were two reports here of problems with Sys.timezone, one
where the zoneinfo directory is in a nonstandard location
(https://stat.ethz.ch/pipermail/r-devel/2017-May/074267.html) and the
other where the system lacks the file /etc/localtime
(https://stat.ethz.ch/pipermail/r-devel/2017-May/074275.html).  My
system exhibits a third case: it lacks /etc/timezone and does not set TZ
systemwide, but it does have /etc/localtime, which is a copy of, rather
than a symlink to, a file under zoneinfo.  On this system Sys.timezone()
returns NA and the Sys.timezone test in reg-tests-1d fails.  However, on
my system I can get the (abbreviated) timezone in R by using as.POSIXlt,
e.g. as.POSIXlt(Sys.time())$zone.  If Sys.timezone took advantage of
this, e.g. as below, it would be useful on such systems as mine and the
regression test would pass.

my.Sys.timezone <- 
    function (location = TRUE) 
{
    tz <- Sys.getenv("TZ", names = FALSE)
    if (!location || nzchar(tz)) 
        return(Sys.getenv("TZ", unset = NA_character_))
    lt <- normalizePath("/etc/localtime")
    if (grepl(pat <- "^/usr/share/zoneinfo/", lt) ||
        grepl(pat <- "^/usr/share/zoneinfo.default/", lt)) 
        sub(pat, "", lt)
    else if (lt == "/etc/localtime")
        if (!file.exists("/etc/timezone"))
            return(as.POSIXlt(Sys.time())$zone)
        else if (dir.exists("/usr/share/zoneinfo") && {
            info <- file.info(normalizePath("/etc/timezone"), extra_cols = FALSE)
            (!info$isdir && info$size <= 200L)
        } && {
            tz1 <- tryCatch(readBin("/etc/timezone", "raw", 200L), 
                            error = function(e) raw(0L))
            length(tz1) > 0L && all(tz1 %in% as.raw(c(9:10, 13L, 32:126)))
        } && {
            tz2 <- gsub("^[[:space:]]+|[[:space:]]+$", "", rawToChar(tz1))
            tzp <- file.path("/usr/share/zoneinfo", tz2)
            file.exists(tzp) && !dir.exists(tzp) &&
                identical(file.size(normalizePath(tzp)), file.size(lt))
        }) 
            tz2
        else NA_character_
}

One problem with this is that the zone component of as.POSIXlt only
holds the abbreviated timezone, not the Olson name.  I don't know how to
get the Olson name using only R functions, but maybe it would be good
enough to return the abbreviated timezone where possible, e.g. as above.
(On my system I can get the Olson name of the timezone in R with a shell
pipeline, e.g.: system("find /usr/share/zoneinfo/ -type f | xargs md5sum
| grep $(md5sum /etc/localtime | cut -d ' ' -f 1) | head -n 1 | cut -d
'/' -f 5,6"), but the last part of this is tailored to my configuration
and the whole thing is not OS-neutral, so it isn't suitable for
Sys.timezone.)

Steve Berman



More information about the R-devel mailing list