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