如何正确转换时区

sta*_*ant 2 r posixct

我正在使用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了点)

Ric*_*ton 9

这里聪明的做法几乎肯定是编写可读,易于维护的代码,如果你的代码太慢,就会抛出更多的硬件.

如果您急需代码加速,那么您可以编写自定义时区调整功能.它不漂亮,所以如果你必须在很多时区之间进行转换,你最终会得到意大利面条代码.这是我从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天的代码维护时间(嘘!).