EasterHoliday.java revision 836e6b40a94ec3fb7545a76cb072960442b7eee9
1/* GENERATED SOURCE. DO NOT MODIFY. */ 2/* 3 ******************************************************************************* 4 * Copyright (C) 1996-2014, International Business Machines Corporation and * 5 * others. All Rights Reserved. * 6 ******************************************************************************* 7 */ 8 9package android.icu.util; 10 11import java.util.Date; 12 13/** 14 * <b>Note:</b> The Holiday framework is a technology preview. 15 * Despite its age, is still draft API, and clients should treat it as such. 16 * 17 * A Holiday subclass which represents holidays that occur 18 * a fixed number of days before or after Easter. Supports both the 19 * Western and Orthodox methods for calculating Easter. 20 * {@literal @}draft ICU 2.8 (retainAll) 21 * {@literal @}provisional This API might change or be removed in a future release. 22 * @hide Only a subset of ICU is exposed in Android 23 * @hide draft / provisional / internal are hidden on Android 24 * @hide All android.icu classes are currently hidden 25 */ 26public class EasterHoliday extends Holiday 27{ 28 /** 29 * Construct a holiday that falls on Easter Sunday every year 30 * 31 * @param name The name of the holiday 32 * {@literal @}draft ICU 2.8 33 * {@literal @}provisional This API might change or be removed in a future release. 34 * @hide draft / provisional / internal are hidden on Android 35 */ 36 public EasterHoliday(String name) 37 { 38 super(name, new EasterRule(0, false)); 39 } 40 41 /** 42 * Construct a holiday that falls a specified number of days before 43 * or after Easter Sunday each year. 44 * 45 * @param daysAfter The number of days before (-) or after (+) Easter 46 * @param name The name of the holiday 47 * {@literal @}draft ICU 2.8 48 * {@literal @}provisional This API might change or be removed in a future release. 49 * @hide draft / provisional / internal are hidden on Android 50 */ 51 public EasterHoliday(int daysAfter, String name) 52 { 53 super(name, new EasterRule(daysAfter, false)); 54 } 55 56 /** 57 * Construct a holiday that falls a specified number of days before 58 * or after Easter Sunday each year, using either the Western 59 * or Orthodox calendar. 60 * 61 * @param daysAfter The number of days before (-) or after (+) Easter 62 * @param orthodox Use the Orthodox calendar? 63 * @param name The name of the holiday 64 * {@literal @}draft ICU 2.8 65 * {@literal @}provisional This API might change or be removed in a future release. 66 * @hide draft / provisional / internal are hidden on Android 67 */ 68 public EasterHoliday(int daysAfter, boolean orthodox, String name) 69 { 70 super(name, new EasterRule(daysAfter, orthodox)); 71 } 72 73 /** 74 * Shrove Tuesday, aka Mardi Gras, 48 days before Easter 75 * {@literal @}draft ICU 2.8 76 * {@literal @}provisional This API might change or be removed in a future release. 77 * @hide draft / provisional / internal are hidden on Android 78 */ 79 static public final EasterHoliday SHROVE_TUESDAY = new EasterHoliday(-48, "Shrove Tuesday"); 80 81 /** 82 * Ash Wednesday, start of Lent, 47 days before Easter 83 * {@literal @}draft ICU 2.8 84 * {@literal @}provisional This API might change or be removed in a future release. 85 * @hide draft / provisional / internal are hidden on Android 86 */ 87 static public final EasterHoliday ASH_WEDNESDAY = new EasterHoliday(-47, "Ash Wednesday"); 88 89 /** 90 * Palm Sunday, 7 days before Easter 91 * {@literal @}draft ICU 2.8 92 * {@literal @}provisional This API might change or be removed in a future release. 93 * @hide draft / provisional / internal are hidden on Android 94 */ 95 static public final EasterHoliday PALM_SUNDAY = new EasterHoliday( -7, "Palm Sunday"); 96 97 /** 98 * Maundy Thursday, 3 days before Easter 99 * {@literal @}draft ICU 2.8 100 * {@literal @}provisional This API might change or be removed in a future release. 101 * @hide draft / provisional / internal are hidden on Android 102 */ 103 static public final EasterHoliday MAUNDY_THURSDAY = new EasterHoliday( -3, "Maundy Thursday"); 104 105 /** 106 * Good Friday, 2 days before Easter 107 * {@literal @}draft ICU 2.8 108 * {@literal @}provisional This API might change or be removed in a future release. 109 * @hide draft / provisional / internal are hidden on Android 110 */ 111 static public final EasterHoliday GOOD_FRIDAY = new EasterHoliday( -2, "Good Friday"); 112 113 /** 114 * Easter Sunday 115 * {@literal @}draft ICU 2.8 116 * {@literal @}provisional This API might change or be removed in a future release. 117 * @hide draft / provisional / internal are hidden on Android 118 */ 119 static public final EasterHoliday EASTER_SUNDAY = new EasterHoliday( 0, "Easter Sunday"); 120 121 /** 122 * Easter Monday, 1 day after Easter 123 * {@literal @}draft ICU 2.8 124 * {@literal @}provisional This API might change or be removed in a future release. 125 * @hide draft / provisional / internal are hidden on Android 126 */ 127 static public final EasterHoliday EASTER_MONDAY = new EasterHoliday( 1, "Easter Monday"); 128 129 /** 130 * Ascension, 39 days after Easter 131 * {@literal @}draft ICU 2.8 132 * {@literal @}provisional This API might change or be removed in a future release. 133 * @hide draft / provisional / internal are hidden on Android 134 */ 135 static public final EasterHoliday ASCENSION = new EasterHoliday( 39, "Ascension"); 136 137 /** 138 * Pentecost (aka Whit Sunday), 49 days after Easter 139 * {@literal @}draft ICU 2.8 140 * {@literal @}provisional This API might change or be removed in a future release. 141 * @hide draft / provisional / internal are hidden on Android 142 */ 143 static public final EasterHoliday PENTECOST = new EasterHoliday( 49, "Pentecost"); 144 145 /** 146 * Whit Sunday (aka Pentecost), 49 days after Easter 147 * {@literal @}draft ICU 2.8 148 * {@literal @}provisional This API might change or be removed in a future release. 149 * @hide draft / provisional / internal are hidden on Android 150 */ 151 static public final EasterHoliday WHIT_SUNDAY = new EasterHoliday( 49, "Whit Sunday"); 152 153 /** 154 * Whit Monday, 50 days after Easter 155 * {@literal @}draft ICU 2.8 156 * {@literal @}provisional This API might change or be removed in a future release. 157 * @hide draft / provisional / internal are hidden on Android 158 */ 159 static public final EasterHoliday WHIT_MONDAY = new EasterHoliday( 50, "Whit Monday"); 160 161 /** 162 * Corpus Christi, 60 days after Easter 163 * {@literal @}draft ICU 2.8 164 * {@literal @}provisional This API might change or be removed in a future release. 165 * @hide draft / provisional / internal are hidden on Android 166 */ 167 static public final EasterHoliday CORPUS_CHRISTI = new EasterHoliday( 60, "Corpus Christi"); 168} 169 170class EasterRule implements DateRule { 171 public EasterRule(int daysAfterEaster, boolean isOrthodox) { 172 this.daysAfterEaster = daysAfterEaster; 173 if (isOrthodox) { 174 orthodox.setGregorianChange(new Date(Long.MAX_VALUE)); 175 calendar = orthodox; 176 } 177 } 178 179 /** 180 * Return the first occurrance of this rule on or after the given date 181 */ 182 public Date firstAfter(Date start) 183 { 184 return doFirstBetween(start, null); 185 } 186 187 /** 188 * Return the first occurrance of this rule on or after 189 * the given start date and before the given end date. 190 */ 191 public Date firstBetween(Date start, Date end) 192 { 193 return doFirstBetween(start, end); 194 } 195 196 /** 197 * Return true if the given Date is on the same day as Easter 198 */ 199 public boolean isOn(Date date) 200 { 201 synchronized(calendar) { 202 calendar.setTime(date); 203 int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR); 204 205 calendar.setTime(computeInYear(calendar.getTime(), calendar)); 206 207 return calendar.get(Calendar.DAY_OF_YEAR) == dayOfYear; 208 } 209 } 210 211 /** 212 * Return true if Easter occurs between the two dates given 213 */ 214 public boolean isBetween(Date start, Date end) 215 { 216 return firstBetween(start, end) != null; // TODO: optimize? 217 } 218 219 private Date doFirstBetween(Date start, Date end) 220 { 221 //System.out.println("doFirstBetween: start = " + start.toString()); 222 //System.out.println("doFirstBetween: end = " + end.toString()); 223 224 synchronized(calendar) { 225 // Figure out when this holiday lands in the given year 226 Date result = computeInYear(start, calendar); 227 228 //System.out.println(" result = " + result.toString()); 229 230 // We might have gotten a date that's in the same year as "start", but 231 // earlier in the year. If so, go to next year 232 if (result.before(start)) 233 { 234 calendar.setTime(start); 235 calendar.get(Calendar.YEAR); // JDK 1.1.2 bug workaround 236 calendar.add(Calendar.YEAR, 1); 237 238 //System.out.println(" Result before start, going to next year: " 239 // + calendar.getTime().toString()); 240 241 result = computeInYear(calendar.getTime(), calendar); 242 //System.out.println(" result = " + result.toString()); 243 } 244 245 if (end != null && !result.before(end)) { 246 //System.out.println("Result after end, returning null"); 247 return null; 248 } 249 return result; 250 } 251 } 252 253 /** 254 * Compute the month and date on which this holiday falls in the year 255 * containing the date "date". First figure out which date Easter 256 * lands on in this year, and then add the offset for this holiday to get 257 * the right date. 258 * <p> 259 * The algorithm here is taken from the 260 * <a href="http://www.faqs.org/faqs/calendars/faq/">Calendar FAQ</a>. 261 */ 262 private Date computeInYear(Date date, GregorianCalendar cal) 263 { 264 if (cal == null) cal = calendar; 265 266 synchronized(cal) { 267 cal.setTime(date); 268 269 int year = cal.get(Calendar.YEAR); 270 int g = year % 19; // "Golden Number" of year - 1 271 int i = 0; // # of days from 3/21 to the Paschal full moon 272 int j = 0; // Weekday (0-based) of Paschal full moon 273 274 if (cal.getTime().after( cal.getGregorianChange())) 275 { 276 // We're past the Gregorian switchover, so use the Gregorian rules. 277 int c = year / 100; 278 int h = (c - c/4 - (8*c+13)/25 + 19*g + 15) % 30; 279 i = h - (h/28)*(1 - (h/28)*(29/(h+1))*((21-g)/11)); 280 j = (year + year/4 + i + 2 - c + c/4) % 7; 281 } 282 else 283 { 284 // Use the old Julian rules. 285 i = (19*g + 15) % 30; 286 j = (year + year/4 + i) % 7; 287 } 288 int l = i - j; 289 int m = 3 + (l+40)/44; // 1-based month in which Easter falls 290 int d = l + 28 - 31*(m/4); // Date of Easter within that month 291 292 cal.clear(); 293 cal.set(Calendar.ERA, GregorianCalendar.AD); 294 cal.set(Calendar.YEAR, year); 295 cal.set(Calendar.MONTH, m-1); // 0-based 296 cal.set(Calendar.DATE, d); 297 cal.getTime(); // JDK 1.1.2 bug workaround 298 cal.add(Calendar.DATE, daysAfterEaster); 299 300 return cal.getTime(); 301 } 302 } 303 304 private static GregorianCalendar gregorian = new GregorianCalendar(/* new SimpleTimeZone(0, "UTC") */); 305 private static GregorianCalendar orthodox = new GregorianCalendar(/* new SimpleTimeZone(0, "UTC") */); 306 307 private int daysAfterEaster; 308 private GregorianCalendar calendar = gregorian; 309} 310