尝试从 5 位或 6 位数字中提取日期

Trying to extract a date from a 5 or 6-digit number

我正在尝试从数字中提取日期。日期存储为 11 位个人 ID 号(日期-月份-年份)的前 6 位数字。不幸的是,它的基于云的数据库 (REDCap) 输出被格式化为数字,因此在该月的前 9 天出生的人中,前导零以 10 位数字而不是 11 位数字结束。我设法提取了与日期对应的 6 位或 5 位数字,即 311230 表示 1930 年 12 月 31 日,或 11230 表示 1930 年 12 月第一个。我最终遇到了两个无法解决的问题。

假设我们使用以下数字:

dato <- c(311230, 311245, 311267, 311268, 310169, 201104, 51230, 51269, 51204)

我将它们转换成字符串,然后应用 as.Date() 函数:

datostr <- as.character(dato)
datofinal <- as.Date(datostr, "%d%m%y")
datofinal

我遇到的问题是:

我相信对于那些更了解 R 的人来说这一定很容易,但是,我很难解决这个问题。非常感谢任何帮助。

您好 比约恩

如果您的 5 位数字真的只需要补零,那么

dato_s <- sprintf("%06d", dato)
dato_s
# [1] "311230" "311245" "311267" "311268" "310169" "201104" "051230" "051269" "051204"

从那里开始,您关于 “1969 年之前的日期”的问题,查看 ?strptime'%y' 模式:

 '%y' Year without century (00-99).  On input, values 00 to 68 are
      prefixed by 20 and 69 to 99 by 19 - that is the behaviour
      specified by the 2018 POSIX standard, but it does also say
      'it is expected that in a future version the default century
      inferred from a 2-digit year will change'.

因此,如果您有特定的交替年份,则需要在 发送到 as.Date(使用 strptime-模式)之前添加世纪 .

dato_d <- as.Date(gsub("([0-4][0-9])$", "20\1",
                       gsub("([5-9][0-9])$", "19\1", dato_s)),
                  format = "%d%m%Y")
dato_d
# [1] "2030-12-31" "2045-12-31" "1967-12-31" "1968-12-31" "1969-01-31" "2004-11-20"
# [7] "2030-12-05" "1969-12-05" "2004-12-05"

在这种情况下,我假设 50-99 为 1900,其他均为 2000。如果您需要 40s 或 30s,请随意调整模式:将数字添加到第二个模式(例如,[3-9]) 并从第一个模式中删除(例如,[0-2]),确保所有十年都包含在一个模式中,而不是“两者都不是”而不是“两者”。

借用 ,我喜欢 now() 的假设(因为你确实提到了 “出生于”)。没有 lubridate,试试这个:

dato_s <- sprintf("%06d", dato)
dato_d <- as.Date(dato_s, format = "%d%m%y")
dato_d[ dato_d > Sys.Date() ] <-
  as.Date(sub("([0-9]{2})$", "19\1", dato_s[ dato_d > Sys.Date() ]), format = "%d%m%Y")
dato_d
# [1] "1930-12-31" "1945-12-31" "1967-12-31" "1968-12-31" "1969-01-31" "2004-11-20"
# [7] "1930-12-05" "1969-12-05" "2004-12-05"

将五位数“数字”转换为六位数非常简单:x <- stringr::str_pad(x, 6, pad="0") 或类似的方法就可以了。

你多年的问题是 Millennium bug 重访。您必须咨询整理数据的人员,以了解他们使用了哪些假设。

我怀疑 31Dec1970 或之前的所有日期都受到影响,而不仅仅是 01Jan1960 之前的日期。这是因为 as.Date 在决定​​如何处理两位数年份时使用默认原点 01Jan1970。所以你的解决方案是在你的转换中选择一个合适的来源来修复这个数据集。类似于 d <- as.Date(x, origin="1900-01-01")。然后开始使用四位数的年份! ;)

您可以使用 lubridate 使这更容易一些,并注意任何人的出生日期都不能是当前时间的未来:

library(lubridate)

dato <- dmy(sprintf("%06d", dato))
dato[dato > now()] <- dato[dato > now()] - years(100)

dato
#> [1] "1930-12-31" "1945-12-31" "1967-12-31" "1968-12-31" "1969-01-31"
#> [6] "2004-11-20" "1930-12-05" "1969-12-05" "2004-12-05"

当然,在没有进一步信息的情况下,此方法(也不会)能够挑选出 100 岁以上人群的边缘情况。这可能很容易从上下文中确定。

reprex package (v0.3.0)

于 2020-06-29 创建