首页 文章

R-有效地将时间(以毫秒为单位)转换为具有不同时区的as.POSIXct

提问于
浏览
0

我想将具有不同时区的多个时间值(当前表示为自01-01-1970以来的毫秒数)转换为POSIXct格式 .

我有以下数据集:

times <- c(1427450400291, 1428562800616, 1418651628795, 1418651938990, 1418652348281, 1418652450161)
tzones <- c("America/Los_Angeles", "Africa/Casablanca", "Africa/Casablanca", "Africa/Casablanca", "Africa/Casablanca", "Israel Standard Time")

问题是 as.POSIXct 方法只接受一个tz值,而不是一个向量 . 因此,我无法直接调用它 . 我尝试使用lapply并逐个元素地调用它,但它需要很长时间(对于更长的向量):

get.dates.with.timezones <- function(epoch.vec,tz.vec) {  
    res <- lapply(seq(epoch.vec),function(x){
           as.POSIXct(epoch.vec[x]/1000,origin = "1970-01-01", tz = tz.vec[x])
        })
        return(do.call(c,res))
}

因此,对于仅1200个值,它需要几乎一秒钟 .

timesX200 <- rep(times,200)
tzonesX200 <- rep(tzones,200)
system.time( get.dates.with.timezones(timesX200,tzonesX200) )
           user              system             elapsed 
0.86800000000005184 0.01999999999999602 0.88899999999921420

我是R的新手,所以我想知道是否有办法改善这项任务的性能 . 这个问题有一个矢量化选项吗?此外,看起来 as.POXIXct() 方法本身也存在一些性能问题,如here所示 .

----------编辑--------

显然,不可能持有不同时区的POSIXct矢量 . 从POSIXct文档:

在“POSIXlt”对象上使用c将它们转换为当前时区,在“POSIXct”对象上删除任何“tzone”属性(即使它们都标有相同的时区) . 资源

这太糟糕了 . 我想知道是否有任何替代方案来处理日期时间变化的时区 . 很高兴听到有没有 .

1 回答

  • 1

    我发现这种方法要快得多 . 它还会输出一个列表,用于保留创建的时区:

    f_time <- function(x,y) as.POSIXct(x/1000, origin="1970-01-01", tz=y)
    s <- split(timesX200, tzonesX200)
    result <- mapply(f_time, s, names(s))
    

    您的输出不保留时区分配 . 检查你的输出:

    get.dates.with.timezones(times, tzones)
    [1] "2015-03-27 06:00:00 EDT" "2015-04-09 03:00:00 EDT"
    [3] "2014-12-15 08:53:48 EST" "2014-12-15 08:58:58 EST"
    [5] "2014-12-15 09:05:48 EST" "2014-12-15 09:07:30 EST"
    

    他们都被强制到当地时区 .

    benchmark test

    times <- c(1427450400291, 1428562800616, 1418651628795, 1418651938990, 1418652348281, 1418652450161)
    tzones <- c("America/Los_Angeles", "Africa/Casablanca", "Africa/Casablanca", "Africa/Casablanca", "Africa/Casablanca", "Israel")
    
    timesX200 <- rep(times,200)
    tzonesX200 <- rep(tzones,200)
    
    
    get.dates.with.timezones <- function(epoch.vec,tz.vec) {  
        res <- lapply(seq(epoch.vec),function(x){
               as.POSIXct(epoch.vec[x]/1000,origin = "1970-01-01", tz = tz.vec[x])
            })
            return(do.call(c,res))
    }
    
    library(microbenchmark)
    microbenchmark(
      get = get.dates.with.timezones(timesX200, tzonesX200),
      plafort = {s <- split(timesX200, tzonesX200);mapply(f_time, s, names(s))},
      times=20L)
    # Unit: microseconds
    #     expr        min         lq       mean     median         uq
    #      get 342693.638 362465.069 378195.687 372553.491 389080.277
    #  plafort    997.138   1027.731   1110.846   1107.471   1149.314
    #         max neval cld
    #  445539.744    20   b
    #    1558.473    20  a
    

相关问题