当有多种日期格式时,如何将字符类日期变量更改为POSIXlt类?

时间:2016-05-04 05:19:47

标签: r date datetime lubridate

我正在努力转换许多不同格式类型的字符类日期(例如,yyyy / mm / dd; mm / dd / yyyy; yyyy-mm-dd; mm-dd-yyyy; yy-mm-dd; mm-dd-yy;等)到POSIXlt类。理想情况下,我想将所有birth_dates转换为具有yyyy / mm / dd格式的POSIXlt类(请参阅下面的示例数据)。在R?中有没有简单的方法呢?

   id  birth_date  start_date  age
  102   08/09/1993  2013/09/01 20
  103   1995-02-21  2013/09/01 18
  104   01-15-94    2013/09/01 19
  105   88-12-30    2013/09/01 24

这是我到目前为止所做的事情。不幸的是,考虑到原始日期格式化的所有不同方式,这似乎不起作用(我结束了比应有的更多的NAs):

  library(lubridate)
  data$birth_date1<-as.Date(data$birth_date,format="%Y-%m-%d") #Convert character class to date class
  data$birth_date2<-ymd(swc3$birth_date1) #Convert date class to POSIXlt class using lubridate pkg

1 个答案:

答案 0 :(得分:1)

那太可怕了。可能会更糟糕。至少在那里有分隔符,如“ - ”和“/".

简答

是的,有一种简单的方法可以在R中解析它。将parse_date_time()分别应用于每个出生日期,给它一个合适的orders列表供选择,并仔细设置猜测的顺序。完成后,您需要将“整数时间”转换为有用的时间。

有关详细信息,请参阅完整答案。

长答案

这就是lubridate包有parse_date_time()的原因。但是有问题。我们来看看:

require(lubridate)
# WRONG! doesn't work as intended.
as.Date(
    parse_date_time(data$birth_date, 
                    orders=c("ymd", "mdy", "mdY", "Ymd")
    )
)  
 [1] "1993-08-09" "1995-02-21" "1994-01-15" "0088-12-30"

除了最后一个,这看起来很棒。发生了什么事?

parse_date_time()正在选择在解析日期时使用的“最适合”的订单和格式集,最后一个元素是奇数的。

为了使这项工作按预期进行,您需要逐个应用parse_date_time()到每个日期,因为每个日期格式显然是随机选择或多或少。这会慢一些,但会提供更多有用的答案。

# RIGHT. Some conversion of results required.
parsed <- sapply(data[,"birth_date"],
                 parse_date_time,
                 orders=c("ymd", "mdy", "mdY", "Ymd") )
parsed
08/09/1993 1995-02-21   01-15-94   88-12-30 
744854400  793324800  758592000  599443200 

好的,那些看起来像Unix时间整数,它是unclass()生成的parse_date_time()'版本。没有一个是消极的,所以它们必须在1970年之后发生。这是令人鼓舞的。转换:

# Conversion of results
parsed <- as.POSIXct(parsed, origin="1970-01-01", tz = "GMT")
as.Date(parsed)
08/09/1993   1995-02-21     01-15-94     88-12-30 
"1993-08-09" "1995-02-21" "1994-01-15" "1988-12-30" 

lubridateparse_date_time()非常擅长他们的工作。

由于您要求POSIXlt,而不是日期类型:

as.POSIXlt(parsed)
                08/09/1993                 1995-02-21 
"1993-08-09 10:00:00 AEST" "1995-02-21 11:00:00 AEDT" 
                 01-15-94                   88-12-30 
"1994-01-15 11:00:00 AEDT" "1988-12-30 11:00:00 AEDT" 

虽然我个人更喜欢只有实际时间不重要的日期;假设这些都发生在UTC的午夜,并转换为我的时区(澳大利亚东部)。