Day 5:日期与时间计算(闰年、星期计算)
在编程竞赛中,日期和时间计算是常见考点,涉及 闰年判断、星期计算、日期间隔计算 等问题。本日的学习目标:
- 判断闰年
- 计算某个日期是星期几
- 计算两个日期之间相差多少天
- 处理日期边界情况
一、闰年判断(Leap Year)
1. 什么是闰年?
闰年(Leap Year)是 一个额外的 2 月 29 日,用来调整公历与天文年的误差。
判断规则
- 能被 4 整除,但不能被 100 整除
- 能被 400 整除
规则:
能被4整除但不能被100整除的年份是闰年。
能被400整除的年份也是闰年。
例子:2000年是闰年,1900年不是闰年。
例如:
- 2000 年 是闰年(满足 400 整除)
- 1900 年 不是闰年(满足 100 整除但不满足 400)
- 2024 年 是闰年(满足 4 但不满足 100)
2. 代码实现
import java.util.Scanner;public class LeapYear {public static boolean isLeapYear(int year) {return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入年份:");int year = scanner.nextInt();if (isLeapYear(year)) {System.out.println(year + " 是闰年");} else {System.out.println(year + " 不是闰年");}}}
✅ 时间复杂度 O(1),只进行几次取模计算,速度非常快。
月份天数
各月天数:
1月(31天)、2月(闰年29天,平年28天)、3月(31天)、4月(30天)、5月(31天)、6月(30天)、
7月(31天)、8月(31天)、9月(30天)、10月(31天)、11月(30天)、12月(31天)。
public static int getDaysOfMonth(int year, int month) {int[] days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};if (month == 2 && isLeapYear(year)) return 29; // 闰年2月return days[month - 1]; // 月份从1开始,数组下标从0开始}
二、计算某个日期是星期几
1. 计算方法
蔡勒公式(Zeller's Congruence)
W=(y+y/4−y/100+y/400+(13(m+1))/5+d)W = (y + y/4 - y/100 + y/400 + (13(m+1))/5 + d) % 7
参数解释
- y = 年份(如果 m=1 或 m=2,则 y = y - 1)
- m = 月份(1 月 和 2 月 视为 13 月 和 14 月,年份减 1)
- d = 日期
- W 代表星期:
0 - 星期六, 1 - 星期日, 2 - 星期一, 3 - 星期二, 4 - 星期三, 5 - 星期四, 6 - 星期五
2. 代码实现
import java.util.Scanner;public class DayOfWeek {public static String getDayOfWeek(int year, int month, int day) {if (month == 1 || month == 2) {month += 12; // 1月和2月看作前一年 13、14 月year--;}int w = (year + year / 4 - year / 100 + year / 400 + (13 * (month + 1)) / 5 + day) % 7;String[] days = {"星期六", "星期日", "星期一", "星期二", "星期三", "星期四", "星期五"};return days[w];}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入年份、月份、日期(用空格分隔):");int year = scanner.nextInt();int month = scanner.nextInt();int day = scanner.nextInt();System.out.println(year + "年" + month + "月" + day + "日 是 " + getDayOfWeek(year, month, day));}}
✅ 时间复杂度 O(1),直接计算,不用循环。
三、计算两个日期间隔天数
1. 思路
- 计算两个日期到 1970-01-01 的天数
- 相减得到间隔天数
- 需要考虑闰年和不同月份的天数
�� 2. 代码实现
import java.time.LocalDate;import java.time.temporal.ChronoUnit;import java.util.Scanner;public class DateDifference {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.println("请输入第一个日期(格式:yyyy mm dd):");int year1 = scanner.nextInt();int month1 = scanner.nextInt();int day1 = scanner.nextInt();System.out.println("请输入第二个日期(格式:yyyy mm dd):");int year2 = scanner.nextInt();int month2 = scanner.nextInt();int day2 = scanner.nextInt();LocalDate date1 = LocalDate.of(year1, month1, day1);LocalDate date2 = LocalDate.of(year2, month2, day2);long daysBetween = ChronoUnit.DAYS.between(date1, date2);System.out.println("两个日期相差 " + Math.abs(daysBetween) + " 天");}}
✅ 时间复杂度 O(1),使用 Java 8 LocalDate 处理日期,避免手动计算。
四、蓝桥杯日期问题常考点
考点 | 典型题目 | 优化技巧 |
闰年判断 | 判断某年是否为闰年 | 直接使用 `if ((year % 4 == 0 && year % 100 != 0) |
星期计算 | 给定年月日,计算星期几 | 使用 蔡勒公式 |
日期间隔 | 计算两个日期间隔天数 | LocalDate 计算更高效 |
自定义日历 | 模拟日历程序 | Java Calendar 或 LocalDateTime |
五、易错点总结
❌ 1. 忘记 1 月 和 2 月 的特殊处理
if (month == 1 || month == 2) {
month += 12;
year--;
}
❌ 2. 日期范围错误
LocalDate date1 = LocalDate.of(2022, 13, 15); // ❌ 错误,月份超出范围
✅ 正确做法
LocalDate date1 = LocalDate.of(2022, 12, 15); // ✅ 正确
❌ 3. ChronoUnit.DAYS.between() 使用错误
long days = ChronoUnit.DAYS.between(date2, date1); // ❌ 可能得到负值
✅ 正确做法
long days = Math.abs(ChronoUnit.DAYS.between(date1, date2)); // ✅ 取绝对值