楚新元 | All in R

Welcome to R Square

用 R 计算一年有多少天?

楚新元 / 2023-10-17


这个问题本质上就是计算某一年的 2 月份有多少天,我之所以会遇到这个问题是因为我在写 CNID 包的时候遇到了一个要判断身份证号码是否符合逻辑的问题。下面我给出计算某个月有多少天的函数。

mdays = function(
    month, year = as.integer(format(Sys.Date(), "%Y"))
) {
  
  if (is.na(as.numeric(month))) {
    stop("month must be numeric value")
  }
  
  if (is.na(as.numeric(year))) {
    stop("year must be numeric value")
  }
  
  month = as.integer(month)
  year = as.integer(year)
  
  if (month < 1 || month > 12) {
    stop("The month must be between 1 and 12")
  }
  
  days_in_month = integer(12)
  days_in_month[c(1, 3, 5, 7, 8, 10, 12)] = 31
  days_in_month[c(4, 6, 9, 11)] = 30
  days_in_month[2] = 28 + (
    (year %% 4 == 0 && year %% 100 != 0) || (year %% 400 == 0)
  )
  
  return(days_in_month[month])

}

mdays(2, 2020)
#> [1] 29

这个函数的核心计算逻辑其实很简单:年份能被 4 整除、但不能被 100 整除,或能被 400 整除的年份为闰年,其余为平年;闰年 2 月份是 29 天,平年 2 月份是 28 天。最初的代码不到 10 行搞定,后来考虑到各种可能的输入错误,相应地给出报错提示。这个函数的年份参数值如果缺失,则默认计算当年。

题外话,编写函数,不但要求计算逻辑准确,还要考虑到用户在使用过程中的各种场景,即使输入错误,也要给出优雅和必要的提示,对于用户体验方面,以前我没有这方面的意识,直到 Ripley 大人下架了我的一个 R 包,原因是没有给出必要的错误提示,很感谢他的严谨,让我的函数质量和用户友好方面更进一步。

好了,平年闰年的问题解决了,一年有多少天就很容易了,下面直接给出代码:

ydays = function(
    year = as.integer(format(Sys.Date(), "%Y"))
) {
  
  if (is.na(as.numeric(year))) {
    stop("year must be numeric value")
  }

  year = as.integer(year)
  days_in_year = 365 + (
    (year %% 4 == 0 && year %% 100 != 0) || (year %% 400 == 0)
  )
  
  return(days_in_year)
  
}

ydays(2022)
#> [1] 365

上面的代码或许还可以更简单点,但是我不想手动计算除了 2 月份,剩下的 11 个月总共有多少天。