是否有可靠的方法来检测表示由于夏令时不存在的时间的POSIXlt对象?

时间:2016-09-16 08:03:29

标签: r datetime dst

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

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

由于日期时间类的属性,这并非易事。

# 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

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

  

isdst
  夏令时标志。如果有效则为正数,否则为零,   如果不知道就会消极。

正在检查isdst字段保存,因为dst-changes导致日期无效,或者-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"

2 个答案:

答案 0 :(得分:1)

手册说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点到2点BST前进)并且不明确(时钟在BST 2:00返回到格林尼治标准时间1点)。在这种情况下发生的事情是特定于操作系统的:一个应该预期第一个是'NA',但第二个可以被解释为BST或GMT(并且常见操作系统给出两个可能的值)。

答案 1 :(得分: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对象的任何其他奇怪行为。