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:    }
017: 
018:    /**
019:       Returns the year of this day
020:       @return the year
021:    */
022:    public int getYear()
023:    {
024:       return year;
025:    }
026: 
027:    /**
028:       Returns the month of this day
029:       @return the month
030:    */
031:    public int getMonth()
032:    {
033:       return month;
034:    }
035: 
036:    /**
037:       Returns the day of the month of this day
038:       @return the day of the month
039:    */
040:    public int getDate()
041:    {
042:       return date;
043:    }
044: 
045:    /**
046:       Returns a day that is a certain number of days away from
047:       this day
048:       @param n the number of days, can be negative
049:       @return a day that is n days away from this one
050:    */
051:    public Day addDays(int n)
052:    {
053:       Day result = this;
054:       while (n > 0)
055:       {
056:          result = result.nextDay();
057:          n--;
058:       }
059:       while (n < 0)
060:       {
061:          result = result.previousDay();
062:          n++;
063:       }
064:       return result;
065:    }
066: 
067:    /**
068:       Returns the number of days between this day and another
069:       day
070:       @param other the other day
071:       @return the number of days that this day is away from 
072:       the other (>0 if this day comes later)
073:    */
074:    public int daysFrom(Day other)
075:    {
076:       int n = 0;
077:       Day d = this;
078:       while (d.compareTo(other) > 0)
079:       {
080:          d = d.previousDay();
081:          n++;
082:       }
083:       while (d.compareTo(other) < 0)
084:       {
085:          d = d.nextDay();
086:          n--;
087:       }
088:       return n;
089:    }
090: 
091:    /**
092:       Compares this day with another day.
093:       @param other the other day
094:       @return a positive number if this day comes after the
095:       other day, a negative number if this day comes before
096:       the other day, and zero if the days are the same
097:    */
098:    private int compareTo(Day other)
099:    {
100:       if (year > other.year) return 1;
101:       if (year < other.year) return -1;
102:       if (month > other.month) return 1;
103:       if (month < other.month) return -1;
104:       return date - other.date;
105:    }
106: 
107:    /**
108:       Computes the next day.
109:       @return the day following this day
110:    */
111:    private Day nextDay()
112:    {
113:       int y = year;
114:       int m = month;
115:       int d = date;
116: 
117:       if (y == GREGORIAN_START_YEAR
118:             && m == GREGORIAN_START_MONTH
119:             && d == JULIAN_END_DAY)
120:          d = GREGORIAN_START_DAY;
121:       else if (d < daysPerMonth(y, m))
122:          d++;
123:       else
124:       {
125:          d = 1;
126:          m++;
127:          if (m > DECEMBER) 
128:          { 
129:             m = JANUARY; 
130:             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; 
159:             y--; 
160:             if (y == 0) y--;
161:          }
162:          d = daysPerMonth(y, m);
163:       }
164:       return new Day(y, m, d);
165:    }
166: 
167:    /**
168:       Gets the days in a given month
169:       @param y the year
170:       @param m the month
171:       @return the last day in the given month
172:    */
173:    private static int daysPerMonth(int y, int m)
174:    {
175:       int days = DAYS_PER_MONTH[m - 1];
176:       if (m == FEBRUARY && isLeapYear(y)) 
177:          days++;
178:       return days;
179:    }
180: 
181:    /**
182:       Tests if a year is a leap year
183:       @param y the year
184:       @return true if y is a leap year
185:    */
186:    private static boolean isLeapYear(int y)
187:    {
188:       if (y % 4 != 0) return false;
189:       if (y < GREGORIAN_START_YEAR) return true;
190:       return (y % 100 != 0) || (y % 400 == 0);
191:    }
192: 
193:    private int year;
194:    private int month;
195:    private int date;
196: 
197:    private static final int[] DAYS_PER_MONTH 
198:          = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
199: 
200:    private static final int GREGORIAN_START_YEAR = 1582;
201:    private static final int GREGORIAN_START_MONTH = 10;
202:    private static final int GREGORIAN_START_DAY = 15;
203:    private static final int JULIAN_END_DAY = 4;
204: 
205:    private static final int JANUARY = 1;
206:    private static final int FEBRUARY = 2;
207:    private static final int DECEMBER = 12;
208: }
209: 
210: 
211: 
212: 
213: