Java日历类Calendar练习——寻找休息日并打印日历(思路详解)
一、任务概述
某公司软件开发工程师孙工,作息规律为上三天班,休息一天,经常不确定休息日是否周末,为此,请你开发一个程序,当孙工输入年及月,以日历方式显示对应月份的休息日,用中括号进行标记.同时,统计出本月有几天休息,轮到周末休息有几天.(注:首次休息日是 2020 年 2 月 2 日)
此习题来自 开课吧:《新职课JavaEE软件开发工程师》课程
第四章:Java核心类库
第2节:常用类库
二、日历类Calendar
1、getInstance()
创建Calendar类的实例对象时,一般不采用构造方法,而是使用Calendar.getInstance()方法,使用默认时区和区域设置获取日历对象。
Calendar calendar = Calendar.getInstance();
此对象中的时间为默认的系统当前日期与时间。
2、set()与get()
创建Calendar类的对象后,通过set()与get()方法对其包含的日期和时间属性进行设置和获取。
calendar.set(Calendar.YEAR, 2098);
// 给月份赋值时,0代表1月,1代表2月,11代表12月
calendar.set(Calendar.MONTH, 0);
System.out.println(calendar.getTime());
System.out.println(calendar.getTimeInMills());
getTime()返回值为Date类型的标准格式日期
getTimeInMills()返回 long类型的时间戳,单位为毫秒
三、思路梳理
1、让用户按需求输入日期
a、InputMismatchException
为了方便进行之后的赋值和运算,我们希望用户输入int类型的年份和月份,所以需要try catch InputMismatchException,当用户输入的类型不符时,需要提示用户重新输入,来确保程序正常执行
b、日期限定
因为需求中要求用户输入的日期不早于2020年2月,所以需要在用户输入日期时进行判断
当用户输入的年份小于2020时直接提示用户重新输入,当等于2020时,需进一步判断月份是否为1月份。可以写两个方法,分别引导用户输入满足需求的年份和月份。
2、打印日历
a、获取用户输入的月份的天数
我们想打印用户输入的月份的日历,首先想到循环,从1号打印到月末最后一天,那么首先要知道用户输入的那个月有多少天。
既然需求中我们已经让用户输入了年月,并创建了Calendar对象,那么就不要再去使用原始的switch手动判断,一三五七八十腊返回天数的办法。
Calendar类中为我们提供了getActualMaximum(int field)方法,获取field可能的最大值。
当我们传入的field为DAY_OF_MONTH时,可以获取用户输入的月中总共有多少天
int days = calendarInput.getActualMaximum(Calendar.DAY_OF_MONTH);
b、计算日期差
知道了该月总共有多少天之后,我们还要知道该月1号从什么位置开始打印,即:需要知道1号为周几。
我们已知2020年2月1号为周六,则可以通过两个时期的时间差对7取余,来判断用户输入的月份中1号为周几。
同时我们知道时期差之后,对4取余,可以用于判断休息日。
所以我们先要计算两个日期的差值天数,可以用两个日期的时间戳做差的方式计算。
c、获取用户输入月中1号为周几
知道日期差之后,将差值对7取余,则可以判断用户输入的月份中1号为周几。
已知2020年2月1号为周六,当余0时,输入月1号也为周六,该周的最后一天。
余1时日期错后一天,为周日,该周的第一天。
余2时继续错后两天,为周一,该周的第二天,其余同理。
综上规律我们得知,余数为几,1号就是该周的第几天,余0时为第7天。
d、获取用户输入月首次休息日为几号
我们知道1号为周几,该月有多少天之后,已经可以打印该月完整的日历了,下一步要思考的是,这些日期中哪些是上三休一的休息日。
首先想到日期差对4取余,但是总不能随着循环递增,一个月30天每天都取时间戳后与2月2号做差取余,这样效率太低。
我们只要知道输入月的第一个休息日是几号,后面的休息日都是四天一循环的规律,所以我们考虑先计算输入月的首个休息日为几号,之后循环判断打印即可。
e、循环打印日历
知道1号为周几后,先在1号前打印对应数量的空格或制表符。
需要定义一个指针变量来判断是否打印到了周六,到周六时需要换行打印。
然后打印首次休息日之前几天的日历。
接着加入是否为休息日的判断,继续循环打印整个月的日历。
四、任务拆解与代码
1、创建属性(用户输入的年和月,以及两个日历对象)
int inputYear;
int inputMonth;
Calendar calendarFirstRestDay = Calendar.getInstance();
Calendar calendarInput = Calendar.getInstance();
2、获取用户键盘输入的日期
创建getDate()方法,调用getYear()和getMonth()方法获取输入,并将输入的值赋值给对象
public void getDate() {
System.out.println("提示:输入的年月须晚于2020年1月");
getYear();
getMonth();
calendarFirstRestDay.set(Calendar.YEAR, 2020);
calendarFirstRestDay.set(Calendar.MONTH, 1);
calendarInput.set(Calendar.YEAR, inputYear);
calendarInput.set(Calendar.MONTH, inputMonth -1);
}
编写getYear()和getMonth()方法,提示用户按需求输入日期
public void getYear() {
Scanner input = new Scanner(System.in);
System.out.println("请输入年份:");
try {
inputYear = input.nextInt();
if (inputYear < 2020) {
System.out.println("输入的年月须晚于2020年1月");
getYear();
}
} catch (InputMismatchException e) {
System.out.println("输入的年份有误");
getYear();
}
}
public void getMonth() {
Scanner input = new Scanner(System.in