    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: }
    203:
    204:
    205:
    206:
    207: