001package horstmann.ch03_junit; 002public class Day 003{ 004 /** 005 Constructs a day with a given year, month, and day 006 of the Julian/Gregorian calendar. The Julian calendar 007 is used for all days before October 15, 1582 008 @param aYear a year != 0 009 @param aMonth a month between 1 and 12 010 @param aDate a date between 1 and 31 011 */ 012 public Day(int aYear, int aMonth, int aDate) 013 { 014 year = aYear; 015 month = aMonth; 016 date = aDate; 017 } 018 019 /** 020 Returns the year of this day 021 @return the year 022 */ 023 public int getYear() 024 { 025 return year; 026 } 027 028 /** 029 Returns the month of this day 030 @return the month 031 */ 032 public int getMonth() 033 { 034 return month; 035 } 036 037 /** 038 Returns the day of the month of this day 039 @return the day of the month 040 */ 041 public int getDate() 042 { 043 return date; 044 } 045 046 /** 047 Returns a day that is a certain number of days away from 048 this day 049 @param n the number of days, can be negative 050 @return a day that is n days away from this one 051 */ 052 public Day addDays(int n) 053 { 054 Day result = this; 055 while (n > 0) 056 { 057 result = result.nextDay(); 058 n--; 059 } 060 while (n < 0) 061 { 062 result = result.previousDay(); 063 n++; 064 } 065 return result; 066 } 067 068 /** 069 Returns the number of days between this day and another 070 day 071 @param other the other day 072 @return the number of days that this day is away from 073 the other (>0 if this day comes later) 074 */ 075 public int daysFrom(Day other) 076 { 077 int n = 0; 078 Day d = this; 079 while (d.compareTo(other) > 0) 080 { 081 d = d.previousDay(); 082 n++; 083 } 084 while (d.compareTo(other) < 0) 085 { 086 d = d.nextDay(); 087 n--; 088 } 089 return n; 090 } 091 092 /** 093 Compares this day with another day. 094 @param other the other day 095 @return a positive number if this day comes after the 096 other day, a negative number if this day comes before 097 the other day, and zero if the days are the same 098 */ 099 private int compareTo(Day other) 100 { 101 if (year > other.year) return 1; 102 if (year < other.year) return -1; 103 if (month > other.month) return 1; 104 if (month < other.month) return -1; 105 return date - other.date; 106 } 107 108 /** 109 Computes the next day. 110 @return the day following this day 111 */ 112 private Day nextDay() 113 { 114 int y = year; 115 int m = month; 116 int d = date; 117 118 if (y == GREGORIAN_START_YEAR 119 && m == GREGORIAN_START_MONTH 120 && d == JULIAN_END_DAY) 121 d = GREGORIAN_START_DAY; 122 else if (d < daysPerMonth(y, m)) 123 d++; 124 else 125 { 126 d = 1; 127 m++; 128 if (m > DECEMBER) 129 { 130 m = JANUARY; y++; 131 if (y == 0) y++; 132 } 133 } 134 return new Day(y, m, d); 135 } 136 137 /** 138 Computes the previous day. 139 @return the day preceding this day 140 */ 141 private Day previousDay() 142 { 143 int y = year; 144 int m = month; 145 int d = date; 146 147 if (y == GREGORIAN_START_YEAR 148 && m == GREGORIAN_START_MONTH 149 && d == GREGORIAN_START_DAY) 150 d = JULIAN_END_DAY; 151 else if (d > 1) 152 d--; 153 else 154 { 155 m--; 156 if (m < JANUARY) 157 { 158 m = DECEMBER; y--; 159 if (y == 0) y = -1; 160 } 161 d = daysPerMonth(y, m); 162 } 163 return new Day(y, m, d); 164 } 165 166 /** 167 Gets the days in a given month 168 @param y the year 169 @param m the month 170 @return the last day in the given month 171 */ 172 private static int daysPerMonth(int y, int m) 173 { 174 int days = DAYS_PER_MONTH[m - 1]; 175 if (m == FEBRUARY && isLeapYear(y)) 176 days++; 177 return days; 178 } 179 180 /** 181 Tests if a year is a leap year 182 @param y the year 183 @return true if y is a leap year 184 */ 185 private static boolean isLeapYear(int y) 186 { 187 if (y % 4 != 0) return false; 188 if (y < GREGORIAN_START_YEAR) return true; 189 return (y % 100 != 0) || (y % 400 == 0); 190 } 191 192 private int year; 193 private int month; 194 private int date; 195 196 private static final int[] DAYS_PER_MONTH 197 = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 198 199 private static final int GREGORIAN_START_YEAR = 1582; 200 private static final int GREGORIAN_START_MONTH = 10; 201 private static final int GREGORIAN_START_DAY = 15; 202 private static final int JULIAN_END_DAY = 4; 203 204 public static final int JANUARY = 1; 205 public static final int FEBRUARY = 2; 206 public static final int DECEMBER = 12; 207} 208 209 210 211 212