根据本地国家信息检索时区(与操作系统无关)

4

又是一个与日期/时间相关的问题;-)

在动手之前

由于以下组合会导致无效的时区,因此使用德国+MS Windows+R可能会存在一些混乱:

> Sys.timezone()
[1] "MST"
Warning message:
In as.POSIXlt.POSIXct(Sys.time()) : unknown timezone 'MET-1MST'

这绝对不是R的错,而是Windows的问题。这就是为什么一开始有这个问题的原因 ;-)

问题

是否有一种易于使用/替代性的、独立于操作系统的方法来通过区域设置信息查询您当前所在的国家,并查找相应的时区(格式为“<country>/<city>”,例如德国的“Europe/Berlin”)?

我还要补充一点,我希望解决方案不依赖于互联网资源,如在此帖子/答案中所述。

问题背景

假设您不知道如何指定您的时区。您可能听说过一些有关CET/CEST等的内容,但据我所知,在使用基本R功能时(至少在德国),这并不能让您找到正确的时区。

您可以从RHOME目录中的/share/zoneinfo/zone.tab文件中获取可用的"<country>/<city>"对列表。但是,为了找到与您所在的国家对应的时区,您需要知道ISO国家代码。

当然,我们通常知道我们自己的本国代码,但是让我们假设我们不知道(我想最终得到一种通用方法)。那么接下来该怎么办呢?

以下是我的“四步解决方案”,但我并不是很满意它,因为:

  1. 它依赖于另一个贡献包(ISOcodes)。
  2. 我无法测试它是否适用于其他区域设置,因为我不知道如果您在印度、俄罗斯、澳大利亚等地,信息实际上看起来如何。

有没有更好的想法?而且,如果您所在的国家不是德国,那么希望您能运行此程序并发布您的区域设置信息Sys.getlocale()

步骤1:获取区域设置信息

loc <- strsplit(unlist(strsplit(Sys.getlocale(), split=";")), split="=")
foo <- function(x) {
    out <- list(x[2])
    names(out) <- x[1]
    out
}
loc <- sapply(loc, foo)

> loc
$LC_COLLATE
[1] "German_Germany.1252"

$LC_CTYPE
[1] "German_Germany.1252"

$LC_MONETARY
[1] "German_Germany.1252"

$LC_NUMERIC
[1] "C"

$LC_TIME
[1] "German_Germany.1252"

步骤2:从本地信息获取国家名称

country.this <- unlist(strsplit(loc$LC_TIME, split="_|\\."))[2]

> country.this 
[1] "Germany"

第三步:获取ISO国家代码

使用country.this在数据集ISO_3166_1中查找相关的国家代码,该数据集位于ISOcodes包中。

require("ISOcodes")
data("ISO_3166_1")
iso  <- ISO_3166_1
idx  <- which(iso$Name %in% country.this)
code <- iso[idx, "Alpha_2"]

> code
[1] "DE"

步骤4:获取时区

使用代码在从文件RHOME/share/zoneinfo/zone.tab派生出来的数据框中查找时区。

path <- file.path(Sys.getenv("R_HOME"), "share/zoneinfo/zone.tab")    
tzones <- read.delim(
    path, 
    row.names=NULL, 
    header=FALSE,
    col.names=c("country", "coords", "name", "comments"),
    as.is=TRUE, 
    fill=TRUE, 
    comment.char = "#"
)

> tzones[which(tzones$country == code), "name"]
[4] "Europe/Berlin"

不需要在Windows上运行。那么关于涉及到此处提到的命令行调用的system调用呢? - Jase_
“FINDSTR Zone” 无法打开。 - Rappster
抱歉,我不在Windows上,所以无法测试它。我认为它可能会解决问题。过去我曾因时区+R+Windows而受到伤害,通常手动设置时区。当然,这并没有回答你的问题。 - Jase_
@Rappster:尝试使用shell('systeminfo | findstr ".*zone:"')。或者你可以使用注册表:readRegistry("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", "HLM", 2)(这两种解决方案仅适用于Windows)。 - sgibb
@sgibb:谢谢你的回复。我刚试了一下,但是我仍然遇到了一个错误(Win XP,32位,SP 3):时区:不可用。 - Rappster
显示剩余2条评论
2个回答

2

关于您的问题:

是否有一种简单/替代的、不依赖操作系统的方法通过区域信息查询当前所在国家,并查找相应的时区?

不,没有这样的方法。这是因为有些国家有多个时区,仅凭国家无法确定时区。

这就是为什么 TZDB 标识符采用 Area/Location 的形式,而不仅仅是国家代码列表。


谢谢您澄清,现在很清楚了。那么问题可能更多地是如何找出连接到互联网的计算机的IP地址“位于”哪里,以获取区域/位置类型的信息。我知道有一些网络服务可以做到这一点,但您是否知道任何可以实现此功能的R软件包? - Rappster
你应该阅读这篇文章了解如何获取时区。但通过IP地址获得经纬度被称为“IP地理定位”,这并不是非常可靠的,因为你的IP地址可能是代理服务器。如果你有一个真实的地址,有各种服务可以将其转换为坐标。如果你有移动设备,可以使用GPS或基站定位。但很遗憾,没有单一通用的解决方案。 - Matt Johnson-Pint

0

简化您的工作流程。

您可以使用以下代码仅检索本地时间部分:

Sys.getlocale("LC_TIME")

这避免了需要拆分字符串的需求。

lubridate包含一个函数,用于检索Olson风格的时区名称,因此您不必担心读取和解析zone.tab

library(lubridate)
olson_time_zones()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接