我有一些角色向量,其中包含各种格式的日期,例如
dates <- c("23/11/12", "20/10/2012", "22/10/2012" ,"23/11/12")
我想将这些转换为日期。我从lubridate包中尝试过非常好的dmy,但这不起作用:
dmy(dates)
[1] "0012-11-23 UTC" "2012-10-20 UTC" "2012-10-22 UTC" "0012-11-23 UTC"
它将/ 12年视为0012。
所以我现在尝试使用正则表达式来选择每种类型,并使用as.Date()单独转换为日期。但是我试图选择dd / mm / yy的正则表达式不起作用。
dates[grep('[0-9]{2}/[0-9]{2}/[0-9]{2,2}', dates)]
返回
[1] "23/11/12" "20/10/2012" "22/10/2012" "23/11/12"
我认为{2,2}应该得到正好2个数字,而不是所有数字。我不太擅长正则表达,所以任何帮助都会受到赞赏。
由于
修改
我实际拥有的是三种不同类型的日期,如下所示
dates <- c("23-Jul-2013", "23/11/12", "20/10/2012", "22/10/2012" ,"23/11/12")
我想将这些转换为日期
parse_date_time(dates,c('dmy'))
给了我
[1] "2013-07-23" "0012-11-23" "2012-10-20" "2012-10-22" "0012-11-23"
然而,这是错误的,0012应该是2012年。我想(一个相当简单的)解决方案。
我现在拥有的一个解决方案(感谢@plannapus)是使用正则表达式 我实际上最终创建了这个函数,因为我仍然得到一些案例,其中rubridate方法将12转变为0012
asDateRegex <- function(dates,
#selects strings from the vector dates using regexes and converts these to Dates
regexes = c('[0-9]{2}/[0-9]{2}/[0-9]{4}', #dd/mm/yyyy
'[0-9]{2}/[0-9]{2}/[0-9]{2}$', #dd/mm/yy
'[0-9]{2}-[[:alpha:]]{3}-[0-9]{4}'), #dd-mon-yyyy
orders = 'dmy',
...){
require(lubridate)
new_dates <- as.Date(rep(NA, length(dates)))
for(reg in regexes){
new_dates[grep(reg, dates)] <- as.Date(parse_date_time(dates[grep(reg, dates)], order = orders))
}
new_dates
}
asDateRegex (dates)
[1] "2012-10-20" "2013-07-23" "2012-11-23" "2012-10-22" "2012-11-23"
但这不是很优雅。有更好的解决方案吗?
答案 0 :(得分:14)
您可以使用parse_date_time
中的lubridate
:
some.dates <- c("23/11/12", "20/10/2012", "22/10/2012" ,"23/11/12")
parse_date_time(some.dates,c('dmy'))
[1] "2012-11-23 UTC" "2012-10-20 UTC" "2012-10-22 UTC" "2012-11-23 UTC"
但是,请注意格式的顺序很重要:
some.dates <- c("20/10/2012","23/11/12", "22/10/2012" ,"23/11/12")
parse_date_time(some.dates,c('dmY','dmy'))
[1] "2012-10-20 UTC" "2012-11-23 UTC" "2012-10-22 UTC" "2012-11-23 UTC"
编辑
内部parse_date_time
正在使用guess_formats
(我猜这会使用一些正则表达式):
guess_formats(some.dates,c('dmy'))
dmy dmy dmy dmy
"%d/%m/%Y" "%d/%m/%y" "%d/%m/%Y" "%d/%m/%y"
如评论中所述,您可以使用parse_date_time
,如下所示:
as.Date(dates, format = guess_formats(dates,c('dmy')))
答案 1 :(得分:7)
您可以根据输入的日期长度选择格式。
y <- ifelse(nchar(dates) == 8, "y", "Y")
as.Date(dates, format = paste0("%d/%m/%", y))
答案 2 :(得分:1)
您可以使用strsplit
和nchar
来获取年份为两个字符的日期的子向量:
> dates[sapply(strsplit(dates,"/"),function(x)nchar(x)[3]==2)]
[1] "23/11/12" "23/11/12"
答案 3 :(得分:1)
根据基于regex
的解决方案的原始尝试后,您可以使用此gsub
尝试regexp
,然后转换为您希望的任何日期时间格式...
# Replace 4 digit years with two digit years
short <- gsub( "([0-9]{2})([0-9]{2})$" , "\\2" , dates )
#[1] "23/11/12" "20/10/12" "22/10/12" "23/11/12"
as.Date( short , format = "%d/%m/%y" )
#[1] "2012-11-23" "2012-10-20" "2012-10-22" "2012-11-23"
答案 4 :(得分:1)
如果您真的想在regexp中执行此操作,则应该使用$
来表示在最后两位数字后面没有任何内容(即字符串结尾):
dates[grep('[0-9]{2}/[0-9]{2}/[0-9]{2}$', dates)]
[1] "23/11/12" "23/11/12"
答案 5 :(得分:1)
这里是一个基本的R方式,用于未通过的答案中尚未解决的更一般情况。
dates <- c("23-Jul-2013", "23/11/12", "20/10/2012", "22/10/2012" ,"23/11/12")
fmts <- list('%d-%b-%Y', '%d/%m/%y', '%d/%m/%Y')
d <- mapply(as.Date, list(dates), fmts, SIMPLIFY=FALSE)
max.d <- do.call(function(...) pmax(..., na.rm=TRUE), d)
min.d <- do.call(function(...) pmin(..., na.rm=TRUE), d)
max.d[max.d > Sys.Date()] <- min.d[max.d > Sys.Date()]
max.d
# [1] "2012-11-23" "2012-10-20" "2012-10-22" "2012-11-23"