001package horstmann.ch03_day1; 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; 131 y++; 132 if (y == 0) y++; 133 } 134 } 135 return new Day(y, m, d); 136 } 137 138 /** 139 Computes the previous day. 140 @return the day preceding this day 141 */ 142 private Day previousDay() 143 { 144 int y = year; 145 int m = month; 146 int d = date; 147 148 if (y == GREGORIAN_START_YEAR 149 && m == GREGORIAN_START_MONTH 150 && d == GREGORIAN_START_DAY) 151 d = JULIAN_END_DAY; 152 else if (d > 1) 153 d--; 154 else 155 { 156 m--; 157 if (m < JANUARY) 158 { 159 m = DECEMBER; 160 y--; 161 if (y == 0) y--; 162 } 163 d = daysPerMonth(y, m); 164 } 165 return new Day(y, m, d); 166 } 167 168 /** 169 Gets the days in a given month 170 @param y the year 171 @param m the month 172 @return the last day in the given month 173 */ 174 private static int daysPerMonth(int y, int m) 175 { 176 int days = DAYS_PER_MONTH[m - 1]; 177 if (m == FEBRUARY && isLeapYear(y)) 178 days++; 179 return days; 180 } 181 182 /** 183 Tests if a year is a leap year 184 @param y the year 185 @return true if y is a leap year 186 */ 187 private static boolean isLeapYear(int y) 188 { 189 if (y % 4 != 0) return false; 190 if (y < GREGORIAN_START_YEAR) return true; 191 return (y % 100 != 0) || (y % 400 == 0); 192 } 193 194 private int year; 195 private int month; 196 private int date; 197 198 private static final int[] DAYS_PER_MONTH 199 = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 200 201 private static final int GREGORIAN_START_YEAR = 1582; 202 private static final int GREGORIAN_START_MONTH = 10; 203 private static final int GREGORIAN_START_DAY = 15; 204 private static final int JULIAN_END_DAY = 4; 205 206 private static final int JANUARY = 1; 207 private static final int FEBRUARY = 2; 208 private static final int DECEMBER = 12; 209} 210 211 212 213 214