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: }