在R中,字符串转日期的“标准明确日期”格式是什么?

113

请考虑以下内容

$ R --vanilla

> as.Date("01 Jan 2000")
Error in charToDate(x) :
    character string is not in a standard unambiguous format

但那个日期显然是以标准明确的格式表示的。为什么会出现错误信息?

更糟糕的是,一个模棱两可的日期显然被接受了,没有警告或错误提示,然后被错误地读取!

> as.Date("01/01/2000")
[1] "0001-01-20"

我在[R]标签中搜索并找到了另外28个包含此错误消息的问题。所有解决方案和解决方法都涉及指定格式,如果我没理解错的话。这个问题不同之处在于,我想知道标准的无歧义格式定义在哪里,并且它们是否可以更改?每个人都会收到这些消息吗,还是只有我?也许与语言环境有关?

换句话说,除了需要指定格式之外,是否有更好的解决方案?

29个包含“[R]标准无歧义格式”的问题

> sessionInfo()
R version 2.15.2 (2012-10-26)
Platform: x86_64-w64-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=English_United Kingdom.1252
[2] LC_CTYPE=English_United Kingdom.1252
[3] LC_MONETARY=English_United Kingdom.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United Kingdom.1252

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

13
根据as.Date.character的函数定义,输入仅经过这两种格式的测试:"%Y-%m-%d""%Y/%m/%d"。如果它能匹配其中一个格式,似乎被视为“明确无歧义”。 - plannapus
7
“Did I even read”似乎暗示?as.Date的答案非常明显。 它在哪里有所帮助? - Matt Dowle
@plannapus 谢谢,那似乎就是答案。您能否添加一下,然后我就可以接受了。 - Matt Dowle
2
可以说,“Jan 24 1949”和“24 Jan 1949”是不含糊的,但它们肯定是以英语为中心的。但是,对于'month.abb'也有一些以英语为中心的值,因此可以认为在这些值匹配的情况下,则可以执行strptime(xx, f <- "%d $B %Y", tz = "GMT")strptime(xx, f <- "%B $d %Y", tz = "GMT")。 (我并不意味着“month.abb”用于与%B匹配,因为文档说匹配是区域设置特定的。) - IRTFM
6
有些时候我们会犯错误。谢谢你在我失落的时候提供的鞭策。在这个问题中,我做对了很多事情:我包含了sessionInfo(),我进行了搜索,并告诉你我搜索了什么并包含了一个链接,我尽可能地保持简洁。我错过了?as.Date的一行内容,你给了我TFM处理。我们不可能始终像你那样完美。 - Matt Dowle
1
@MatthewDowle 对不起,如果我说话太重了。我认为这种华而不实的情况始于你似乎混淆了“对一个相当受过教育的人来说是明确的”和“对一个可怜的代码片段来说是明确的”。 :-( - Carl Witthoft
8个回答

74

这是有文档记录的行为。根据?as.Date

格式:一个字符字符串。如果没有指定,则会在第一个非'NA'元素上尝试“%Y-%m-%d”然后“%Y/%m/%d”,如果两者都不起作用,则会出现错误。

as.Date("01 Jan 2000")会产生一个错误,因为格式不是以上列出的两种之一。as.Date("01/01/2000")会产生一个错误答案,因为日期不符合以上列出的两种格式之一。

我认为“标准明确”的意思是“ISO-8601”(即使as.Date不是那么严格,因为“%m/%d/%Y”不符合ISO-8601)。

如果您收到此错误消息,则解决方法是使用在?strptime详细信息部分中描述的格式指定您的日期(或日期时间)所在的格式。

请确保转换说明的顺序以及任何分隔符与输入字符串的格式完全对应。此外,如果您的数据包含日/月名称和/或缩写,请特别小心,因为转换将取决于您的语言环境(请参见?strptime中的示例并阅读?LC_TIME;还请参见strptimeas.POSIXctas.Date返回意外的NA)。


6
“字符串不是 %Y-%m-%d 或 %Y/%m/%d”这样怎么样? - Matt Dowle
9
?as.Date中确实有对该行为的记录(+1)。然而,“标准无歧义格式”这个错误信息具有讽刺意味,正如前面23个问题所证明的那样,其含义是不明确的。一个更直接的错误信息,比如“未识别的格式,请查看文档”,可能会提高用户体验。此外,我不认为“01/01/2000”是ISO-8601(“2000-01-01”才是ISO-8601),这增加了混淆的可能性。 - jthetzel
@jthetzel:你说得对,“01/01/2000”不是ISO-8601。我的意思是,我个人认为ISO-8601是标准、明确的格式。我同意as.Date不会抱怨“01/01/2000”与错误消息不一致。 - Joshua Ulrich

41

换句话说,是否有比需要指定格式更好的解决方案?

是的,现在(即2016年末)有了更好的解决方案,感谢来自anytime包的anytime::anydate函数。

请参见以下示例:

R> anydate(c("01 Jan 2000", "01/01/2000", "2015/10/10"))
[1] "2000-01-01" "2000-01-01" "2015-10-10"
R> 

正如您所说,它们实际上是明确无误的,并且应该可以直接工作。通过 anydate() ,无需格式。


2
只是因为我们有另一个问题,尝试使用“不完整”的格式解析日期,才来到这里。对于完整的日期格式,我们现在已经有了解决方案。我对此感到非常满意——这是一个令人困扰的问题。不用说,“anytime()”对于“POSIXct”同样有用。 - Dirk Eddelbuettel
刚刚使用了 anytime 包,效果非常好,只是出现了相当多的 NAs。在对日期向量运行 trimws() 后,一切都完美了。 - lawyeR
1
我也使用它非常多! - Dirk Eddelbuettel
看起来很简单!我在一个包含 mm-dd(没有 yy)字符串值的列上使用了 anydate()。该列中的所有 <chr> 值都成功转换为 <date>。不幸的是,它将年份设置为“1400”而不是“2020”。¯_(ツ)_/¯ - owlstone
不完全正确。正如我在这个网站上回答的其他问题中所述,mm-dd不是一个日期(mm-yy或mm-yyyy也不是)。你无法解析不存在的内容。 - Dirk Eddelbuettel

27

作为对@JoshuaUlrich答案的补充,这里是函数as.Date.character的定义:

as.Date.character
function (x, format = "", ...) 
{
    charToDate <- function(x) {
        xx <- x[1L]
        if (is.na(xx)) {
            j <- 1L
            while (is.na(xx) && (j <- j + 1L) <= length(x)) xx <- x[j]
            if (is.na(xx)) 
                f <- "%Y-%m-%d"
        }
        if (is.na(xx) || !is.na(strptime(xx, f <- "%Y-%m-%d", 
            tz = "GMT")) || !is.na(strptime(xx, f <- "%Y/%m/%d", 
            tz = "GMT"))) 
            return(strptime(x, f))
        stop("character string is not in a standard unambiguous format")
    }
    res <- if (missing(format)) 
        charToDate(x)
    else strptime(x, format, tz = "GMT")
    as.Date(res)
}
<bytecode: 0x265b0ec>
<environment: namespace:base>

基本上,如果strptime(x, format="%Y-%m-%d")strptime(x, format="%Y/%m/%d")都抛出一个NA,那么它被认为是有歧义的,否则是无歧义的。


8

没有指定当前日期格式进行转换可能会很容易地导致出现此错误。

以下是一个示例:

sdate <- "2015.10.10"

不指定格式进行转换:


date <- as.Date(sdate4) # ==> This will generate the same error"""Error in charToDate(x): character string is not in a standard unambiguous format""".

指定格式进行转换:

date <- as.Date(sdate4, format = "%Y.%m.%d") # ==> Error Free Date Conversion.

4

无论之前日期编码的方式如何,这对我来说都完美地运作。

library(lubridate)
data$created_date1 <- mdy_hm(data$created_at)
data$created_date1 <- as.Date(data$created_date1)

2

作为补充说明: 如果要转换的项是本应为NA的字符串,则此错误也会被触发。 如果您指定了预期格式或使用“真正的”NA,则不会出现任何问题:

使用data.table的最小可重现示例:

library(data.table)
df <- data.table(date_good = c("01-01-2001", "01-01-2001"), date_bad= ("NA", "01-01-2001"))

df[, .(date_good = as.Date(date_good), date_bad = as.Date(date_bad))]
# Error in charToDate(x) : character string is not in a standard unambiguous format

df[, .(date_good = as.Date(date_good), date_bad = as.Date(date_bad, format="%Y-%m-%d"))]
# No errors; you simply get NA.

df2 <- data.table(date_good = c("01-01-2001", "01-01-2001"), date_bad= (NA, "01-01-2001"))
    
df2[, .(date_good = as.Date(date_good), date_bad = as.Date(date_bad))]
# Just NA

1
你甚至可能想要指定 NA_character_(默认的 NA 是逻辑类型;在实践中这几乎没有影响)。 - Ben Bolker

0
如果日期是例如:"2000年1月1日",我建议使用:
library(lubridate)
date_corrected<-dmy("01 Jan 2000")
date_corrected
[1] "2000-01-01"
class(date_corrected)
[1] "Date"

lubridate几乎为每种日期类型都提供了一个函数。


-1

这些解决方案对我没有用,我仍然遇到了同样的错误。回溯信息显示该错误是由charToDate()函数引起的。

来自Statistics Globe的这篇文章 解决了我的问题。

他们使用了“anytime”包中的“anydate”函数:

df <- df %>% dplyr::mutate(New_Date = as.Date(anytime::anydate(Old_Date)))

你可能忽略了它,但是Dirk Eddelbuettel对这个问题的现有答案给出了这个解决方案...(不清楚为什么需要as.Date(),因为anydate已经返回一个"Date"类的对象...??) - Ben Bolker
我在发布那个问题时有些草率,它没有起作用,把所有东西都转换成了缺失。我正在查看那个答案。 - Barry DeCicco
我在发布那个回答时有点仓促,结果并没有成功,所有的内容都变成了缺失。我正在研究那个答案。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接