期中考试题1:MyDate的部分实现
题目:根据提供的代码,实现一个简单的日期类。将你的代码实现在标示有YOU FILL THIS IN的位置。你可以添加新的类或者新的方法,但请不要改动已有的代码。
注:
1. 根据格里高利历法(Gregorian calendar,即公历) 实现这个类
2. year参数是大于或等于1970,小于2050的正整数,month是大于等于1,小于等于12的正整数,day是大于等于 1,小于等于31的正整数。
3. 你无需考虑输入值是否合法的问题。测试时我们总会输入合法的日期。但是我们鼓励你在实现中考虑到非法输入的情况,比如 2010-02-29。
4. 闰年的规则是:
# 逢400的倍数为闰年,如2000年;
# 若非400的倍数,而是100的倍数,为平年,如1900年;
# 若非100的倍数,而是4的倍数,为闰年,如1996年;
# 非以上情况的年份均为平年。
5. 不允许使用java.util包
这个MyDate类其实是java.util包中的Calendar类的部分实现,需要实现的方法是:
public boolean isLeapYear();
public int getDaysBetween(MyDate another);
public MyDate getDateAfter(int d);
public int getDayOfWeek();
如果各位知道Calendar类的实现思路的话,这个类的实现还是很简单的,很多人头疼的就是怎样写getDaysBetween()方法,比较简单的一种思路就是:让两个日期和同一个起始日期比较,相减即可;类似如果我们知道了起始日期是星期几,那么通过取模运算就可以很方便的得到当前日期是星期几。
综合考虑,我们需要一下几个辅助方法:
public static boolean isLeapYear(int year); //判断传入年份是否是闰年
public static int getDaysOffset(MyDate date); //返回输入日期和起始日期之间的天数差
private static int getDaysOfMonth(int month, boolean isLeapYear); //返回对应月份的天数
各自的实现:
public static boolean isLeapYear(int year){ return ((year % 400 == 0)||((year % 100 != 0) && (year % 4 == 0))); }
/** * Added method<br> * Returns the number of days since January 1st, 1970. * @param date * a <code>MyDate</code> object * @return the gap between date and January 1st, 1970 */ public static int getDaysOffset(MyDate date) { boolean isLeapYear = isLeapYear(date.year); int yearOffset = date.year - 1970; int leapYears = (yearOffset + 1) / 4; int totalDays = (yearOffset - leapYears) * 365 + leapYears * 366; for(int i = 1;i < date.month;i++){ totalDays += getDaysOfMonth(i, isLeapYear); } //System.out.println("the offset is " + (totalDays + date.day - 1)); return (totalDays + date.day - 1); }
/** * Added method<br> * Returns the days of the <code>month</code><br> * The days of February is determined by <code>isLeapYear</code> * @param month * @param isLeapYear * @return the days of a certain month */ private static int getDaysOfMonth(int month, boolean isLeapYear) { switch(month){ case 1: case 3: case 5: case 7: case 8: case 10: case 12: return 31; case 2: return (isLeapYear)?29:28; case 4: case 6: case 9: case 11: return 30; } return 0; }
这三个方法中,只有getDaysOffset方法有点儿复杂,其实就是从1970年1月1日算起(题目的要求中已经说明了不会早于这个日期,其实Calendar类是以1900年1月1日开始计算的,那天是星期一),先算相隔年份中的平年天数和闰年天数,在计算“今年”已经经过的天数,就是总的天数差了。
然后,四个方法里面的三个我们都可以很快写出来了:
/** * Returns if this year is a leap one. * * @return whether this year is a leap one */ public boolean isLeapYear() { return isLeapYear(this.year); } public static boolean isLeapYear(int year){ return ((year % 400 == 0)||((year % 100 != 0) && (year % 4 == 0))); }
/** * Returns the number of days between this object and another MyDate object. * If this date is the same as <code>another</code>, 0 is returned. If it is * after <code>another</code>, then the returned value should be a positive * number. Otherwise, this method returns a negative number. * * @param another * a <code>MyDate</code> object * @return the gap between two MyDate objects */ public int getDaysBetween(MyDate another) { return getDaysOffset(this) - getDaysOffset(another); }
/** * Tells which day of the week this date is. If it is Monday, 0 is returned. * Tuesday gives a result of 1, and so forth. * * @return the day of the week */ public int getDayOfWeek() { int days = getDaysOffset(this); return (days + 3) % 7; }
剩下的一个方法,因为只要得到n天之后的日期,我们循环到需要加的日期小于等于当前月的最大天数就行,所以这样写:
/** * Calculates the date that are <code>d</code> days after this date. * * @param days * the number of days * @return a new <code>MyDate</code> object */ public MyDate getDateAfter(int d) { int newDay = day + d; int newMonth = month; int newYear = year; while(newDay > getDaysOfMonth(newMonth, isLeapYear(newYear))){ newDay -= getDaysOfMonth(newMonth, isLeapYear(newYear)); newMonth++; if(newMonth > 12){ newMonth -= 12; newYear++; } } return new MyDate(newYear, newMonth, newDay); }