【问题标题】:Europe/Moscow time zone issue with strptimestrptime 的欧洲/莫斯科时区问题
【发布时间】:2014-05-14 12:50:54
【问题描述】:

我正在开发一个执行一些时间序列操作的软件。我最近在我开发的 R 脚本方面发现了一个严重的问题;在具有Europe/Moscow 语言环境的特定机器上隔离了意外行为。问题归结为以下 sn-p:

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') 强制所有时区为格林威治标准时间;问题就这样消失了。

这是一个好习惯吗?代码在所有情况下都可靠吗?您会推荐哪些技术来避免类似问题?

1984 年 4 月 1 日发生了什么事?

编辑thisthis 问题表明这可能是导致问题的夏令时。

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

【问题讨论】:

  • Daylight Saving Time started in 1984 in Russia 的确切日期是 4 月 1 日...
  • 在这种情况下,为什么不使用as.Date
  • 另外:您使用的是哪个 R / OS 版本?对我来说,在带有 R 2.14.2 的 Mac OS X 10.7.5 上,我得到了as.numeric(d) [1] 444430800 446936400 449611200 452203200 454881600
  • @plannapus 谢谢,cmets 非常有帮助。您想发布这些作为答案吗?添加了 SessionInfo()。

标签: r timezone strptime


【解决方案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)。

话虽如此,在运行 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 转换时返回不存在时间的无意义结果。

【讨论】:

  • 可能与this bug有关?考虑到您的 R 3.1.0 (2014-04-10) 的时间戳,这并非不可能:此错误已在 2014 年 4 月 24 日通过补丁修复(请参阅CHANGES IN R 3.1.0 patched)。如果您使用该修补版本,问题是否仍然可以重现?
  • 检查了补丁版本,还是一样。
  • 感谢您的努力!这确实是一个与平台相关的问题,请参阅我的最新编辑。
猜你喜欢
  • 1970-01-01
  • 2021-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多