在R中转换为本地时间 - 时区向量

5
我有一组来自美国各地的数据,我想将每个“主体”的数据转换为当地时间。我已经在每个事件上有了UTC时间戳,并将其转换为POSIXct格式,但每次我尝试在任何POSIXct/POSIXlt函数中包括tz = DS$Factortz = as.character(DS$Factor) 的向量时(包括format()strftime()),都会出现以下错误:

Error in as.POSIXlt.POSIXct(x, tz = tz) : invalid 'tz' value

如果我只输入tz ='US/Eastern'它就可以正常工作,但当然不是所有的值都来自该时区。
如何将时间戳转换为每个“主体”的本地时间? DS$Factor有5个值:US/Arizona US/Central US/Eastern US/Mountain US/Pacific
谢谢, Shorthand
3个回答

2

使用dplyr和lubridate,我最终做了这样的事情:

require(lubridate)
require(dplyr)

df = data.frame(timestring = c("2015-12-12 13:34:56", "2015-12-14 16:23:32"),
                localzone = c("America/Los_Angeles", "America/New_York"), stringsAsFactors = F)

df$moment = as.POSIXct(df$timestring, format="%Y-%m-%d %H:%M:%S", tz="UTC")

df = df %>% rowwise() %>% mutate(localtime = force_tz(moment, localzone))

df

似乎问题在于as.POSIXct不喜欢接受向量,它只接受字符串。因此,使用rowwise()可以避免使用force_tz的解决方法。所以这个可以工作:df %>% rowwise() %>% mutate(moment = as.POSIXct(timestring, format="%Y-%m-%d %H:%M:%S", tz=localzone) %>% ungroup() - Lloyd Christmas
rowwise方法非常慢。我建议查看这些解决方案,它们速度更快:https://community.rstudio.com/t/working-with-timezones-in-lubridate/4260/6 - Lloyd Christmas

1
实际上,我所做的是循环遍历时区而不是数据集中的行数...这样速度会快得多。明天我会发布代码。
总的来说,这是R的一个教训:不要循环遍历大型数据框,而是循环遍历(更短的)类别向量并使用which()函数应用。
由于只有5个时区,现在循环只需要几秒钟。
另一个注意事项是,如果将其放入POSIXct格式,则仍会在计算机本地时区中绘制时间。因此,您需要额外的步骤将其转换为本地时间,使用force_tz()。
cap$tdiff只是为了确保代码正在执行其应该执行的操作。
library("lubridate")    

tzs <- as.character(unique(cap$timezone))

cap$localtimes <- as.POSIXlt(0,origin = "1970-01-01")

#now loop through by timezone instead of lines of cap[]
for (i in 1:length(tzs)) {
  whichrows <- which(cap$timezone == tzs[i])

  cap[whichrows,"localtimes"] <-
    with_tz(cap[whichrows,"UTC"],tzone = tzs[i])
}

remove(i, whichrows)

cap$tdiff <- as.numeric((force_tz(cap$localtime, "UTC") - cap$UTC))
cap$localtime <- as.POSIXct(force_tz(cap$localtimes))

我想补充一下,这是我仍然在R中使用循环的少数几次之一...你也可以通过group_by(timezone) %>% group_split() %>% map_dfr(function(df_i){df_i$timestamp <- with_tz(df_i$timestamp, tzone = df_i$tzn[1]})来实现。 - Shorthand

0

所以我能够创建一个for循环来完成这个操作,但是它很慢,需要大约10分钟才能运行。我无法弄清楚apply()的语法,并且肯定会感激一些帮助来创建更快、更可并行化的方式来执行此操作,因为数据存储器有768k个观测值并且还在增长。

>     require(lubridate)
>     
>     loct = NULL for (i in 1:nrow(DS))
>     {
>       loct[i] <- with_tz(DS$UTC[i],tzone =
>       ifelse(DS$timezone[i]=="","US/Eastern",as.character(DS$timezone[i])))
>     } DS$localtime <- as.POSIXct(loct, origin ="1970-01-01") remove (loct, i)

我需要做同样的事情。我想到的最好方法也是使用for循环。一定有更好的方法。 - josiekre

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