我正在使用fasttime包来实现其fastPOSIXct功能,可以非常有效地读取字符日期时间.我的问题是它只能读取GMT中表达的字符日期时间.
R) fastPOSIXct("2010-03-15 12:37:17.223",tz="GMT") #very fast
[1] "2010-03-15 12:31:16.223 GMT"
R) as.POSIXct("2010-03-15 12:37:17.223",tz="GMT") #very slow
[1] "2010-03-15 12:31:16.223 GMT"
Run Code Online (Sandbox Code Playgroud)
现在,假设我有一个日期时间以"America/Montral"时区表示的文件,计划是加载它们(隐含地假装它们在GMT中)并随后修改时区属性而不更改基础值.
如果我使用这个功能,请参考另一篇文章:
forceTZ = function(x,tz){
return(as.POSIXct(as.numeric(x), origin=as.POSIXct("1970-01-01",tz=tz), tz=tz))
}
Run Code Online (Sandbox Code Playgroud)
我看到一个bug ...
R) forceTZ(as.POSIXct("2010-03-15 12:37:17.223",tz="GMT"),"America/Montreal")
[1] "2010-03-15 13:37:17.223 EDT"
Run Code Online (Sandbox Code Playgroud)
...因为我希望它是
R) as.POSIXct("2010-03-15 12:37:17.223",format="%Y-%m-%d %H:%M:%OS",tz="America/Montreal")
[1] "2010-03-15 12:37:17.223 EDT"
Run Code Online (Sandbox Code Playgroud)
有解决方法吗?
编辑:我知道lubridate::force_tz但它太慢了(不再使用fasttime::fastPOSIXct了点)
这里聪明的做法几乎肯定是编写可读,易于维护的代码,如果你的代码太慢,就会抛出更多的硬件.
如果您急需代码加速,那么您可以编写自定义时区调整功能.它不漂亮,所以如果你必须在很多时区之间进行转换,你最终会得到意大利面条代码.这是我从GMT转换到蒙特利尔时间的具体案例的解决方案.
首先预先计算夏令时的日期列表.为了适合您的数据集,您需要将其扩展到2010年之前/ 2013年之后.我在这里找到了约会
http://www.timeanddate.com/worldclock/timezone.html?n=165
montreal_tz_data <- cbind(
start = fastPOSIXct(
c("2010-03-14 07:00:00", "2011-03-13 07:00:00", "2012-03-11 07:00:00", "2013-03-10 07:00:00")
),
end = fastPOSIXct(
c("2010-11-07 06:00:00", "2011-11-06 06:00:00", "2012-11-04 06:00:00", "2013-11-03 06:00:00")
)
)
Run Code Online (Sandbox Code Playgroud)
对于速度,更改时区的功能将时间视为数字.
to_montreal_tz <- function(x)
{
x <- as.numeric(x)
is_dst <- logical(length(x)) #initialise as FALSE
#Loop over DST periods in each year
for(row in seq_len(nrow(montreal_tz_data)))
{
is_dst[x > montreal_tz_data[row, 1] & x < montreal_tz_data[row, 2]] <- TRUE
}
#Hard-coded numbers are 4/5 hours in seconds
ans <- ifelse(is_dst, x + 14400, x + 18000)
class(ans) <- c("POSIXct", "POSIXt")
ans
}
Run Code Online (Sandbox Code Playgroud)
现在,比较时间:
#A million dates
ch <- rep("2010-03-15 12:37:17.223", 1e6)
#The easy way (no conversion of time zones afterwards)
system.time(as.POSIXct(ch, tz="America/Montreal"))
# user system elapsed
# 28.96 0.05 29.00
#A slight performance gain by specifying the format
system.time(as.POSIXct(ch, format = "%Y-%m-%d %H:%M:%S", tz="America/Montreal"))
# user system elapsed
# 13.77 0.01 13.79
#Using the fast functions
library(fasttime)
system.time(to_montreal_tz(fastPOSIXct(ch)))
# user system elapsed
# 0.51 0.02 0.53
Run Code Online (Sandbox Code Playgroud)
与所有优化技巧一样,您可以获得27倍的加速(yay!)或者您节省了13秒的处理时间,但是当DST表在2035年耗尽时,从一个不起眼的错误中增加了3天的代码维护时间(嘘!).