R:检查日期是否有效



>假设日期指定为三个整数:年、月、日

年份是一个 4 位整数(例如 2020(,月份范围超过 1-12,日期范围超过 1-31。

我正在寻找一个简单的函数(称之为 checkdate(,它可以检查日期是否有效,如果有效则返回 TRUE,如果无效则返回 FALSE。

例如,checkdate(2008, 2, 29( 将返回 TRUE,因为 2008 年是闰年。

另一方面,checkdate(2009, 2, 29( 将返回 FALSE,因为 2009 年不是闰年。

checkdate(2009, 6, 31( 将返回 FALSE,因为 6 月只有 30 天。

等。

更新

根据 Dirk 的回答,下面是一个函数,可以满足我的要求:

checkdate = function(y, m, d) {
#y: A year, not abbreviated to 2 digits.
#m: An integer in the range 1-12.
#d: An integer in the range 1-31.
#Convert to an R Date object.
#If the date is not valid, NA is returned.
dt = as.Date(paste(y, m, d, sep='-'), optional=TRUE)
ifelse(is.na(dt), FALSE, TRUE)
}

如果返回FALSE失败,请尝试将输入转换为日期。

checkdate <- function(y, m, d) {
tryCatch(lubridate::is.Date(as.Date(paste(y, m, d, sep = '-'))), 
error = function(e) return(FALSE))
}
checkdate(2009, 6, 31)
#[1] FALSE
checkdate(2009, 2, 29)
#[1] FALSE
checkdate(2008, 2, 29)
#[1] TRUE

当然。只需尝试解析它:

R> days <- 28:31
R> dates <- paste0("2020-02-", days)
R> as.Date(dates)
[1] "2020-02-28" "2020-02-29" NA           NA          
R> 

这表明在 2020 年,2 月 28 日和 29 日存在(闰年(,但没有 30 日和 31 日。

从三个向量中,您可以使用sprintf("%4d-%02d-%02", y, m, d)来创建要解析的文本输入向量。

Base R 使用@Ronak Shah 的逻辑:

checkdate <- function(y, m, d) {
tryCatch(inherits(as.Date(paste(y, m, d, sep = '-')), "Date"), 
error = function(e) return(FALSE))
}
checkdate(2015, 12, 31)

这是一个更安全的功能:

checkdate <- function(y, m, d, min.year = NA, max.year = NA, recycle = TRUE) {
if (!recycle){
y_length <- length(y)
m_length <- length(m)
d_length <- length(d)
if (y_length != m_length | d_length != m_length ){
stop("The y, m and d vectors provided do not have the same length.")
}
}

dates <- paste(y, m, d, sep = "-")
# Accepts numbers and characters, but explicitly check conversion

!is.na(as.numeric(y)) &

# These 2 lines of code are optional but useful (with min.year=1900, reject "23" as we think "2023" is meant)
(is.na(min.year) | as.numeric(y) >= min.year ) &  
(is.na(max.year) | as.numeric(y) <= max.year ) & 
!is.na(as.numeric(m)) & as.numeric(m) > 0 & as.numeric(m) < 13 &
!is.na(as.numeric(d)) & as.numeric(d) > 0 & as.numeric(d) < 32 &
!is.na(as.Date(dates,
format = "%Y-%m-%d",
optional = TRUE # indicating to return NA (instead of signalling an error)
)
)
}
# Possible uses:
checkdate(0:40, 0:40, 0:40)
checkdate(0:40, 0:40, 0:40, min.year = 2000)
checkdate("2023", 0:40, 0:40, min.year = 2000)
checkdate("2023", 0:40, 0:40, recycle = F)

这比其他答案安全得多。 它将适用于 3 个向量 y、m、d(与 Ronak 的答案相反(;如果需要,它会回收它们(我们可以使用 recycle=F 检查矢量长度以防止这种情况(。它接受字符串和数字。 它不接受"10-11-12"或"10-11-123456789"。请注意,有点令人惊讶:

as.Date (paste(10, 11, 2023, sep = '-'), format = "%Y-%m-%d" )
[1]  "10-11-20" # is "a valid date" (!)

但这并不太令人惊讶:作为。Date(( 不是设计为验证函数,而是转换有效输入的函数。我们需要更加小心地进行验证。

min.year,max.year选项和相关的代码行是可选的,但在我看来,在某些情况下很有用;它们定义了一年的有效范围。当min.year=1900时,我们拒绝"23",因为我们认为"2023"的意思。

最新更新