12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others. 22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 1996-2014, International Business Machines Corporation and * 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved. * 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.util; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Date; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <b>Note:</b> The Holiday framework is a technology preview. 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Despite its age, is still draft API, and clients should treat it as such. 172d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A Holiday subclass which represents holidays that occur 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a fixed number of days before or after Easter. Supports both the 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Western and Orthodox methods for calculating Easter. 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 (retainAll) 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class EasterHoliday extends Holiday 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert{ 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct a holiday that falls on Easter Sunday every year 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param name The name of the holiday 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public EasterHoliday(String name) 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(name, new EasterRule(0, false)); 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct a holiday that falls a specified number of days before 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or after Easter Sunday each year. 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param daysAfter The number of days before (-) or after (+) Easter 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param name The name of the holiday 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public EasterHoliday(int daysAfter, String name) 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(name, new EasterRule(daysAfter, false)); 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct a holiday that falls a specified number of days before 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or after Easter Sunday each year, using either the Western 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or Orthodox calendar. 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param daysAfter The number of days before (-) or after (+) Easter 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param orthodox Use the Orthodox calendar? 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param name The name of the holiday 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public EasterHoliday(int daysAfter, boolean orthodox, String name) 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(name, new EasterRule(daysAfter, orthodox)); 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Shrove Tuesday, aka Mardi Gras, 48 days before Easter 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday SHROVE_TUESDAY = new EasterHoliday(-48, "Shrove Tuesday"); 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Ash Wednesday, start of Lent, 47 days before Easter 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday ASH_WEDNESDAY = new EasterHoliday(-47, "Ash Wednesday"); 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Palm Sunday, 7 days before Easter 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday PALM_SUNDAY = new EasterHoliday( -7, "Palm Sunday"); 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Maundy Thursday, 3 days before Easter 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday MAUNDY_THURSDAY = new EasterHoliday( -3, "Maundy Thursday"); 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Good Friday, 2 days before Easter 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday GOOD_FRIDAY = new EasterHoliday( -2, "Good Friday"); 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Easter Sunday 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday EASTER_SUNDAY = new EasterHoliday( 0, "Easter Sunday"); 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Easter Monday, 1 day after Easter 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday EASTER_MONDAY = new EasterHoliday( 1, "Easter Monday"); 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Ascension, 39 days after Easter 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday ASCENSION = new EasterHoliday( 39, "Ascension"); 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Pentecost (aka Whit Sunday), 49 days after Easter 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday PENTECOST = new EasterHoliday( 49, "Pentecost"); 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Whit Sunday (aka Pentecost), 49 days after Easter 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday WHIT_SUNDAY = new EasterHoliday( 49, "Whit Sunday"); 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Whit Monday, 50 days after Easter 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday WHIT_MONDAY = new EasterHoliday( 50, "Whit Monday"); 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Corpus Christi, 60 days after Easter 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final EasterHoliday CORPUS_CHRISTI = new EasterHoliday( 60, "Corpus Christi"); 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertclass EasterRule implements DateRule { 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public EasterRule(int daysAfterEaster, boolean isOrthodox) { 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.daysAfterEaster = daysAfterEaster; 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isOrthodox) { 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert orthodox.setGregorianChange(new Date(Long.MAX_VALUE)); 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert calendar = orthodox; 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1632d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * Return the first occurrence of this rule on or after the given date 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1652d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Date firstAfter(Date start) 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return doFirstBetween(start, null); 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1722d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * Return the first occurrence of this rule on or after 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the given start date and before the given end date. 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1752d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Date firstBetween(Date start, Date end) 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return doFirstBetween(start, end); 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return true if the given Date is on the same day as Easter 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1842d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isOn(Date date) 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized(calendar) { 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert calendar.setTime(date); 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR); 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert calendar.setTime(computeInYear(calendar.getTime(), calendar)); 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return calendar.get(Calendar.DAY_OF_YEAR) == dayOfYear; 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return true if Easter occurs between the two dates given 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2002d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isBetween(Date start, Date end) 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return firstBetween(start, end) != null; // TODO: optimize? 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Date doFirstBetween(Date start, Date end) 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //System.out.println("doFirstBetween: start = " + start.toString()); 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //System.out.println("doFirstBetween: end = " + end.toString()); 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized(calendar) { 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Figure out when this holiday lands in the given year 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Date result = computeInYear(start, calendar); 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //System.out.println(" result = " + result.toString()); 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We might have gotten a date that's in the same year as "start", but 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // earlier in the year. If so, go to next year 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result.before(start)) 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert calendar.setTime(start); 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert calendar.get(Calendar.YEAR); // JDK 1.1.2 bug workaround 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert calendar.add(Calendar.YEAR, 1); 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //System.out.println(" Result before start, going to next year: " 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // + calendar.getTime().toString()); 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result = computeInYear(calendar.getTime(), calendar); 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //System.out.println(" result = " + result.toString()); 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 232f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert if (end != null && !result.before(end)) { 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //System.out.println("Result after end, returning null"); 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Compute the month and date on which this holiday falls in the year 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * containing the date "date". First figure out which date Easter 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * lands on in this year, and then add the offset for this holiday to get 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the right date. 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The algorithm here is taken from the 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <a href="http://www.faqs.org/faqs/calendars/faq/">Calendar FAQ</a>. 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Date computeInYear(Date date, GregorianCalendar cal) 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cal == null) cal = calendar; 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized(cal) { 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.setTime(date); 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int year = cal.get(Calendar.YEAR); 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int g = year % 19; // "Golden Number" of year - 1 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int i = 0; // # of days from 3/21 to the Paschal full moon 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int j = 0; // Weekday (0-based) of Paschal full moon 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cal.getTime().after( cal.getGregorianChange())) 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We're past the Gregorian switchover, so use the Gregorian rules. 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int c = year / 100; 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int h = (c - c/4 - (8*c+13)/25 + 19*g + 15) % 30; 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert i = h - (h/28)*(1 - (h/28)*(29/(h+1))*((21-g)/11)); 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert j = (year + year/4 + i + 2 - c + c/4) % 7; 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Use the old Julian rules. 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert i = (19*g + 15) % 30; 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert j = (year + year/4 + i) % 7; 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int l = i - j; 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int m = 3 + (l+40)/44; // 1-based month in which Easter falls 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int d = l + 28 - 31*(m/4); // Date of Easter within that month 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.clear(); 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.set(Calendar.ERA, GregorianCalendar.AD); 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.set(Calendar.YEAR, year); 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.set(Calendar.MONTH, m-1); // 0-based 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.set(Calendar.DATE, d); 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.getTime(); // JDK 1.1.2 bug workaround 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.add(Calendar.DATE, daysAfterEaster); 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return cal.getTime(); 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static GregorianCalendar gregorian = new GregorianCalendar(/* new SimpleTimeZone(0, "UTC") */); 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static GregorianCalendar orthodox = new GregorianCalendar(/* new SimpleTimeZone(0, "UTC") */); 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int daysAfterEaster; 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private GregorianCalendar calendar = gregorian; 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 297