【问题标题】:Is there a more elegant way to convert two-digit years to four-digit years with lubridate?有没有更优雅的方法可以使用 lubridate 将两位数年份转换为四位数年份?
【发布时间】:2012-09-01 16:00:42
【问题描述】:

如果日期向量有两位数的年份,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 中对日期处理的一个很好的补充似乎是在日期解析函数中处理两位数日期的世纪选择截止值。

【问题讨论】:

  • 从技术上讲,日期被正确解析,因为文档 (?strptime) 指出:“在输入时,值 00 到 68 以 20 为前缀,而 69 到 99 以 19 为前缀 - 也就是说2004 和 2008 POSIX 标准规定的行为”。 ?parse_date 简要告诉您查看 ?strptime 的格式。
  • 我应该更准确。我并不是要暗示lubridate 有一个错误,而仅仅是因为两位数年份的模糊性,包的自然行为导致不正确的四位数年份(“不正确”在“不是期望的结果”)在一些相对常见的情况下。我希望lubridate 中有某种方法可以指定“开关”或“截止”值,从而为给定的两位数日期范围提供所需的世纪。
  • 建议您向 lubridate 的 github 页面提交功能请求。
  • 请注意,这不再是 lubridate 的行为。对于您的示例,输出现在是 [1] "2054-01-02 UTC" "2068-01-02 UTC" "2069-01-02 UTC" "2099-01-02 UTC" "2004-01-02 UTC"
  • @skan, parse_date_time2 有一个 cutoff_2000 选项。您可以在此处指定不同的截止年份。

标签: r date lubridate


【解决方案1】:

另一种选择是:

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

【讨论】:

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

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      这是一个允许您执行此操作的函数:

      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。

      【讨论】:

      • 不错!刚刚注意到你的回答。感谢您的帮助。
      猜你喜欢
      • 2011-01-02
      • 2010-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      相关资源
      最近更新 更多