【问题标题】:R Change from stardard UTC time zone to multiple local time zonesR 从标准 UTC 时区更改为多个本地时区
【发布时间】:2018-12-07 19:01:47
【问题描述】:

假设我有一个 df,其中包含对一项调查的一系列回复。每个响应都有一个 UTC 时间戳。我也恰好有填写调查表的每个人的当地时区。

例如:

 df <-  data.frame(day = c("2018-12-06 15:40:29", "2018-12-06 15:25:28", 
"2018-12-06 15:25:28", "2018-12-06 14:09:09"), time_zone = c("EST", "PST", "CST", "EST"))

df$day <- as.POSIXct(df$day, tz = "UTC")

我希望所有这些日期都反映参加调查的人在当地的时间。所以我尝试了以下方法:

df %>% 
  mutate(time_start = format(day, tz = time_zone))

但我得到Error in mutate_impl(.data, dots) : Evaluation error: invalid 'tz' value.

我也尝试过使用具有 GTM 格式时区的数据框

df<-  data.frame(day = c("2018-12-06 15:40:29", "2018-12-06 15:25:28", 
"2018-12-06 15:25:28", "2018-12-06 14:09:09"), 
time_zone = c("GMT-5", "GMT-6", "GMT-7", "GMT-8"))

有没有办法将一系列标准化时间改为当地时间?

【问题讨论】:

  • 我怀疑有两个问题:(1)我熟悉的日期/时间函数都没有为tz 取多个值,因此invalid 'tz' value; (2) "GMT-7" 未被 R 识别为有效时区,通过 format(Sys.time(), tz="GMT-7")format(Sys.time(), tz="GMT") 进行验证。

标签: r datetime timezone posixct


【解决方案1】:

这里有多个问题:

  1. format(和其他与时间相关的函数)只为 tz 采用长度为 1 的参数;
  2. R 识别的时区不包括流行的"CST""PST" 等。

要解决第一个问题,使用Mapmapply 就足够了。

不幸的是,第二个需要更多的研究。像"PST" 之类的区域,虽然至少在美国很流行,如果不是其他国家的话,它们不是有效的时区字符串(参考:CCTZ,一个用于在时区之间转换的 C++ 库,says so)。 "GMT-7" 等人都不是,尽管后者可以被 prepending with Etc/ 伪造,如:"Etc/GMT-7"。或者你可以选择"America/New_York""US/Eastern"

df$time_zone <- c("US/Eastern", "US/Pacific", "US/Central", "US/Eastern")
df
#                   day  time_zone
# 1 2018-12-06 15:40:29 US/Eastern
# 2 2018-12-06 15:25:28 US/Pacific
# 3 2018-12-06 15:25:28 US/Central
# 4 2018-12-06 14:09:09 US/Eastern
mapply(format, df$day, tz = "GMT")
# [1] "2018-12-06 15:40:29" "2018-12-06 15:25:28" "2018-12-06 15:25:28"
# [4] "2018-12-06 14:09:09"
mapply(format, df$day, tz = df$time_zone)
# [1] "2018-12-06 10:40:29" "2018-12-06 07:25:28" "2018-12-06 09:25:28"
# [4] "2018-12-06 09:09:09"

所有可立即识别的 R 时区格式都可以在 594 元素向量中找到:

str(OlsonNames())
#  chr [1:592] "Africa/Abidjan" "Africa/Accra" "Africa/Addis_Ababa" ...
#  - attr(*, "Version")= chr "2018e"
set.seed(2)
sample(OlsonNames(), size=8)
# [1] "America/El_Salvador"  "Etc/GMT+8"            "Atlantic/Madeira"    
# [4] "America/Creston"      "Pacific/Port_Moresby" "Pacific/Ponape"      
# [7] "America/Atka"         "GB-Eire"             
grep("US/", OlsonNames(), value = TRUE)
#  [1] "US/Alaska"         "US/Aleutian"       "US/Arizona"       
#  [4] "US/Central"        "US/East-Indiana"   "US/Eastern"       
#  [7] "US/Hawaii"         "US/Indiana-Starke" "US/Michigan"      
# [10] "US/Mountain"       "US/Pacific"        "US/Pacific-New"   
# [13] "US/Samoa"         

在此示例中,您将看到可以使用的备选方案之一:"Etc/GMT+8"。注意+ 在本初子午线的西,所以

mapply(format, df$day, tz = "US/Eastern")
# [1] "2018-12-06 10:40:29" "2018-12-06 10:25:28" "2018-12-06 10:25:28"
# [4] "2018-12-06 09:09:09"
mapply(format, df$day, tz = "Etc/GMT+5")
# [1] "2018-12-06 10:40:29" "2018-12-06 10:25:28" "2018-12-06 10:25:28"
# [4] "2018-12-06 09:09:09"

警告购买者:使用"US/Eastern" 应在适当的情况下考虑夏令时; "Etc/GMT+5" 没有,我相信。

【讨论】:

  • 谢谢,这解决了。虽然它运行得很慢。这是预期的吗?
  • 不足为奇。因为format(和朋友)不允许矢量化tz= 参数,所以我们为帧的每一行调用一次format。实际上,有一种方法可能更快:对数据进行分组。您使用的是dplyr 还是data.table?如果是这样,我们可以修改此方法以每个唯一时区调用一次format,这应该会显着提高性能。 (即使您没有使用这些软件包中的任何一个,我们也可以这样做,尽管它不太容易阅读。)
  • 但它在我的 4 行样本中运行得非常快;-)
  • 如果我不回复它,在确保所有 time_zone 字段都是合法的之后,类似 by(df, df$time_zone, function(d) format(d$day, tz=d$time_zone[1])) 的内容。
猜你喜欢
  • 2011-09-16
  • 1970-01-01
  • 1970-01-01
  • 2020-08-31
  • 2014-08-12
  • 1970-01-01
  • 1970-01-01
  • 2017-04-23
  • 1970-01-01
相关资源
最近更新 更多