是否有更优雅的方式将两位数年份转换为四位数年份与lubridate?

时间:2012-09-07 18:44:35

标签: r date lubridate

如果日期向量具有两位数年份,则mdy()将年份介于00和68之间,进入21世纪,年份介于69到99之间,直至20世纪。例如:

library(lubridate)    
mdy(c("1/2/54","1/2/68","1/2/69","1/2/99","1/2/04"))

给出以下输出:

Multiple format matches with 5 successes: %m/%d/%y, %m/%d/%Y.
Using date format %m/%d/%y.
[1] "2054-01-02 UTC" "2068-01-02 UTC" "1969-01-02 UTC" "1999-01-02 UTC" "2004-01-02 UTC"

我可以通过从不正确的日期减去100到2054和2068到1954年和1968年来解决这个问题。但是有一种更优雅且不易出错的方法来解析两位数日期以便处理它们正确地在解析过程中?

更新 @JoshuaUlrich指出strptime后我发现了this question,它处理了与我类似的问题,但是使用了基础R.

似乎R中日期处理的一个很好的补充是在日期解析函数中处理两位数日期的世纪选择截止值的某种方式。

3 个答案:

答案 0 :(得分:26)

这是一个允许你这样做的功能:

library(lubridate)
x <- mdy(c("1/2/54","1/2/68","1/2/69","1/2/99","1/2/04"))


foo <- function(x, year=1968){
  m <- year(x) %% 100
  year(x) <- ifelse(m > year %% 100, 1900+m, 2000+m)
  x
}

尝试一下:

x
[1] "2054-01-02 UTC" "2068-01-02 UTC" "1969-01-02 UTC" "1999-01-02 UTC"
[5] "2004-01-02 UTC"

foo(x)
[1] "2054-01-02 UTC" "2068-01-02 UTC" "1969-01-02 UTC" "1999-01-02 UTC"
[5] "2004-01-02 UTC"

foo(x, 1950)
[1] "1954-01-02 UTC" "1968-01-02 UTC" "1969-01-02 UTC" "1999-01-02 UTC"
[5] "2004-01-02 UTC"

这里的神奇之处在于使用模数运算符%%来返回除法的小数部分。所以1968 %% 100会产生68。

答案 1 :(得分:2)

我刚刚遇到了这个完全相同的错误/功能。

我最后编写了以下两个快速函数来帮助从excel类型的日期(这是我最常见的)转换为R可以使用的东西。

接受的答案没有错 - 只是我不想太多地加载包裹。

首先,帮助分裂并取代岁月......

year1900 <- function(dd_y, yrFlip = 50)
{
    dd_y <- as.numeric(dd_y)
    dd_y[dd_y > yrFlip] <- dd_y[dd_y > yrFlip] + 1900
    dd_y[dd_y < yrFlip] <- dd_y[dd_y < yrFlip] + 2000
    return(dd_y)
}

由“修复”您的Excel日期的函数使用,具体取决于类型:

XLdate <- function(Xd, type = 'b-Y')
{
    switch(type,
        'b-Y' = as.Date(paste0(substr(Xd, 5, 9), "-", substr(Xd, 1, 3), "-01"), format = "%Y-%b-%d"),
        'b-y' = as.Date(paste0(year1900(substr(Xd, 5, 6)), "-", substr(Xd, 1, 3), "-01"), 
                        format = "%Y-%b-%d"),
        'Y-b' = as.Date(paste0(substr(Xd, 1, 3), "-", substr(Xd, 5, 9), "-01"), format =     "%Y-%b-%d")
        )
}

希望这会有所帮助。

答案 2 :(得分:0)

另一种选择是:

xxx <- c("01-Jan-54","01-Feb-68","01-Aug-69","01-May-99","01-Jun-04", "
       31-Dec-68","01-Jan-69", "31-Dec-99")

dmy(paste0(sub("\\d\\d$","",xxx) , ifelse( (tt <- 
   sub("\\d\\d-\\D\\D\\D-","",xxx)  ) > 20 ,paste0("19",tt),paste0("20",tt))))

虽然没有解决方案优雅也不简短。 我认为如果lubridate只添加一个选项来指定截止日期会更好。