在R中寻求as.Date()函数的解释

6

我正在将一年中的天数转化为日期,但是我发现as.Date函数经常返回出乎意料的(对我来说)结果。为什么下面这些命令会得到如此不同的答案呢?

as.Date(x =  1, format = '%j', origin= '2015-01-01')

返回 "2018-07-21"

as.Date(x = 1, origin= '2015-01-01')

返回 "2015-01-02"

as.Date(x =  1, format = '%j', origin= as.Date('2015-01-01'))

返回 "2015-01-02"

as.Date(x = '1',format = '%j', origin= '2015-01-01')

返回 "2018-01-01"

as.Date(x = '1', origin= '2015-01-01')

返回错误:Error in charToDate(x):字符字符串不符合标准无歧义格式


似乎“as.Date”或“strptime”中存在错误。请注意,当“x”为“character”类时,必须提供“format”,这是最后一个记录的行为。但是,前一个明显是一个错误,“help”页面说明“origin”是“Date object”或“可以被as.Date(origin,...)强制转换为这样的对象的东西”。 - Rui Barradas
安全的方法,也是唯一能够给出正确输出的方法是 as.Date(x = '1', format = '%j', origin= as.Date('2015-01-01'))。请注意 '1' 周围的引号。 - Rui Barradas
@RuiBarradas - 你能否详细解释一下你的答案? - filups21
2
当您使用字符x时,需要使用format,只有在x是字符时才会考虑format。至于origin=as.Date('2015-01-01'),值'2015-01-01'应自动强制转换为Date。但实际上并没有,我认为这是一个明显的错误。 - Rui Barradas
3
这里没有任何错误;@radmuzom的答案解释了所有事情都表现如预期。 - user2554330
1个回答

2

我尝试通过查看S3通用as.Date下的各种方法的定义,以及通过RStudio调试您的代码并查看所调用函数的历史记录来部分回答以下问题。

as.Date.numericas.Date.characteras.Date.default的定义在答案底部提供。

我定义了自己的函数check来调试发生了什么。

check <- function() {

as.Date(x =  1, format = '%j', origin= '2015-01-01')
as.Date(x = 1, origin= '2015-01-01')

}

在第一次调用中,as.DateUseMethod被调用,它将其分派给as.Date.numeric。这又调用了as.Date(origin, ...),现在它被分派给as.Date.character。如果您查看as.Date.character的源代码,则条件if missing(format)为FALSE,因为在此情况下提供了格式%j。因此,被调用的代码片段是strptime(x, format, tz = "GMT")。这将返回2018-07-20 IST,最后一次调用as.Date将其转换为2018-07-20。请注意,时区可能因您所在的国家而异。 strptime内部调用一个无法使用此过程进行调试的C函数。
在第二个调用中,主要区别在于用户未提供格式字符串。因此,按照上述相同的过程,被调用的是as.Date.character内部定义的charToDate函数,而不是strptime,因为条件if missing(format)为TRUE。在这种情况下,charToDate尝试默认格式,并在'%Y-%m-%d中找到匹配项。在这种情况下,strptime提供了正确的格式,并计算出正确的值2015-01-01。现在将其添加到x中,即1-请记住,字符版本是由数字版本调用的,其中代码为as.Date(origin, ...) + x。这提供了正确的答案。
虽然它并没有完全回答您的问题,但一般的学习是它严重依赖于传递给strptime的格式字符串。希望这有所帮助。 as.Date.numeric
function (x, origin, ...)
{
  if (missing(origin))
    stop("'origin' must be supplied")
  as.Date(origin, ...) + x
}

as.Date.character

function (x, format, tryFormats = c("%Y-%m-%d", "%Y/%m/%d"),
          optional = FALSE, ...)
{
  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))
      strptime(x, f)
    else {
      for (ff in tryFormats) if (!is.na(strptime(xx, ff,
                                                 tz = "GMT")))
        return(strptime(x, ff))
      if (optional)
        as.Date.character(rep.int(NA_character_, length(x)),
                          "%Y-%m-%d")
      else 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)
}

as.Date.default

function (x, ...)
{
  if (inherits(x, "Date"))
    x
  else if (is.logical(x) && all(is.na(x)))
    .Date(as.numeric(x))
  else stop(gettextf("do not know how to convert '%s' to class %s",
                     deparse(substitute(x)), dQuote("Date")), domain = NA)
}

2
这个答案非常完整。简短版:如果x是数字,format仅用于origin。如果x是字符,则忽略origin - user2554330

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