我有一个POSIXct稍微误用该格式的向量:
> head(df$datetime)
[1] "2016-03-03 12:30:00 UTC" "2016-03-03 12:00:00 UTC" "2016-02-27 09:00:00 UTC" "2016-03-03 17:30:00 UTC"
[5] "2016-03-03 10:30:00 UTC" "2016-03-03 14:30:00 UTC"
Run Code Online (Sandbox Code Playgroud)
这些日期时间标记为UTC时间,但实际上是各种各样的本地时区:
> df %>% select(datetime, timezone) %>% head
datetime timezone
1 2016-03-03 12:30:00 Australia/Melbourne
2 2016-03-03 12:00:00 Europe/Berlin
3 2016-02-27 09:00:00 Europe/Amsterdam
4 2016-03-03 17:30:00 Australia/Brisbane
5 2016-03-03 10:30:00 Europe/Amsterdam
6 2016-03-03 14:30:00 Europe/Berlin
Run Code Online (Sandbox Code Playgroud)
我想将这些日期时间转换为适当的UTC - 从某种意义上说,这里和这里面临的逆问题- 但是我很难过.来自第二个链接的解决方案的变体工作:
get_utc_time <- function(timestamp_local, local_tz) {
l <- lapply(seq(length(timestamp_local)),
function(x) {with_tz(force_tz(timestamp_local[x], tzone=local_tz[x]), tzone='UTC')})
as.POSIXct(combine(l), origin = '1970-01-01 00:00.00', tz = 'UTC')
}
df$datetime_utc <- get_utc_time(df$datetime, df$timezone)
Run Code Online (Sandbox Code Playgroud)
(dplyr::mutate(df, datetime_utc = get_utc_time(datetime, timezone))我认为这是等价的,会引发错误.)
但由于这不是矢量化的,因此在具有50万行的data.frame上速度非常慢.有没有更优雅,更快的方式来做到这一点?
Dir*_*tel 10
我所知道的最"官方"方式涉及格式化和重新分析; 不久前,David Smith 在REvolutions博客上发表了一篇文章.
时间序列库,特别是那些具有时区感知能力的库,也可以做到.这是一种使用RcppCCTZ的方法,它是我的CCTZ包装器(由一些Googler编写但不是官方Google库) - 它计算两个时区之间的差异(默认以小时为单位).
library(RcppCCTZ) # you need the GitHub version though
# your data
df <- read.csv(text="datetime,timezone
2016-03-03 12:30:00,Australia/Melbourne
2016-03-03 12:00:00,Europe/Berlin
2016-02-27 09:00:00,Europe/Amsterdam
2016-03-03 17:30:00,Australia/Brisbane
2016-03-03 10:30:00,Europe/Amsterdam
2016-03-03 14:30:00,Europe/Berlin", stringsAsFactor=FALSE)
# parse to POSIXct
df[,"pt"] <- as.POSIXct(df[,"datetime"])
# compute difference
for (i in 1:6)
df[i,"diff"] <- tzDiff("UTC", df[i,"timezone"], df[i,"pt"])
Run Code Online (Sandbox Code Playgroud)
这让我们得到了这个data.frame:
R> df
datetime timezone pt diff
1 2016-03-03 12:30:00 Australia/Melbourne 2016-03-03 12:30:00 11
2 2016-03-03 12:00:00 Europe/Berlin 2016-03-03 12:00:00 1
3 2016-02-27 09:00:00 Europe/Amsterdam 2016-02-27 09:00:00 1
4 2016-03-03 17:30:00 Australia/Brisbane 2016-03-03 17:30:00 10
5 2016-03-03 10:30:00 Europe/Amsterdam 2016-03-03 10:30:00 1
6 2016-03-03 14:30:00 Europe/Berlin 2016-03-03 14:30:00 1
R>
Run Code Online (Sandbox Code Playgroud)
返回解析的Datetime偏移量也很简单,但是小辅助函数tzDiff当前没有这样做.如果你想走这条路,我可以把它作为第二个辅助函数添加...
编辑: 这是一个有趣的问题.我现在已经向RcppCCTZ添加了一些代码来执行此操作,但它(至少)没有矢量化.也就是说,我们可以使用data.table提供更简单,更快速的解决方案.
让我们首先对您的解决方案及其所需的三个包进行编码:
library(lubridate)
library(magrittr)
library(dplyr)
useLubridate <- function(df) {
df %>%
group_by(timezone) %>%
mutate(datetime_local = ymd_hms(datetime, tz=unique(timezone))) %>%
mutate(datetime_utc = with_tz(datetime_local, tzone = 'UTC')) %>%
ungroup %>%
select(datetime_local) -> df
df
}
Run Code Online (Sandbox Code Playgroud)
我们对data.table做同样的事情:
library(data.table)
useDataTable <- function(df) {
dt <- as.data.table(df)
dt[, pt := as.POSIXct(datetime, tz=timezone[1]), by=timezone]
dt[]
}
Run Code Online (Sandbox Code Playgroud)
请注意,这将返回三列而不是一列.
当我们在这里时,让我们做一场赛马:
R> library(microbenchmark)
R> microbenchmark( useDataTable(df), useLubridate(df) )
Unit: milliseconds
expr min lq mean median uq max neval cld
useDataTable(df) 1.23148 1.53900 1.61174 1.57635 1.64734 3.85423 100 a
useLubridate(df) 7.51158 8.88734 9.10439 9.19390 9.38032 15.27572 100 b
R>
Run Code Online (Sandbox Code Playgroud)
因此data.table更快,同时还返回更多有用的信息.将第三列整理回data.frame(或相似)将花费更多时间.