闰年的判断方法
在我们目前使用的格里高利历(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;
}