【问题标题】:Is there a reliable way to detect POSIXlt objects representing a time which does not exist due to DST?是否有可靠的方法来检测代表由于 DST 不存在的时间的 POSIXlt 对象?
【发布时间】:2017-01-24 09:21:36
【问题描述】:

我有以下问题:我得到的数据中的日期列包含由于夏令时不存在的日期。 (例如 2015-03-29 02:00 在欧洲中部时间不存在,因为 DST 在这一天生效,时钟直接从 01:59 设置到 03:00)

是否有一种简单可靠的方法来确定日期是否对夏令时有效?

由于日期时间类的属性,这不是微不足道的。

# generating the invalid time as POSIXlt object
test <- strptime("2015-03-29 02:00", format="%Y-%m-%d %H:%M", tz="CET")

# the object seems to represent something at least partially reasonable, notice the missing timezone specification though
test
# [1] "2015-03-29 02:00:00"

# strangely enough this object is regarded as NA by is.na
is.na(test)
# [1] TRUE

# which is no surprise if you consider:
is.na.POSIXlt
# function (x) 
# is.na(as.POSIXct(x))

as.POSIXct(test)
# [1] NA

# inspecting the interior of my POSIXlt object:
unlist(test)
# sec    min   hour   mday    mon   year   wday   yday  isdst   zone gmtoff
# "0"    "0"    "2"   "29"    "2"  "115"    "0"   "87"   "-1"     ""     NA

所以我想到的最简单的方法是检查POSIXlt对象的isdst字段,POSIXt的帮助描述该字段如下:

isdst
夏令时标志。有效时为正,否则为零, 如果未知,则为负。

是否检查isdst 字段是否保存,因为如果日期由于 dst 更改而无效,则此字段仅是 -1,或者由于某些其他原因它可以是 -1

关于版本、平台和语言环境的信息

R.version
# _                           
# platform       x86_64-w64-mingw32          
# arch           x86_64                      
# os             mingw32                     
# system         x86_64, mingw32             
# status                                     
# major          3                           
# minor          3.1                         
# year           2016                        
# month          06                          
# day            21                          
# svn rev        70800                       
# language       R                           
# version.string R version 3.3.1 (2016-06-21)
# nickname       Bug in Your Hair            
Sys.getlocale()
# [1] "LC_COLLATE=German_Austria.1252;LC_CTYPE=German_Austria.1252;LC_MONETARY=German_Austria.1252;LC_NUMERIC=C;LC_TIME=English_United States.1252"

【问题讨论】:

  • 我无法重现您的示例。当我执行您的代码时,我没有得到is.na(test) FALSE,而是TRUE,并且在执行test 时我得到了时区CEST。两种可能:(1) Sys.getlocale(),(2) 你用的是什么 R 版本?
  • is.na(test) 应该是 TRUE 我正在使用 Sys.getlocale("LC_TIME") "German_Austria.1252" 但如果我使用 Sys.setlocale("LC_TIME", "german") 以及 Sys.setlocale("LC_TIME", "english") strptime 中的时区设置,示例结果相同应该注意选择正确的时区。 R版本是:R版本3.3.1(2016-06-21)运行在:x86_64-w64-mingw32(64位Windows 7)
  • 猜猜它取决于操作系统,我也无法重现您的示例。如果您尝试as.POSIXct(test) 会发生什么?我在 Linux 上,我注意到 POSIXlt 对象有时代表无效时间,而 POSIXct 不代表。如果我尝试as.POSIXct(test) 我得到2015-03-29 01:00:00 CET,即日期时间已更正。也许您可以尝试identical(as.POSIXlt(as.POSIXct(test)),test) 获得您的支票。
  • 对不起我的第一篇文章。我有is.na(test) FALSE,而不是你的例子中的TRUE。顺便说一句:有一个名为anytime 的新包,它可以转换“任何”时间格式。你可以试试这个(下载后),对我来说它有效:anytime::anytime(test)[1] "2015-03-29 01:00:00 CET"
  • 例如NaNs 也可以有不同的位表示,NaN 的帮助文件说不要在它们上使用identical

标签: r datetime dst


【解决方案1】:

as.POSIXct(test) 的值似乎与平台相关,为获得可靠 方法增加了一层复杂性。在我的 Windows 机器(R 3.3.1)上,as.POSIXct(test) 产生 NA,正如 OP 所报告的那样。但是,在我的 Linux 平台(相同的 R 版本)上,我得到以下信息:

times = c ("2015-03-29 01:00",
           "2015-03-29 02:00",
           "2015-03-29 03:00")

test <- strptime(times, format="%Y-%m-%d %H:%M", tz="CET")

test
#[1] "2015-03-29 01:00:00 CET"  "2015-03-29 02:00:00 CEST" "2015-03-29 03:00:00 CEST"
as.POSIXct(test)
#[1] "2015-03-29 01:00:00 CET"  "2015-03-29 01:00:00 CET"  "2015-03-29 03:00:00 CEST"
as.character(test)
#[1] "2015-03-29 01:00:00" "2015-03-29 02:00:00" "2015-03-29 03:00:00"
as.character(as.POSIXct(test))
#[1] "2015-03-29 01:00:00" "2015-03-29 01:00:00" "2015-03-29 03:00:00"

我们可以依赖的一件事不是as.POSIXct(test) 的实际值,而是当test 是无效的日期/时间时,它将与test 不同:

(as.character(test) == as.character(as.POSIXct(test))) %in% TRUE
# TRUE FALSE  TRUE

我不确定as.character 在这里是否绝对必要,但我将其包括在内只是为了确保我们不会违反 POSIX 对象的任何其他奇怪行为。

【讨论】:

  • 我认为您从test 复制了两次输出,而不是从as.POSIXct(test) 粘贴输出,最后一次检查也给了我# TRUE NA TRUE。但是(as.character(test) == as.character(as.POSIXct(test))) %in% TRUE 对我有用。不是一个漂亮的解决方案,但它有效。谢谢。
  • 感谢@snaut,很好。我确实粘贴了正确的输出,但as.POSIXct 的行为显然取决于平台。我已经相应地更新了答案
【解决方案2】:

手册说strptime 不验证时间是否存在于特定时区,因为转换到/从夏令时 (?strptime)。手册还说as.POSIXct 进行了此验证,因此按照手册,应该检查生成的 POSIXct 对象的 NA (?asPOSIXct),这将识别不存在的时间,如问题示例中所示。然而,对于在一个时区中存在两次的时间,结果是特定于操作系统的 (?asPOSIXct):

请记住,在大多数时区,有些时间不会出现,有些时间会出现两次,因为转换到/从“夏令时”(也称为“夏季”)时间。 strptime 不验证此类时间(它不假定特定时区),但 as.POSIXct 的转换会这样做。

一个问题是在 DST 的转换过程中会发生什么,例如在英国

as.POSIXct(strptime("2011-03-27 01:30:00", "%Y-%m-%d %H:%M:%S")) as.POSIXct(strptime("2010-10-31 01:30:00", "%Y-%m-%d %H:%M:%S"))

分别是无效的(时钟在格林威治标准时间 1:00 前进到英国夏令时 2:00)和不明确(时钟在格林威治标准时间 2:00 回到格林威治标准时间 1:00)。在这种情况下会发生什么是特定于操作系统的:人们应该期望第一个是“NA”,但第二个可能被解释为 BST 或 GMT(常见的操作系统会给出这两个可能的值)。

【讨论】:

  • 另外,很少有理由使用POSIXlt。 POSIXct 通常更可取。
  • 对不起,这并不能回答我的问题,而是再次说明问题。我需要可靠地检测从 csv 解析的一系列日期中不存在的日期,并且我需要将它们与源自空字符串等的其他 NA 值区分开来。直接解析为 POSIXct 是不可能的,至少不能使用标准库.
猜你喜欢
  • 1970-01-01
  • 2022-09-23
  • 2015-10-12
  • 1970-01-01
  • 2015-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-01
相关资源
最近更新 更多