我正在开发一个执行一些时间序列操作的软件。我最近发现了我开发的R脚本方面的一个严重问题;在具有Europe/Moscow
区域设置的特定计算机上隔离了意外行为。问题归结为以下代码段:
strange_days <- c("2/1/1984", "3/1/1984", "4/1/1984", "5/1/1984", "6/1/1984")
Sys.setenv(TZ='Europe/Moscow')
d <- strptime(strange_days, '%m/%d/%Y')
d
[1] "1984-02-01 MSK" "1984-03-01 MSK" "1984-04-01" "1984-05-01 MSD" "1984-06-01 MSD"
所有似乎都能正确识别。我认为既然这是日常数据,那么时区属性没有太大区别;痛苦的错误:
as.numeric(d)
[1] 444430800 446936400 NA 452203200 454881600
在转换为xts
对象时显然会失败。
目前的修正方法是通过strptime(strange_days, '%m/%d/%Y', tz='GMT')
甚至Sys.setenv(TZ='GMT')
强制所有时区为GMT;这个问题已经消失了。
这是一个好习惯吗?代码在所有情况下都是可靠的吗?您建议采用哪些技巧来避免类似的问题?
1984年4月1日发生了什么?
sessionInfo()
R version 3.1.0 (2014-04-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
locale:
[1] LC_COLLATE=English_United Kingdom.1252 LC_CTYPE=English_United Kingdom.1252 LC_MONETARY=English_United Kingdom.1252
[4] LC_NUMERIC=C LC_TIME=English_United Kingdom.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] tools_3.1.0
编辑2 :问题显然是特定于Windows的,不会在Linux上使用这些规范重现:
R version 3.1.0 (2014-04-10)
Platform: i686-pc-linux-gnu (32-bit)
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] tools_3.1.0
答案 0 :(得分:1)
在这种情况下,由于您对时间不感兴趣,但仅在您可以使用as.Date
的日期感兴趣:
> as.Date(strange_days,"%m/%d/%Y")
[1] "1984-02-01" "1984-03-01" "1984-04-01" "1984-05-01" "1984-06-01"
您面临的错误(正如您已经注意到的)最有可能是由于夏令时:1984年俄罗斯的DST专门于4月1日开始(source)。 / p>
话虽如此,在运行R 2.14.2的Mac OSX 10.7.5上(有点过时),此错误无法重现:
> strange_days <- c("2/1/1984", "3/1/1984", "4/1/1984", "5/1/1984", "6/1/1984")
> Sys.setenv(TZ='Europe/Moscow')
> d <- strptime(strange_days, '%m/%d/%Y')
> d
[1] "1984-02-01 MSK" "1984-03-01 MSK" "1984-04-01 MSD" "1984-05-01 MSD" "1984-06-01 MSD"
> as.numeric(d)
[1] 444430800 446936400 449611200 452203200 454881600
这表明R版本2.14.2和3.1.0之间对strptime
所做的更改之一修改了此行为。我目前正在改变日志中寻找它,但我还没有确切的证据。另一种可能性是它是特定于平台的。
此外,摘录自?strptime
:
请记住,在大多数时区中,某些时候不会发生,有些时候会发生 两次因为往返夏季的过渡。 strptime没有 验证这样的时间(它不假设特定的时区),但是 转换为as.POSIXct)将这样做。按strftime和。转换 格式化/打印使用操作系统设施,可能(并在Windows上) 在DST过渡时返回不存在时间的无意义结果。