R语言 用正确的世纪将两位数年份转换为四位数年份

bf1o4zei  于 2023-05-11  发布在  其他
关注(0)|答案(3)|浏览(206)

如果日期向量有两位数的年份,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,它处理了一个类似于我的问题,但使用的是base R。

看起来R中日期处理的一个很好的补充是在日期解析函数中处理两位数日期的世纪选择截止值。

qvk1mo1f

qvk1mo1f1#

下面是一个函数,它允许你这样做:

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。

jyztefdp

jyztefdp2#

我刚刚经历了这个完全相同的bug /功能。
最后,我写了下面两个快速函数来帮助从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")
        )
}

希望这能帮上忙。

ivqmmu1c

ivqmmu1c3#

另一种选择是:

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只是添加一个指定截止日期的选项会更好。

相关问题