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