将日期时间字符串转换为日期类Date

58

我有一个包含日期时间字符列的数据框。

当我使用as.Date函数时,大部分字符串都能被正确解析,但是有少数几个实例无法解析。下面的示例将希望向您展示发生了什么。

# my attempt to parse the string to Date -- uses the stringr package
prods.all$Date2 <- as.Date(str_sub(prods.all$Date, 1, 
                str_locate(prods.all$Date, " ")[1]-1), 
                "%m/%d/%Y")

# grab two rows to highlight my issue
temp <- prods.all[c(1925:1926), c(1,8)]
temp
#                    Date      Date2
# 1925  10/9/2009 0:00:00 2009-10-09
# 1926 10/15/2009 0:00:00 0200-10-15

正如您所看到的,一些日期的年份是不准确的。这种情况似乎发生在日期为两位数的日子。

如果您能提供任何帮助,将不胜感激。


你之所以得到无效的0200日期是因为日期中天数的字符长度不同(15-Oct为两位数字,而9-Oct为一位数字)- 而你的字符串替换代码没有考虑到这一点。无论如何,你可能可以直接使用as.Date或strptime函数,并使用格式参数,而不需要进一步处理字符。 - mdsumner
4个回答

91
最简单的方法是使用lubridate库:
library(lubridate)
prods.all$Date2 <- mdy(prods.all$Date2)

这个函数会自动返回POSIXct类的对象,并且可以处理因子或字符类型的数据。


11
我会提到该库中诸如ymd()、ymd_hms()、myd_hms()等用于处理日期和时间字段的函数。顺便说一句,这个库很棒。我向你致敬。 - Mike Wise
4
lubridate是一个很棒的软件包。我仍在2018年使用它,并且无法满足。在https://github.com/rstudio/cheatsheets/raw/master/lubridate.pdf上有一个“lubridate”备忘单。 - Lobbie
1
@hadley 当我成为国王时,你将被封为骑士。 - shekeine

79

你可能过于复杂化了,有没有必要使用stringr包?您可以使用as.Date和它的format参数来指定字符串的输入格式。

 df <- data.frame(Date = c("10/9/2009 0:00:00", "10/15/2009 0:00:00"))
 as.Date(df$Date, format =  "%m/%d/%Y %H:%M:%S")
 # [1] "2009-10-09" "2009-10-15"

请注意?as.Date中的详细信息部分:

字符字符串将根据指定的格式进行处理:任何尾随字符都将被忽略。

因此,以下代码也可以正常工作:

as.Date(df$Date, format =  "%m/%d/%Y")
# [1] "2009-10-09" "2009-10-15"

可以用来指定输入格式的所有转换规范都在?strptime详细信息部分中找到。确保转换规范的顺序以及任何分隔符与您的输入字符串的格式完全相对应。


更普遍地,如果您还需要时间组件,请使用as.POSIXctstrptime

as.POSIXct(df$Date, "%m/%d/%Y %H:%M:%S")    
strptime(df$Date, "%m/%d/%Y %H:%M:%S")

根据你提供的部分结果,我猜测你实际的数据可能是什么样子。


1
我建议不要使用 strptime,因为它返回一个 POSIXlt 对象,这经常会让新用户感到困惑,因为他们没有意识到它是一个列表。如果你需要时间,请使用 as.POSIXct,但需要注意的是,如果你的“日期”实际上是因子,就要小心了... - Joshua Ulrich
1
自从 R 2.11.0 版本以来,“length(<POSIXlt>)”现在返回相应的抽象时间日期向量的长度,而不总是9(底层列表结构的长度)。 (PR#14073和PR#10507的愿望。)所以我想知道是否值得让事情变得复杂。无论如何你都可以使用 as.POSIXct(strptime(x))。 - mdsumner
我没有意识到这点。谢谢指出。虽然我想知道,如果你在 data.frame 中有一个 POSIXlt 列,它是否仍然会令人困惑... - Joshua Ulrich
我意识到后来它并不完全有用 - 在一个 data.frame 中,你仍然会遇到麻烦,尽管我认为可以将列表和数组等放入 data.frame 作为列。但我认为更好的方法是理解 lt/ct 的区别并小心使用它们。 - mdsumner
1
这对我来说似乎是误导性的,因为as.Date返回的Date类实际上并不处理时间。答案暗示它可以处理时间。 - Mike Wise

1
如果您不知道格式,可以使用anytime::anydate,它会尝试匹配常见的格式。
library(anytime)

date <- c("01/01/2000 0:00:00", "Jan 1, 2000 0:00:00", "2000-Jan-01 0:00:00")

anydate(date)
[1] "2000-01-01" "2000-01-01" "2000-01-01"

0

library(lubridate) 如果你的日期格式是这样的 '04/24/2017 05:35:00',那么请按照以下方式更改 prods.all$Date2<-gsub("/","-",prods.all$Date2) 然后更改日期格式 parse_date_time(prods.all$Date2, orders="mdy hms")


不需要将斜杠改为破折号,parse_date_time 可以解析任何一种方式。 - camille

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接