记得之前蔡工说过一道题:在Java的控制台中打印用户指定月份的日历,要求类似Windows系统任务栏右侧的日历。一直觉着很简单没去做,今天有空,就拿来练练手磨磨刀,免得Java基础忘得一干二净吧。该工程有两个类,一个执行类(Run.java),一个自然月类(Month.java)。现将代码贴上,如下:
Run类
package com.printcalendar.run;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Run {
Month inputMonth = null;
boolean debug = false;//Just for debug when it's necessary.
//获得用户输入,并简单判断输入合法性
private boolean getUserInput() {
int year;
int month;
String preYear = null;
String preMonth = null;
System.out.print("Input destination year:");
preYear = new Scanner(System.in).next();
System.out.print("Input destination month:");
preMonth = new Scanner(System.in).next();
if( isNumeric(preYear) ) {
year = Integer.parseInt(preYear);
} else {
return false;
}
if( isNumeric(preMonth) ) {
month = Integer.parseInt(preMonth);
} else {
return false;
}
if( !(year> 0 && year< 10000) ) {
return false;
}
if( !(month> 0 && month< 13) ) {
return false;
}
inputMonth = new Month(year, month);
return true;
}
//检查指定字串内容是否为数字
private boolean isNumeric(String str) {
Matcher isNum = Pattern.compile("[0-9]*").matcher(str);
if( !isNum.matches() ) {
return false;
} else {
return true;
}
}
//检查指定年份是否为闰年:四年一闰,百年不闰,四百年再闰
private boolean isLeapYear(int year) {
if ( (year% 4== 0 && year%100!= 0) || year% 400== 0 ) {
return true;
} else {
return false;
}
}
//获取两个自然月实例之间的自然日差值(以2016年1月为基准)
private int getBetweenDays(Month month) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
long day1= 0,day2= 0;
try {
day1 = sdf.parse("2016-1-1").getTime();
day2 = sdf.parse(month.getYear()+ "-"+ month.getMonth()+ "-1").getTime();
} catch (ParseException e) {
e.printStackTrace();
}
long betweenDays = Math.abs(day1- day2)/86400000;//86400000=1000*60*60*24
return (int)betweenDays;
}
//设置指定月的天数
private void setMonthLength(Month month) {
switch(month.getMonth()) {
case 2:
if( isLeapYear(month.getYear()) ) {
month.setmonthLength(29);
} else {
month.setmonthLength(28);
}
break;
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
month.setmonthLength(31);
break;
default:
month.setmonthLength(30);
break;
}
}
//设置指定自然月实例第一天(1号)为星期几:Sunday=1,Monday=2,...,Saturday=7
private void setOrdinalDay(Month month) {//Sun=1,Sat=7
int result = getBetweenDays(month)% 7;
//↓ ↓ ↓ D E B U G ↓ ↓ ↓
if(debug == true) {
System.out.println("[DEBUG]"+ "BetweenDays="+ getBetweenDays(month));
System.out.println("[DEBUG]"+ "result="+ result);
}
//↑ ↑ ↑ D E B U G ↑ ↑ ↑
if(month.getYear()>= 2016) {//When the "month" after 2016.01
switch(result) {
case 0:
month.setOrdinalDay(6);
break;
case 1:
month.setOrdinalDay(7);
break;
case 2:
month.setOrdinalDay(1);
break;
case 3:
month.setOrdinalDay(2);
break;
case 4:
month.setOrdinalDay(3);
break;
case 5:
month.setOrdinalDay(4);
break;
case 6:
month.setOrdinalDay(5);
break;
default:
}
} else {//When the "month" before 2016.01
switch(result) {
case 0:
month.setOrdinalDay(6);
break;
case 1:
month.setOrdinalDay(5);
break;
case 2:
month.setOrdinalDay(4);
break;
case 3:
month.setOrdinalDay(3);
break;
case 4:
month.setOrdinalDay(2);
break;
case 5:
month.setOrdinalDay(1);
break;
case 6:
month.setOrdinalDay(7);
break;
default:
}
}
}
//按照Windows系统任务栏的日历格式在控制台输出
private void layout(Month month) {
System.out.println();
System.out.println(" === "+ month.getYear()+ "-"+ month.getMonth()+ " ===");
System.out.println();
System.out.println("Sun Mon Tue Wed Thu Fri Sat");
int od = month.getOrdinalDay();
//↓ ↓ ↓ D E B U G ↓ ↓ ↓
if(debug == true) {
System.out.println("[DEBUG]"+ "OrdinalDay="+ od);
}
//↑ ↑ ↑ D E B U G ↑ ↑ ↑
for(int i= 0; i< (od- 1)* 4; i++) {
System.out.print(" ");
}
int counter = 0;
for(int i= 1; counter< month.getmonthLength(); i++) {
if( (od+ counter- 1)% 7== 0 ) {
System.out.println();
}
System.out.printf("%2d",i);
System.out.print(" ");
counter++;
}
}
//Constructor
public Run() {
if( !getUserInput() ) {
System.out.println("sth. wrong");
}
setMonthLength(inputMonth);
setOrdinalDay(inputMonth);
layout(inputMonth);
}
public static void main(String[] args) {
new Run();
}
}
Month类
package com.printcalendar.run;
public class Month {
private int year;//Which year is it.
private int month;//The first of several be this month of the year
private int ordinalDay;//The first of several be ((the first day of this month) of the week).
private int monthLength;//How many days does the month has.
public int getYear() {
return year;
}
//@unused
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
//@unused
public void setMonth(int month) {
this.month = month;
}
public int getOrdinalDay() {
return ordinalDay;
}
public void setOrdinalDay(int ordinalDay) {
this.ordinalDay = ordinalDay;
}
public int getmonthLength() {
return monthLength;
}
public void setmonthLength(int monthLength) {
this.monthLength = monthLength;
}
//Constructor
public Month(int year, int month) {
this.year = year;
this.month = month;
}
}
由于是在单位的电脑上写的,而那儿的电脑又是全日文环境,编码是Shift-JIS,不能打汉字。所以写的时候基本是英文注释,现在上面的中文注释都是临时加的。因为加得比较匆忙,可能会有些不准确甚至错误,以后发现了再来修改吧。