R - 给定奥尔森时区的 UTC 到本地时间

Posted

技术标签:

【中文标题】R - 给定奥尔森时区的 UTC 到本地时间【英文标题】:R - UTC to LOCAL time given Olson timezones 【发布时间】:2014-08-26 20:21:56 【问题描述】:

我有 1974 年至 2013 年的时间序列数据,其中有一列表示 datetimeUTC (YYYY-MM-DD hh:mm +0000),有一列表示奥尔森格式的时区(例如,加拿大/太平洋、加拿大/东部) .我可以将整个 UTCdatetime 列转换为这样的公共时区:

dataset$datetimeEST <- strptime(
  dataset$datetimeUTC, format="%Y-%m-%d %H:%M:%S%z", tz="Canada/Eastern"
)  

在给定每行对应的时区的情况下,如何将datetimeUTC 转换为datetimeLOCAL

让我稍微备份一下。我有来自全国各地(6 个时区)的数据,格式为 1974-2013 年的 ISO8601 表示。时间戳全年采用当地标准时间(即,即使该地区的民用时间遵守 DST,也忽略 DST)。我需要进行日期时间计算,这在 UTC 时间可能是最安全的,所以这很容易。但是,我还需要提取特定民用时间段的数据,同时考虑 DST,并为该子集数据进行计算和绘图(例如,所有 6 个时区位置的高峰时间的所有数据)。

我在下面计算的 datetimeCLOCKTIME 似乎正在做我想要的绘图,但在进行日期时间计算时给出了错误的答案,因为它将日期时间存储在我本地机器的时区中而没有实际转换时间。 @thelatemail 提供的解决方案是我正在寻找的,但我无法让它在 2012 年的测试数据集上的 Windows 中工作(见下文)。另外,我使用的是转换为 POXITlt 的 strptime,他的解决方案是在 POXITct 中。我是 R 新手,所以任何帮助都将不胜感激。

测试数据集:

    dataset <- data.frame (timestampISO8601 = c("2012-04-25T22:00:00-08:00","2012-04-25T22:15:00-08:00","2012-04-25T22:30:00-08:00","2012-04-25T22:45:00-08:00","2012-04-25T23:00:00-08:00","2012-04-25T23:15:00-08:00","2012-04-25T23:30:00-08:00","2012-04-25T23:45:00-08:00","2012-04-26T00:00:00-08:00","2012-04-26T00:15:00-08:00","2012-04-26T00:30:00-08:00","2012-04-26T00:45:00-08:00","2012-04-26T01:00:00-08:00","2012-04-26T01:15:00-08:00","2012-04-26T01:30:00-08:00","2012-04-26T01:45:00-08:00","2012-04-26T02:00:00-08:00","2012-04-25T22:00:00-03:30","2012-04-25T22:15:00-03:30","2012-04-25T22:30:00-03:30","2012-04-25T22:45:00-03:30","2012-04-25T23:00:00-03:30","2012-04-25T23:15:00-03:30","2012-04-25T23:30:00-03:30","2012-04-25T23:45:00-03:30","2012-04-26T00:00:00-03:30","2012-04-26T00:15:00-03:30","2012-04-26T00:30:00-03:30","2012-04-26T00:45:00-03:30","2012-04-26T01:00:00-03:30","2012-04-26T01:15:00-03:30","2012-04-26T01:30:00-03:30","2012-04-26T01:45:00-03:30","2012-04-26T02:00:00-03:30"), olson = c("Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Pacific","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland","Canada/Newfoundland"), value = c(0,0,1,2,5,11,17,19,20,19,17,11,5,2,1,0,0,-3,-3,-2,-1,2,8,14,16,17,16,14,8,2,-1,-2,-3,-3), stringsAsFactors=FALSE)

从 UTC 偏移量中删除“:”。 (R 期望 UTC 偏移的格式为 nnnn):

    dataset$timestampR<- paste(substr(dataset$timestampISO8601,1,22),substr(dataset$timestampISO8601,24,25),sep="")

当转换为 UTC 时间时,R 默认为 -ve 作为 UTC 偏移量,使时间戳中的 -ve 偏移量为正:

    dataset$datetimeUTC <- strptime(dataset$timestampR, format="%Y-%m-%dT%H:%M:%S%z", tz="UTC")

当像这样转换为 MACHINE 时间时,R 读取输入时间并将其转换为本地机器时区的时间 - 在我的例子中,这是加拿大/东部:

    dataset$datetimeMACHINE <- strptime(dataset$timestampR, format="%Y-%m-%dT%H:%M:%S%z")

当像这样转换为 CLOCKTIME 时间时,R 读取输入时间并分配本地机器的时区(当前在我的机器上是 EDT)而不进行任何时间转换:

    dataset$datetimeCLOCKTIME <- strptime(dataset$timestampR,format="%Y-%m-%dT%H:%M:%S")

查看数据集的结构:

    str(dataset)  

绘图行为不同

    library(ggplot2)
    qplot(data=dataset,x=datetimeUTC,y=value)
    qplot(data=dataset,x=datetimeMACHINE,y=value)
    qplot(data=dataset,x=datetimeCLOCKTIME,y=value)

计算结果不同。 datetimeCLOCKTIME 的计算结果不正确:

    range (dataset$datetimeUTC)
    range (dataset$datetimeMACHINE)
    range (dataset$datetimeCLOCKTIME)

    dataset$datetimeUTC[34] - dataset$datetimeUTC[1]
    dataset$datetimeMACHINE[34] - dataset$datetimeMACHINE[1]
    dataset$datetimeCLOCKTIME[34] - dataset$datetimeCLOCKTIME[1]

【问题讨论】:

你不能。时区适用于整个日期/时间向量,而不是特定元素。如果您备份几个步骤并解释您要解决的更大问题,可能会有更简单的方法来解决它。 仅供参考 - 您应该考虑使用规范时区,例如 "America/Toronto""America/Vancouver""Canada/*" 区域主要用于向后兼容的目的。 See the list here 如果您在确定要使用的正确区域时需要帮助。 等一下,你说"DST is disregarded even if civilian time in the region observes DST." 如果是这样,那么你根本不应该使用奥尔森时区。像 "Canada/Eastern" 这样的区域仅在标准时间是 UTC-05:00。 DST 期间是 UTC-04:00。如果这不是您想要的,您可能应该使用固定偏移量。 @Matt Johnson。这些数据是从记录当地标准时间的仪器中收集的,具有固定的偏移量,全年无休,未针对 DST 进行调整。这些地方中的一些(但不是全部)遵守夏令时。因此,根据我想要做什么,我需要能够将所有内容从本地标准时间转换为本地时间,并在适用的情况下考虑 DST。感谢您提供有关规范时区的提示! 【参考方案1】:

您可以来回格式化一下,以获得字符格式的本地时间表示。例如:

dataset <- data.frame(
  datetimeUTC=c("2014-01-01 00:00 +0000","2014-01-01 00:00 +0000"),
  olson=c("Canada/Eastern", "Canada/Pacific"),
  stringsAsFactors=FALSE
)

#             datetimeUTC          olson
#1 2014-01-01 00:00 +0000 Canada/Eastern
#2 2014-01-01 00:00 +0000 Canada/Pacific

dataset$localtime <- with(dataset, 
     mapply(function(dt,ol) format(
              as.POSIXct(dt,"%Y-%m-%d %H:%M %z",tz=ol),
              "%Y-%m-%d %H:%M %z"), 
              datetimeUTC, olson
            )
     )

#             datetimeUTC          olson              localtime
#1 2014-01-01 00:00 +0000 Canada/Eastern 2013-12-31 19:00 -0500
#2 2014-01-01 00:00 +0000 Canada/Pacific 2013-12-31 16:00 -0800

【讨论】:

在我的 MacBookPro 上,当我在 Mac 端运行它时,我得到了和你一样的结果——这就是我想要的。但是,我也在 Parallels 上使用 Windows7 虚拟机。当我在 Windows 端运行你的 R 代码时,它给了我相同的时钟时间,但在东部标准时间。 在我的 MacBookPro 上,当我在 Mac 端运行它时,我得到了和你一样的结果——这就是我想要的。但是,我也在 Parallels 上使用 Windows7 虚拟机。当我在 Windows 端运行你的 R 代码时,它给了我与你的结果相同的时钟时间,但在东部标准时间,这是我的机器所在的位置。 @JAQ - 我已经在 Linux/Win7 上测试过,两次都得到了相同的结果。我不知道该说什么。 R2.15.3 64bit, x86_64-w64-mingw32/x64, Parallels/Win7 $ datetimeUTC: chr "2014-01-01 00:00 +0000" "2014-01-01 00:00 + 0000" $ olson: chr "America/Toronto" "America/Vancouver" $ localtime: chr "2013-12-31 19:00 Eastern Standard Time" "2013-12-31 16:00 Eastern Standard Time" R3.0.2 64bit , x86_64-apple-darwin10.8.0, MacBookPro $ datetimeUTC: chr "2014-01-01 00:00 +0000" "2014-01-01 00:00 +0000" $ olson: chr "America/Toronto" "America/温哥华" $ localtime : chr "2013-12-31 19:00 -0500" "2013-12-31 16:00 -0800" 我在运行 Windows7 和 R3.0.3 64 位的另一台计算机(Lenovo 2014 型号 ThinkPad)上得到相同(错误)的结果。因此,问题不在于 Parallels。所有机器上的机器时区都是东部夏令时间。这让我担心 Windows 机器上的日期和时间还有什么问题,特别是因为我的大部分工作都在 Windows 端。【参考方案2】:

如果您只有两个时区可以转换并知道 UTC 与这两个之间的时差。使用@thelatemail 的dataset

transform(dataset, 
localtime=as.POSIXct(datetimeUTC, "%Y-%m-%d %H:%M %z")-
           c(5*3600,8*3600)[as.numeric(factor(olson))])
 #            datetimeUTC          olson           localtime
#1 2014-01-01 00:00 +0000 Canada/Eastern 2013-12-31 19:00:00
#2 2014-01-01 00:00 +0000 Canada/Pacific 2013-12-31 16:00:00

【讨论】:

我考虑过这样的事情(可能使用查找表),但担心夏令时可能会破坏它。不过,它可能在很多情况下都可以正常工作。

以上是关于R - 给定奥尔森时区的 UTC 到本地时间的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 的本地时间和UTC时间

给定 UTC 时间戳和 UTC 偏移量,是不是可以在 Python 中获取时区?

python / pytz问题从本地时区转换为UTC然后返回

Javascript-基础-Date本地时间与UTC(GMT)时间转换

如何将系统时间转换成utc时间

从时区和 UTC 时间,获取该时间点与本地时间的秒差