我想将具有不同时区的多个时间值转换为POSIXct格式,当前表示为毫秒,从01-01-1970开始。
我有以下数据集:
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()
方法本身似乎有一些性能问题,如下所示。
---------- EDIT --------
显然,不可能在不同的时区保存POSIXct向量。来自POSIXct文档:
在"POSIXlt"对象上使用c将其转换为当前时区,并且在"POSIXct"对象上删除任何"tzone"属性(即使它们都标有相同的时区)。源
那太糟糕了。我想知道是否有任何替代方法来处理日期+时间+不同的时区。如果有的话我会很高兴听到的。
我发现这种方法要快得多。它还输出一个保留已创建时区的列表:
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"
它们都被强制为本地时区。
基准测试
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