【问题标题】:Converting to Local Time in R - Vector of Timezones在 R 中转换为本地时间 - 时区向量
【发布时间】:2015-11-12 01:50:22
【问题描述】:

我有一组来自美国各地的数据,我正在尝试将这些数据转换为每个“主题”的当地时间。我对每个事件都有 UTC 时间戳并将其转换为 POSIXct 格式,但每次我尝试在任何 POSIXct/POSIXlt 函数中包含tz = DS$Factortz = as.character(DS$Factor) 的向量(包括format()strftime())我收到一条错误消息:

as.POSIXlt.POSIXct(x, tz = tz) 中的错误:'tz' 值无效

如果我只输入tz = 'US/Eastern',它可以正常工作,但当然不是我所有的值都来自那个时区。

如何将每个“主题”的时间戳转换为当地时间?

DS$Factor 有 5 个值:US/Arizona US/Central US/Eastern US/Mountain US/Pacific

谢谢, 速记

【问题讨论】:

    标签: timezone format strftime posixct posixlt


    【解决方案1】:

    引入 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()
    • rowwise 的方法非常非常慢。我建议查看这些解决方案,它们的速度要快得多:community.rstudio.com/t/working-with-timezones-in-lubridate/…
    【解决方案2】:

    实际上,我所做的是遍历时区而不是数据集中的行数……然后它就快得多了。我明天会发布代码。

    总的来说,这是 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
    【解决方案3】:

    所以我能够创建一个 for 循环来执行此操作,但速度很慢,大约需要 10 分钟才能运行。我想不出apply() sytnax,当然希望有人帮助我创建一种更快、更可并行化的方式来执行此操作,因为数据存储区有 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 循环。必须有更好的方法。
    猜你喜欢
    • 1970-01-01
    • 2020-06-12
    • 1970-01-01
    • 2019-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-09
    相关资源
    最近更新 更多