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