使用Calendar类和它的子类GregorianCalendar类实现构建动态日历

大家好, 我是安心君,这是我在博客园的第一篇博客. 这里主要和大家分享我使用Calendar类和它的子类GregorianCalendar类实现构建动态日历项目的收获和心得. 

以前我们在没有学习到这两个类之前,用的是当前月的头一天到1900年1月1日(因为在这天正好是星期一)的时间除以7(一周的时间) 所得的余数 确定当前月份的第一天是星期几. 这个算法虽然容易理解,但是实现起来比较繁琐.而当我们学会了Calendar类的使用,会发现制作动态日历的过程变得非常轻松

这里先把代码奉上(在敲这个代码的时候,本人对Calendar类的使用也不熟悉,所以代码很多地方都可以优化,我也会逐一解析)

import java.util.Calendar;
import java.util.GregorianCalendar;

public class DynaCalendar {
//创建一个日历对象
Calendar c = Calendar.getInstance();
//创建一个公历类对象
GregorianCalendar gc = new GregorianCalendar();
public static void main(String[] args) {
//这里选择直接定义 如果你们想在控制台输入 写个Scanner就行了 也不麻烦
//咱们这就主讲算法了
int year = 2020;
int month = 7;
//创建一个对象调用日历方法(如果创建对象只需要调用一个方法,则可以直接new 不需要再定义一个引用去接受它)
//建议大家看方法一定要从主方法开始看起 所有程序都是由主方法开始执行的
new DynaCalendar().dynaCalendar(year,month);
}

public void dynaCalendar(int year,int month) {
//先输出日历格式
System.out.println("星期一"+"\t"+"星期二"+"\t"+"星期三"+"\t"+"星期四"+"\t"+"星期五"+"\t"+"星期六"+"\t"+"星期日"+"\t");
//通过GregorianCalendar类的isLeapYear判断是否为闰年
if(gc.isLeapYear(year)){
switch(month){
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: evenMonth(month - 1,year);//大月排序方法
break;
case 2: leapFebMonth(month - 1,year);//闰年2月排序方法
break;
case 4:
case 6:
case 9:
case 11: oddMonth(month - 1,year);//小月排序方法
}
}else{
switch(month){
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: evenMonth(month - 1,year);
break;
case 2: febMonth(month - 1,year);//普通年份2月排序方法
break;
case 4:
case 6:
case 9:
case 11: oddMonth(month - 1,year);
}

}
}
public void evenMonth(int month,int year){//大月
int t = 0;
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month);
c.set(Calendar.DAY_OF_MONTH, 1);
int day = c.get(Calendar.DAY_OF_WEEK);
// System.out.println(day);
if(day == 1){
t = 6;
}else{
//打印的空格数
t = day - 2;
}
for(int i = 0;i < t;i++){
System.out.print("\t");
}
for(int i = 1;i < 32;i++){
System.out.print(i+"\t");
if((i + t) % 7==0){
System.out.println();
}
}
}

public void febMonth(int month,int year){//普通2月
int t = 0;
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month);
c.set(Calendar.DAY_OF_MONTH, 1);
int day = c.get(Calendar.DAY_OF_WEEK);
// System.out.println(day);
if(day == 1){
t = 6;
}else{
t = day - 2;
}
for(int i = 0;i < t;i++){
System.out.print("\t");
}
for(int i = 1;i < 29;i++){
System.out.print(i+"\t");
if((i + t) % 7==0){
System.out.println();
}
}
}

public void oddMonth(int month,int year){//小月
int t = 0;
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month);
c.set(Calendar.DAY_OF_MONTH, 1);
int day = c.get(Calendar.DAY_OF_WEEK);
// System.out.println(day);
if(day == 1){
t = 6;
}else{
t = day - 2;
}
for(int i = 0;i < t;i++){
System.out.print("\t");
}
for(int i = 1;i < 31;i++){
System.out.print(i+"\t");
if((i + t) % 7==0){
System.out.println();
}
}
}

public void leapFebMonth(int month,int year){//闰年2月
int t = 0;
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month);
c.set(Calendar.DAY_OF_MONTH, 1);
int day = c.get(Calendar.DAY_OF_WEEK);
// System.out.println(day);
if(day == 1){
t = 6;
}else{
t = day - 2;
}
for(int i = 0;i < t;i++){
System.out.print("\t");
}
for(int i = 1;i < 30;i++){
System.out.print(i+"\t");
if((i + t) % 7==0){
System.out.println();
}
}
}
}

可能这个时候有些读者已经看出来了 那个时候我还不会使用Calendar类中的getActualMaximum 方法 所以冤枉的写了很多switch-case语句和确定不同月份的日历排序的方法(很烦~~~).

Calendar类中的getActualMaximum(int field)方法中的参数可以把当前月份-1的值传进来,确定当前月份的天数,这样就不用像我一样创建很多这种方法去计算.而且这两个switch其实也能合并成一个 在二月份那里加上确认闰年的判断就行了

虽然代码的冗余度高了,但是从某种角度说,读者看这样的代码思路应该会更清晰,也是好事.    现在开始分析代码 :

1.首先定义创建Calendar类和GregorianCalendar类的对象,这里主要会用到GregorianCalendar类中的isLeapYear方法,即判断闰年的方法.

2.首先我们就能想到,拿到一个年份,首先判断他是否为闰年,因为只有是或不是两种情况,所以我在选择了闰年一个switch-case语句 非闰年一个switch-case语句 

3.根据不同月份确定如何排序  其实也没啥改变,只是修改下天数罢了 排序的方式都是相同的  (重点:这里传入方法的月份应该是你输入月份-1的值,因为在Calendar类内部12个月份是按数组排列的 ,下标为0-11,要比实际值少个1,当然用户不知道我们方法的内部实现,不可能自己手动-1,因此我们要将传入的月份-1达到用户的期望)

4.当设置的年份和月份传入方法后 , 我们利用Calendar类中的set(int field, int value)方法,将时间设定到我们所设置的时间,重点来了:接着我们把天数通过c.set(Calendar.DAY_OF_MONTH, 1);方法设定到当前月份的第一天,然后通过c.get(Calendar.DAY_OF_WEEK);方法得到当前月份的第一天在这周是第几天  这里通过Calendar类中的这些方法就可以实现定位当前月份第一天的想法 较之以前省下了很多代码的编写 

5.定位了当前月份第一天后,我们就可以确定日历前的空格是多少,这里推荐用"\t"制表符进行分割. 接下来还是重点:我们要知道,以前的日历是以星期日为一周的第一天,Calendar类也是一样,所以正常情况下,我们是用day-1作为空格数,而现在应该用day-2作为空格数了. 重重重点!   这里还有个意外 就是当当前月份的第一天就是星期日的时候,day -1 是0 而空格数变成了负数,这当然是不合乎常理的 所以我们只需要把这个单独情况列出来即可.

6.我们输出空格的算法已经完成 最后一步就是把当前月份的日历打印出来,这就很简单了 从当前月份的第一天循环输出到最后一天 (将得到的天数+空格数)%7,得到的余数如果是0 就换行

7.这样动态日历就制作完成了!!!!!!!!!

这里附上上面代码的运行结果:

 

posted @ 2020-07-05 10:09  安心敲代码就完事了  阅读(207)  评论(1编辑  收藏  举报