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