上机作业:日历(java)

1.思路框架分析

本着按照手机日历的构造模型作为model,我着手开始了日历java小程序的编写。说到日历,就不得不提一嘴最可恶的闰年。懂得都懂,闰年是bug制造者。这次用java语言编写,我特意拿出一个方法来判断闰年与否。

java ews 给用户添加日历事件_java

如图所示,用一个if条件语句与闰年的判断条件,返回一个布尔值。

其次,拿到这道题,最让我头疼的是格式化输出。经过网上查阅资料和对UI界面设计的理解,在格式化输出这块,我比照着win10的日历程序编写而成。即:

java ews 给用户添加日历事件_java ews 给用户添加日历事件_02

拿到这个模板之后,我开始编写输出函数。

首先是月份表头的输出,如图所示:

java ews 给用户添加日历事件_主函数_03

以及每个日子组合成表格样式的输出函数:

java ews 给用户添加日历事件_java ews 给用户添加日历事件_04

此处System.out.printf运用条件输出,较为方便。

之后我进行主函数的编写,主要包括人性化提示设计,参数输入以及方法调用,如图所示:

java ews 给用户添加日历事件_主函数_05

主函数实现两个题目所要求的功能,用if与temp1判断符相结合来确定不同功能的实现。在编写过程中为了使主函数尽可能的短小精悍,我又添加了两个方法来缩短行数,两个方法主要是用来储存月份名的字符数据以及每一年第一天的星期的计算,此处我以2000.1.1是周六的基准来计算的,由于未考虑跨世纪的计算,本程序的有效区间也就定格在2000年-2099年。两个类似库的方法如图:

java ews 给用户添加日历事件_System_06


java ews 给用户添加日历事件_java_07

为了进一步加强主函数的可读性,我又将计算某年第一天是周几的函数单独拿出来作为一个方法来应用,如下图所示:

java ews 给用户添加日历事件_System_08

至此,实现功能1的函数已经搭设完毕。为实现功能2,以2000.1.1周六为基准计算之后某一天的星期,我单独拿出一个函数judgeDay来计算

java ews 给用户添加日历事件_格式化输出_09

至此,功能2得到实现,全程序框架结束

2.问题整合

至此程序的所有单独部分都已介绍完毕,下面整合一下遇到的问题。

首先是输出部分的问题,主函数着重有两段函数重复,即我在此处给大家提出的问题:

java ews 给用户添加日历事件_System_10

在格式化输出这一步中,我们可以发现两者的不同在于firstDay变量的不同,由main函数可知,firstDay代表着该年的第一天,是一个基准量,是不同于下面dayWeek变量的,下面的dayWeek变量是给下一个月做铺垫的,本月最后几天给下一周前几天占用多少空,就有多少个dayWeek,但是对于本年第一天,我们需要应用方法theFirstDay计算出结果。
在实现功能2时,对于闰年天数的把握有所欠缺,导致后期出现bug,耽误了许多时间。
在开发过程中遇到很多与c语言相出入的问题,如print、println、printf的用法,以及scanner的用法,都得到了进一步的理解。

3.效果呈现

功能1

java ews 给用户添加日历事件_System_11

功能2

java ews 给用户添加日历事件_主函数_12

4.源码复现

package experience3_2;

import java.util.Scanner;
public class calendar{
	
	//判断是否是闰年的函数
	public static boolean isLeap(int year) {
		if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
			return true;
		else 
			return false;
	}
	
	//计算某年的第一天是周几的函数
	public static int theFirstDay(int year) {
		int i=0;
		switch(((year-2000)*365+(year-2000)/4+1)%7) {
		case 1: i=0;break;
		case 2: i=1;break;
		case 3: i=2;break;
		case 4: i=3;break;
		case 5: i=4;break;
		case 6: i=5;break;
		case 0: i=6;break;
	}
		return i;
	}
	
	//主函数 负责格式化输出和集成调用
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		//先做格式化输出
		System.out.print("主人您好,我是您的智能日历阿展\n请按回车键继续");
		scan.nextLine();
		System.out.println("功能①:查询某年日历 请输入1\n功能②:查询某日星期 请输入2");
		int temp1 = scan.nextInt();
		if(temp1==1) {
			System.out.print("请输入年份:");
			int year = scan.nextInt();
			//计算每年的第一天是周几
			int firstDay = theFirstDay(year);
			//先输出改年第一个月的表头和数据,读者可以自行思考一下为什么单独拿出第一个月
			printMonthTitle(1, year);
			int dayWeek = printDayInMonth(firstDay, 1, year);
			//格式化输出剩下的月份
			for(int month = 2; month <= 12; month++) {
				printMonthTitle(month, year);
				dayWeek = printDayInMonth(dayWeek, month, year);
			}
		}
		else if(temp1==2) {
			System.out.println("请输入年:");
			int year2  = scan.nextInt();
			System.out.println("请输入月:");
			int month  = scan.nextInt();
			System.out.println("请输入日:");
			int day  = scan.nextInt();
			System.out.println("日期  : "+year2+"年"+month+"月"+day+"日");
			String str[]= {"一","二","三","四","五","六","日"};
			int i=1;
			if(isLeap(year2)) {
				int[] leapDays=everyMonthDays(year2);
				i=judgeDay(year2,month,day,leapDays);
				}
			else {
				int[] nonleapDays=everyMonthDays(year2);
				i=judgeDay(year2,month,day,nonleapDays);
			}
			System.out.print("星期"+str[i]);
			}
		
		scan.close();
	}
	
	//格式化每个月份的输出
	public static void printMonthTitle(int month, int year) {
		String monthName = anyMonthName(month);
		System.out.println("       ||" + monthName + "|| " + year);
		
		System.out.println("============================");
		
		System.out.println(" Sun Mon Tue Wed Thu Fri Sat");
	}
	
	//字符串函数给出月份名
	public static String anyMonthName(int month) {
		String monthName = "";
		switch(month) {
			case 1: monthName = "January"; break;
			case 2: monthName = "February"; break;
			case 3: monthName = "March"; break;
			case 4: monthName = "April"; break;
			case 5: monthName = "May"; break;
			case 6: monthName = "June"; break;
			case 7: monthName = "July"; break;
			case 8: monthName = "August"; break;
			case 9: monthName = "September"; break;
			case 10: monthName = "October"; break;
			case 11: monthName = "November"; break;
			case 12: monthName = "December";break;
		}
		
		return monthName;
	}
	
	//通过闰年输出不同月份日期(二月28还是29)
	public static int[] everyMonthDays(int year) {
		int[] leapDays = {
			31,29,31,30,31,30,31,31,30,31,30,31
		};
		int[] nonLeapDays = {
			31,28,31,30,31,30,31,31,30,31,30,31
		};
		
		if(isLeap(year))
			return leapDays;
		else
			return nonLeapDays;
	}
	
	//输出月内日历的函数
	public static int printDayInMonth(int day, int month, int year) {
		
		int t = 0;
		//空出上个月占用第一行的几天,并规定一个日期占用四个空格
		for(int j = 0; j < (day % 7); j++) {
			System.out.print("    ");
			t++;
		}
		int[] days = everyMonthDays(year);
		//打印剩下的天数
		for(int i = 1; i <= days[month - 1]; i++) {
			System.out.printf("%4d", i);
			t++;
			if(t % 7 == 0) {
				System.out.print("\n");
			}
		}
		System.out.print("\n");
		return (t % 7);
	}
	
	//判断功能二中的某日是周几
	public static int judgeDay(int year,int month,int day,int[] args) {
		int daySum=0,i=0;
		for(int j=0;j<month-1;j++)
			daySum+=args[j];
		daySum=daySum+day+(year-2000)*365+(year-2001)/4;
		switch(daySum%7) {
			case 0:i=5;break;
			case 1:i=6;break;
			case 2:i=0;break;
			case 3:i=1;break;
			case 4:i=2;break;
			case 5:i=3;break;
			case 6:i=4;break;
		}
	return i;
	}
}