    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; y++;
    130:             if (y == 0) y++;
    131:          }
    132:       }
    133:       return new Day(y, m, d);
    134:    }
    135:
    136:    /**
    137:       Computes the previous day.
    138:       @return the day preceding this day
    139:    */
    140:    private Day previousDay()
    141:    {
    142:       int y = year;
    143:       int m = month;
    144:       int d = date;
    145:
    146:       if (y == GREGORIAN_START_YEAR
    147:          && m == GREGORIAN_START_MONTH
    148:          && d == GREGORIAN_START_DAY)
    149:             d = JULIAN_END_DAY;
    150:       else if (d > 1)
    151:          d--;
    152:       else
    153:       {
    154:          m--;
    155:          if (m < JANUARY)
    156:          {
    157:             m = DECEMBER; y--;
    158:             if (y == 0) y = -1;
    159:          }
    160:          d = daysPerMonth(y, m);
    161:       }
    162:       return new Day(y, m, d);
    163:    }
    164:
    165:    /**
    166:       Gets the days in a given month
    167:       @param y the year
    168:       @param m the month
    169:       @return the last day in the given month
    170:    */
    171:    private static int daysPerMonth(int y, int m)
    172:    {
    173:       int days = DAYS_PER_MONTH[m - 1];
    174:       if (m == FEBRUARY && isLeapYear(y))
    175:          days++;
    176:       return days;
    177:    }
    178:
    179:    /**
    180:       Tests if a year is a leap year
    181:       @param y the year
    182:       @return true if y is a leap year
    183:    */
    184:    private static boolean isLeapYear(int y)
    185:    {
    186:       if (y % 4 != 0) return false;
    187:       if (y < GREGORIAN_START_YEAR) return true;
    188:       return (y % 100 != 0) || (y % 400 == 0);
    189:    }
    190:
    191:    private int year;
    192:    private int month;
    193:    private int date;
    194:
    195:    private static final int[] DAYS_PER_MONTH
    196:       = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    197:
    198:    private static final int GREGORIAN_START_YEAR = 1582;
    199:    private static final int GREGORIAN_START_MONTH = 10;
    200:    private static final int GREGORIAN_START_DAY = 15;
    201:    private static final int JULIAN_END_DAY = 4;
    202:
    203:    public static final int JANUARY = 1;
    204:    public static final int FEBRUARY = 2;
    205:    public static final int DECEMBER = 12;
    206: }
    207:
    208:
    209:
    210:
    211: