关于日期的一些计算

闰年的判断方法

在我们目前使用的格里高利历(Gregorian Calendar)中,闰年的确定遵循着一套精确的规则,具体来说,这些规则如下:

  • 任何能被4整除的年份通常被认为是闰年。这意味着每四年,我们会增加一天,即2月29日,使得该年有366天而非常规的365天。
  • 如果一个年份能被100整除,那么它通常不被认定为闰年,但是它既能被100整除,同时也能被400整除,那么它就是闰年。

以2000年和1900年为例,2000年是闰年,因为它能被400整除(2000 ÷ 400 = 5),而1900年虽然能被100整除(1900 ÷ 100 = 19),但不能被400整除(1900 ÷ 400 ≠ 整数),因此1900年不是闰年。

bool isLeapYear(int year) { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); }

给定年份的某个月有几天

主要涉及到闰年要调整2月份的天数

int daysInMonth(int year, int month) {
  assert(month >= 1 && month <= 12);  // 月份范围检查
  // 每个月的天数(非闰年)
  const int daysInMonthTable[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

  // 判断是否为闰年
  if (month == 2 && isLeapYear(year)) {
    return 29;
  } else {
    return daysInMonthTable[month];
  }
}

判断给定的日期是给定年份的第几天

要计算给定的日期是给定年份的第几天,可以遍历从1月到给定月份之前的所有月份,累加每个月的天数到dayOfYear,最后,将给定月份的天数加到dayOfYear上即可。要特别注意2月,因为闰年和平年的天数不同,在累加月份天数时,如果年份是闰年且当前月份是2月,则2月有29天;否则,2月有28天。

int dayOfYear(int year, int month, int day) {
  int doy = 0;
  for (int m = 1; m < month; ++m) doy += daysInMonth(year, m);
  doy += day;
  return doy;
}

判断给定的日期是星期几

要判断给定日期是星期几,可以使用蔡勒公式(Zeller’s Congruence)。该公式通过数学计算将日期转换为星期几,适用于格里高利历(公历)。以下是实现步骤:

  • 调整月份和年份:例如,2020年1月转换为2019年13月,以便公式处理。
  • 分解年份:将年份分解为世纪数J和后两位K,如2023年分解为J=20,K=23。
  • 蔡勒公式计算:公式中的各项计算对应日期参数,最终结果h取模7得到0-6的值,分别对应星期六到星期五。
int dayOfWeek(int year, int month, int day) {
  // 处理1月和2月,视为上一年的13月和14月
  if (month < 3) {
    month += 12;
    year--;
  }
  // 分解年份为世纪数(J)和年份后两位(K)
  int j = year / 100, k = year % 100;
  // 蔡勒公式计算
  int h = (day + (13 * (month + 1)) / 5 + k + (k / 4) + (j / 4) + 5 * j) % 7;
  return (h == 0) ? 6 : (h == 1) ? 7 : h - 1;  // 转换为ISO星期(周一=1)
}

不过,蔡勒公式只适合于1582年(中国明朝万历十年)10月15日之后的情形。

判断当前日期为当前年份周数

在中国,周数的计算通常遵循以下规则:

  • 每周从星期一开始,到星期日结束;
  • 1月1日所在的周通常被认为是第1周;
int week(int year, int month, int day) {
  int daysOfRemain = dayOfYear(year, month, day) - (7 - dayOfWeek(year, 1, 1) + 1);
  if (daysOfRemain == 0) {
    return 1;
  }

  int week = std::ceil(static_cast<double>(daysOfRemain) / 7);
  return week + 1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值