【问题标题】:Guard against accidental time-zone conversion防止意外时区转换
【发布时间】:2011-10-05 18:03:02
【问题描述】:

在 R 中,我有一堆我在 GMT 中测量的日期时间值。我经常遇到一些函数或其他函数丢失我的值的时区,甚至丢失类名的事故。即使是像c()unlist() 这样基本的功能:

> dput(x)
structure(1317830532, class = c("POSIXct", "POSIXt"), tzone = "GMT")
> dput(c(x))
structure(1317830532, class = c("POSIXct", "POSIXt"))
> dput(list(x))
list(structure(1317830532, class = c("POSIXct", "POSIXt"), tzone = "GMT"))
> dput(unlist(list(x)))
1317830532

如果这发生在我最不期待的时候,我觉得我距离拥有真正的Mars Climate Orbiter 时刻仅一步之遥。任何人都有任何策略来确保他们的约会“保持不变”?

【问题讨论】:

标签: r timezone date


【解决方案1】:

此行为记录在?c?DateTimeClasses?unlist

来自?DateTimeClasses

在“POSIXlt”对象上使用c会将它们转换为当前时区,而在“POSIXct”对象上使用任何“tzone”属性(即使它们都标记为相同的时区) ).*

来自?c

c 有时用于删除除名称之外的属性的副作用。*


也就是说,我的测试表明,尽管使用了cunlist,您的数据的完整性仍然完好无损。例如:

x <- structure(1317830532, class = c("POSIXct", "POSIXt"), 
                 tzone = "GMT")
y <- structure(1317830532+3600, class = c("POSIXct", "POSIXt"), 
                 tzone = "PST8PDT")
x
[1] "2011-10-05 16:02:12 GMT"

y
[1] "2011-10-05 10:02:12 PDT"

strftime(c(x, y), format="%Y/%m/%d %H:%M:%S", tz="GMT")
[1] "2011/10/05 16:02:12" "2011/10/05 17:02:12"

strftime(c(x, y), format="%Y/%m/%d %H:%M:%S", tz="PST8PDT")
[1] "2011/10/05 09:02:12" "2011/10/05 10:02:12"

strftime(unlist(y), format="%Y/%m/%d %H:%M:%S", tz="PST8PDT")
[1] "2011/10/05 10:02:12"

如果您使用 R 来跟踪日期,您的火星探测器应该没问题。

【讨论】:

  • 我认为我的漫游车实际上处于危险之中 - 因为我正在查看事件发生的时间(例如,通过 x-floor_date(x,'day')),以及时区是否被默默删除,这些数字最终是错误的。
  • 再一个例子:strftime(unlist(list(y)), format="%Y/%m/%d %H:%M:%S", tz="PST8PDT") as.POSIXlt.numeric(x, tz = tz) 中的错误:必须提供'origin'
  • 简而言之,我确实理解这是记录在案的行为,我只是认为它极易出错并且不太可能真正有帮助。如果我想转换为当地时间,我不会只打电话给c(),无论如何我会让我的代码更明确。
  • @KenWilliams 我的理解不是c 将时间转换为当地时间。是的,它去掉了原来的tz,但实际时间保持不变。发生的情况是,在您以后的计算中会隐式转换为本地时间。如果您以后想知道当地时间是什么并且您不再有 tz 的记录,我可以看到这将如何导致簿记问题。很抱歉,我想不出一个简单的解决方法。
  • 对 - 更准确地说,c 删除了任何时区属性,然后,其他各种功能将根据我的环境选择默认时区。相对于 GMT 的时刻保持不变,但一天中的时间会发生变化。
【解决方案2】:

那么,为什么不将 R 会话的时区设置为 GMT?如果某些东西被转换为“当前”时区,它仍然是正确的。

【讨论】:

  • 是的,我正在考虑这样做。但我并不是只处理来自一个时区的数据,而且我不喜欢我的环境对我的数据进行的这种“远距离操作”。
  • 您可以在 R 中使用Sys.setenv(TZ="GMT")在相关会话(脚本)中设置它
【解决方案3】:

鉴于这是记录在案的行为,并且应该避免此类功能或围绕此类行为进行防御性编码,那么您需要支持任一方法的机制。对于这样的事情,我建议写一个“穷人的皮棉”;有了这样的棉绒检测器,您可以恢复理智此外,对于棉绒检测,有几种方法可以避免火星 Polar Orbiter 坠毁,有些是相互独立的,有些是相互依赖的:

  1. 制定政策并构建替代方案首先,对于您知道会导致问题的所有函数,要么决定不使用它们,要么编写一个新的包装函数,使其行为符合预期,这将设置您想要的时区参数。然后,确保使用该特殊包装器而不是底层函数。
  2. 静态分析 使用您喜欢的编辑器(例如,作为宏)、使用 shell 脚本和 GNU findgrep 函数,或以其他方式(例如 grep在 R) 中,找到那些导致您出现问题的特定功能。找到后,删除或使用防御性编码方法(例如 #1 中的包装器)。
  3. 测试 使用单元测试,例如Runittestthat,开发测试以确保在使用您的函数或包时维护时区属性。每次出现新错误时,创建一个新测试以确保该错误不会再次出现在已发布的版本中。
  4. 弱类型检查 您还可以在整个代码中包含测试是否指定了时区。最好有你自己的函数来进行这个测试,而不是编写一个在整个过程中复制的代码块。通过这种方式,您最终可以扩展检查以包括其他类型的检查,例如时区的持久性和测试两个或多个对象上的操作是否注意时区的差异(也许他们允许,也许他们不)。
  5. 将所有内容映射到一个 TZ 也称为 Indiana-be-damned。保留有关时区的各种策略是一项艰巨的工作,并且在处理时态数据时本质上是摩擦。只需映射到一个 TZ (UTC),然后让任何本地工作都可以。如果您碰巧具有不受 DST 影响的局部规律性,请在从 UTC 转换回来后解决该问题。

我为其他问题做了所有#s 1-4,但是,就像它们很容易适应时区检查一样,它们对于许多火星轨道飞行器避免目标来说是相当可重用的。我这样做正是为了避免编写下一个这样的火星轨道飞行器。 (对于我们所有使用数字数据的人来说,这是一个昂贵的教训。:))

【讨论】:

    猜你喜欢
    • 2014-07-04
    • 2016-06-20
    • 2010-09-20
    • 2015-12-17
    • 2018-04-08
    • 2020-05-08
    • 2010-09-08
    相关资源
    最近更新 更多