【问题标题】:Convert dd/mm/yy and dd/mm/yyyy to Dates将 dd/mm/yy 和 dd/mm/yyyy 转换为日期
【发布时间】:2013-10-25 20:13:45
【问题描述】:

我有一些像这样的各种格式日期的字符向量

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)是使用正则表达式 实际上我最终创建了这个函数,因为我仍然遇到了一些 lubridate 方法将 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"

但这不是很优雅。有更好的解决方案吗?

【问题讨论】:

标签: regex r lubridate


【解决方案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"

【讨论】:

    【解决方案2】:

    你可以从lubridate使用parse_date_time:

    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 我需要花更多时间在 lubridate 上
    • 只是出于兴趣,您使用的是什么版本的 lubridate?在 lubridate 1.3.0 ,R 2.15.2 (是的,过时,我知道)下,Win 7,当我复制并粘贴您的 parse_date_time 代码时,我仍然得到 0012 年。
    • 还要注意parse_date_time返回一个POSIXlt向量,而不是Date,(dmy返回POSIXct)。
    • 我在my last question中描述了类似的现象。它也作为一个问题发布在lubridate github。
    • as.Date(dates, format = guess_formats(dates,c('dmy'))) 为我工作。我不确定为什么这有效,而不是parse_date_time。 @agstudy 如果您将其添加到您的答案中,我会将其标记为已回答的问题(我不太确定这里的正确礼仪......)
    【解决方案3】:

    您可以根据输入的日期长度选择格式。

    y <- ifelse(nchar(dates) == 8, "y", "Y")
    as.Date(dates, format = paste0("%d/%m/%", y))
    

    【讨论】:

      【解决方案4】:

      如果你真的想在正则表达式中这样做,你应该使用$ 来表示在最后两位数字之后没有任何内容(即字符串结尾):

      dates[grep('[0-9]{2}/[0-9]{2}/[0-9]{2}$', dates)]
      [1] "23/11/12" "23/11/12"
      

      否则,除了其他答案之外,您还可以查看 here 和 here 以了解处理多种日期格式的其他方法。

      【讨论】:

        【解决方案5】:

        在您最初尝试基于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"
        

        【讨论】:

          【解决方案6】:

          您可以使用strsplit 和nchar 来获取年份为两个字符长的日期的子向量:

          > dates[sapply(strsplit(dates,"/"),function(x)nchar(x)[3]==2)]
          [1] "23/11/12" "23/11/12"
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-01-25
            • 2012-03-05
            • 1970-01-01
            • 2021-12-31
            • 1970-01-01
            • 1970-01-01
            • 2019-01-14
            • 1970-01-01
            相关资源
            最近更新 更多