001package horstmann.ch03_day3;
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                ymdValid = true;
018                julianValid = false;
019        }
020
021        /**
022      Returns the year of this day
023      @return the year
024         */
025        public int getYear()
026        {
027                ensureYmd();
028                return year;
029        }
030
031        /**
032      Returns the month of this day
033      @return the month
034         */
035        public int getMonth()
036        {
037                ensureYmd();
038                return month;
039        }
040
041        /**
042      Returns the day of the month of this day
043      @return the day of the month
044         */
045        public int getDate()
046        {
047                ensureYmd();
048                return date;
049        }
050
051        /**
052      Returns a day that is a certain number of days away from
053      this day
054      @param n the number of days, can be negative
055      @return a day that is n days away from this one
056         */
057        public Day addDays(int n)
058        {
059                ensureJulian();
060                return new Day(julian + n);
061        }
062
063        /**
064      Returns the number of days between this day and another
065      day
066      @param other the other day
067      @return the number of days that this day is away from
068      the other (>0 if this day comes later)
069         */
070        public int daysFrom(Day other)
071        {
072                ensureJulian();
073                other.ensureJulian();
074                return julian - other.julian;
075        }
076
077        private Day(int aJulian)
078        {
079                julian = aJulian;
080                ymdValid = false;
081                julianValid = true;
082        }
083
084        /**
085      Computes the Julian day number of this day if
086      necessary
087         */
088        private void ensureJulian()
089        {
090                if (julianValid) return;
091                julian = toJulian(year, month, date);
092                julianValid = true;
093        }
094
095        /**
096      Converts this Julian day mumber to a calendar date if necessary.
097         */
098        private void ensureYmd()
099        {
100                if (ymdValid) return;
101                int[] ymd = fromJulian(julian);
102                year = ymd[0];
103                month = ymd[1];
104                date = ymd[2];
105                ymdValid = true;
106        }
107
108        /**
109      Computes the Julian day number of the given day day.
110
111      @param year a year
112      @param month a month
113      @param date a day of the month
114      @return The Julian day number that begins at noon of
115      the given day
116      Positive year signifies CE, negative year BCE.
117      Remember that the year after 1 BCE is 1 CE.
118
119      A convenient reference point is that May 23, 1968 noon
120      is Julian day number 2440000.
121
122      Julian day number 0 is a Monday.
123
124      This algorithm is from Press et al., Numerical Recipes
125      in C, 2nd ed., Cambridge University Press 1992
126         */
127        private static int toJulian(int year, int month, int date)
128        {
129                int jy = year;
130                if (year < 0) jy++;
131                int jm = month;
132                if (month > 2) jm++;
133                else
134                {
135                        jy--;
136                        jm += 13;
137                }
138                int jul = (int) (java.lang.Math.floor(365.25 * jy)
139                                + java.lang.Math.floor(30.6001 * jm) + date + 1720995.0);
140
141                int IGREG = 15 + 31 * (10 + 12 * 1582);
142                // Gregorian Calendar adopted Oct. 15, 1582
143
144                if (date + 31 * (month + 12 * year) >= IGREG)
145                        // Change over to Gregorian calendar
146                {
147                        int ja = (int) (0.01 * jy);
148                        jul += 2 - ja + (int) (0.25 * ja);
149                }
150                return jul;
151        }
152
153        /**
154      Converts a Julian day number to a calendar date.
155
156      This algorithm is from Press et al., Numerical Recipes
157      in C, 2nd ed., Cambridge University Press 1992
158
159      @param j  the Julian day number
160      @return an array whose 0 entry is the year, 1 the month,
161      and 2 the day of the month.
162         */
163        @SuppressWarnings("cast")
164        private static int[] fromJulian(int j)
165        {
166                int ja = j;
167
168                int JGREG = 2299161;
169                // The Julian day number of the adoption of the Gregorian calendar
170
171                if (j >= JGREG)
172                        // Cross-over to Gregorian Calendar produces this correction
173                {
174                        int jalpha = (int) (((float) (j - 1867216) - 0.25)
175                                        / 36524.25);
176                        ja += 1 + jalpha - (int) (0.25 * jalpha);
177                }
178                int jb = ja + 1524;
179                int jc = (int) (6680.0 + ((float) (jb - 2439870) - 122.1)
180                                / 365.25);
181                int jd = (int) (365 * jc + (0.25 * jc));
182                int je = (int) ((jb - jd) / 30.6001);
183                int date = jb - jd - (int) (30.6001 * je);
184                int month = je - 1;
185                if (month > 12) month -= 12;
186                int year = jc - 4715;
187                if (month > 2) --year;
188                if (year <= 0) --year;
189                return new int[] { year, month, date };
190        }
191
192        private int year;
193        private int month;
194        private int date;
195        private int julian;
196        private boolean ymdValid;
197        private boolean julianValid;
198}
199
200
201
202
203