R中字符串到日期转换的“标准明确日期”格式是啥?

Posted

技术标签:

【中文标题】R中字符串到日期转换的“标准明确日期”格式是啥?【英文标题】:What are the "standard unambiguous date" formats for string-to-date conversion in R?R中字符串到日期转换的“标准明确日期”格式是什么? 【发布时间】:2013-01-23 04:57:55 【问题描述】:

请考虑以下事项

$ 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 个其他问题。所有解决方案和解决方法都涉及指定格式 iiuc。这个问题的不同之处在于我问的是标准的明确格式在哪里定义,它们可以改变吗?每个人都收到这些消息还是只有我一个人?也许它与语言环境有关?

也就是说,有没有比需要指定格式更好的解决方案?

29 questions containing "[R] standard unambiguous format"

> 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

【问题讨论】:

as.Date.character的函数定义来看,输入只测试了"%Y-%m-%d""%Y/%m/%d"这两种格式。如果它可以匹配其中之一,它似乎被认为是“明确的”。 @CarlWitthoft “我读过吗”似乎暗示答案在?as.Date 中显而易见。它对这有什么帮助? 可以说“1949 年 1 月 24 日”和“1949 年 1 月 24 日”是明确的,但它们肯定是以盎格鲁为中心的。然而,“month.abb”也有一些以盎格鲁为中心的值,因此可以在以下情况下匹配这些值:strptime(xx, f <- "%d $B %Y", tz = "GMT")strptime(xx, f <- "%B $d %Y", tz = "GMT") 返回值。 (我并不是说 month.abb 用于匹配 %B,因为文档说匹配是特定于语言环境的。) @CarlWitthoft 我们中的一些人时不时地绊倒。谢谢你在我情绪低落时的一脚。在这个问题中,我做了很多正确的事情:我包含了 sessionInfo(),我搜索了,告诉你我搜索了什么并包含了一个链接,我尽可能地保持简洁。我错过了 ?as.Date 中的一行,你给了我 TFM 治疗。我们不可能一直都像你一样完美。 @MatthewDowle 对不起,如果我摔倒了。我认为,当您似乎将“对受过良好教育的人毫不含糊”与“对于可怜无助的一段代码毫不含糊”混为一谈时,这种***就开始了。 :-( 【参考方案1】:

这是记录在案的行为。来自?as.Date

格式:一个字符串。如果未指定,它将尝试 '"%Y-%m-%d"' 然后 '"%Y/%m/%d"' 在第一个非 'NA' 元素上, 如果两者都不起作用,则给出错误。

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

我认为“标准明确”是指“ISO-8601”(尽管 as.Date 没有那么严格,因为“%m/%d/%Y”不是 ISO-8601)。

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

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

【讨论】:

@BenBolker "character string is not either %Y-%m-%d or %Y/%m/%d" 怎么样? 该行为肯定记录在?as.Date (+1) 中。然而,具有讽刺意味的是,“标准明确格式”的错误消息是模棱两可的,前面的 23 个问题都证明了这一点。更直接的错误消息(例如“格式无法识别,请参阅文档”)可能会改善用户体验。另外,我不相信“01/01/2000”是 ISO-8601(“2000-01-01”是 ISO-8601),这增加了歧义。 @jthetzel:你说得对,“01/01/2000”不是 ISO-8601。我的意思是我个人认为 ISO-8601 是标准的、明确的格式。我同意as.Date 不抱怨“01/01/2000”与错误消息不一致。【参考方案2】:

也就是说,有没有比需要指定格式更好的解决方案?

是的,现在有(即在 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() 他们做到了。没有格式。

【讨论】:

之所以来到这里,是因为我们有另一个问题是试图用 incomplete 格式解析日期。对于完整的,我们现在有了一些东西。我对此很满意——这是一个令人烦恼的问题。不用说,anytime()POSIXct 同样有用。 刚刚使用了anytime包,它工作得非常好,除了很多NA。在日期向量上运行 trimws() 之后,一切都很完美。 我也用了一公吨! 看起来很简单!我在字符串值为 mm-dd(无 yy)的列上使用了 anydate()。该列中的所有 值均已成功转换为 。不幸的是,它将年份设置为“1400”而不是“2020”。 ¯_(ツ)_/¯ 嗯,不完全是。正如我在本网站上的其他几个问题中回答的那样,mm-dd 不是日期(既不是 mm-yy 也不是 mm-yyyy)。你无法解析它不存在的东西。【参考方案3】:

作为@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,它被认为是模棱两可的,如果不是明确的话。

【讨论】:

【参考方案4】:

在不指定当前格式的情况下转换日期很容易给你带来这个错误。

这是一个例子:

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.

【讨论】:

【参考方案5】:

这对我来说非常适合,无论日期之前是如何编码的。

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

【讨论】:

【参考方案6】:

作为补充: 如果您尝试转换的条目是应该是 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

【讨论】:

您甚至可能想要指定NA_character_(默认NA 是逻辑类型;实际上这并不重要)【参考方案7】:

如果日期例如:“01 Jan 2000”,我建议使用

library(lubridate)
date_corrected<-dmy("01 Jan 2000")
date_corrected
[1] "2000-01-01"
class(date_corrected)
[1] "Date"

lubridate 对几乎所有类型的日期都有一个功能。

【讨论】:

以上是关于R中字符串到日期转换的“标准明确日期”格式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

将日期转换为格式日、日月年

R笔记日期处理

dateformat将日期类型转换为指定的字符串格式的方法名是啥

在R中将日期转换为特定格式的字符

使用 R 将日期格式的字符串列表/向量转换为 posix 日期类

SQL中如何将数值格式的20110801(2011年8月01日)转换为日期格式的201108或者2011-08?