KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibm > icu > util > EasterHoliday


1 /*
2  *******************************************************************************
3  * Copyright (C) 1996-2006, International Business Machines Corporation and *
4  * others. All Rights Reserved. *
5  *******************************************************************************
6  */

7
8 package com.ibm.icu.util;
9
10 import java.util.Date JavaDoc;
11
12 /**
13  * A Holiday subclass which represents holidays that occur
14  * a fixed number of days before or after Easter. Supports both the
15  * Western and Orthodox methods for calculating Easter.
16  * @draft ICU 2.8 (retainAll)
17  * @provisional This API might change or be removed in a future release.
18  */

19 public class EasterHoliday extends Holiday
20 {
21     /**
22      * Construct a holiday that falls on Easter Sunday every year
23      *
24      * @param name The name of the holiday
25      * @draft ICU 2.8
26      * @provisional This API might change or be removed in a future release.
27      */

28     public EasterHoliday(String JavaDoc name)
29     {
30         super(name, new EasterRule(0, false));
31     }
32
33     /**
34      * Construct a holiday that falls a specified number of days before
35      * or after Easter Sunday each year.
36      *
37      * @param daysAfter The number of days before (-) or after (+) Easter
38      * @param name The name of the holiday
39      * @draft ICU 2.8
40      * @provisional This API might change or be removed in a future release.
41      */

42     public EasterHoliday(int daysAfter, String JavaDoc name)
43     {
44         super(name, new EasterRule(daysAfter, false));
45     }
46
47     /**
48      * Construct a holiday that falls a specified number of days before
49      * or after Easter Sunday each year, using either the Western
50      * or Orthodox calendar.
51      *
52      * @param daysAfter The number of days before (-) or after (+) Easter
53      * @param orthodox Use the Orthodox calendar?
54      * @param name The name of the holiday
55      * @draft ICU 2.8
56      * @provisional This API might change or be removed in a future release.
57      */

58     public EasterHoliday(int daysAfter, boolean orthodox, String JavaDoc name)
59     {
60         super(name, new EasterRule(daysAfter, orthodox));
61     }
62
63     /**
64      * Shrove Tuesday, aka Mardi Gras, 48 days before Easter
65      * @draft ICU 2.8
66      * @provisional This API might change or be removed in a future release.
67      */

68     static public final EasterHoliday SHROVE_TUESDAY = new EasterHoliday(-48, "Shrove Tuesday");
69
70     /**
71      * Ash Wednesday, start of Lent, 47 days before Easter
72      * @draft ICU 2.8
73      * @provisional This API might change or be removed in a future release.
74      */

75     static public final EasterHoliday ASH_WEDNESDAY = new EasterHoliday(-47, "Ash Wednesday");
76
77     /**
78      * Palm Sunday, 7 days before Easter
79      * @draft ICU 2.8
80      * @provisional This API might change or be removed in a future release.
81      */

82     static public final EasterHoliday PALM_SUNDAY = new EasterHoliday( -7, "Palm Sunday");
83
84     /**
85      * Maundy Thursday, 3 days before Easter
86      * @draft ICU 2.8
87      * @provisional This API might change or be removed in a future release.
88      */

89     static public final EasterHoliday MAUNDY_THURSDAY = new EasterHoliday( -3, "Maundy Thursday");
90
91     /**
92      * Good Friday, 2 days before Easter
93      * @draft ICU 2.8
94      * @provisional This API might change or be removed in a future release.
95      */

96     static public final EasterHoliday GOOD_FRIDAY = new EasterHoliday( -2, "Good Friday");
97
98     /**
99      * Easter Sunday
100      * @draft ICU 2.8
101      * @provisional This API might change or be removed in a future release.
102      */

103     static public final EasterHoliday EASTER_SUNDAY = new EasterHoliday( 0, "Easter Sunday");
104
105     /**
106      * Easter Monday, 1 day after Easter
107      * @draft ICU 2.8
108      * @provisional This API might change or be removed in a future release.
109      */

110     static public final EasterHoliday EASTER_MONDAY = new EasterHoliday( 1, "Easter Monday");
111
112     /**
113      * Ascension, 39 days after Easter
114      * @draft ICU 2.8
115      * @provisional This API might change or be removed in a future release.
116      */

117     static public final EasterHoliday ASCENSION = new EasterHoliday( 39, "Ascension");
118
119     /**
120      * Pentecost (aka Whit Sunday), 49 days after Easter
121      * @draft ICU 2.8
122      * @provisional This API might change or be removed in a future release.
123      */

124     static public final EasterHoliday PENTECOST = new EasterHoliday( 49, "Pentecost");
125
126     /**
127      * Whit Sunday (aka Pentecost), 49 days after Easter
128      * @draft ICU 2.8
129      * @provisional This API might change or be removed in a future release.
130      */

131     static public final EasterHoliday WHIT_SUNDAY = new EasterHoliday( 49, "Whit Sunday");
132
133     /**
134      * Whit Monday, 50 days after Easter
135      * @draft ICU 2.8
136      * @provisional This API might change or be removed in a future release.
137      */

138     static public final EasterHoliday WHIT_MONDAY = new EasterHoliday( 50, "Whit Monday");
139
140     /**
141      * Corpus Christi, 60 days after Easter
142      * @draft ICU 2.8
143      * @provisional This API might change or be removed in a future release.
144      */

145     static public final EasterHoliday CORPUS_CHRISTI = new EasterHoliday( 60, "Corpus Christi");
146 }
147
148 class EasterRule implements DateRule {
149     public EasterRule(int daysAfterEaster, boolean isOrthodox) {
150         this.daysAfterEaster = daysAfterEaster;
151         if (isOrthodox) {
152             orthodox.setGregorianChange(new Date JavaDoc(Long.MAX_VALUE));
153             calendar = orthodox;
154         }
155     }
156
157     /**
158      * Return the first occurrance of this rule on or after the given date
159      */

160     public Date JavaDoc firstAfter(Date JavaDoc start)
161     {
162         return doFirstBetween(start, null);
163     }
164
165     /**
166      * Return the first occurrance of this rule on or after
167      * the given start date and before the given end date.
168      */

169     public Date JavaDoc firstBetween(Date JavaDoc start, Date JavaDoc end)
170     {
171         return doFirstBetween(start, end);
172     }
173
174     /**
175      * Return true if the given Date is on the same day as Easter
176      */

177     public boolean isOn(Date JavaDoc date)
178     {
179         synchronized(calendar) {
180             calendar.setTime(date);
181             int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
182
183             calendar.setTime(computeInYear(calendar.getTime(), calendar));
184
185             return calendar.get(Calendar.DAY_OF_YEAR) == dayOfYear;
186         }
187     }
188
189     /**
190      * Return true if Easter occurs between the two dates given
191      */

192     public boolean isBetween(Date JavaDoc start, Date JavaDoc end)
193     {
194         return firstBetween(start, end) != null; // TODO: optimize?
195
}
196
197     private Date JavaDoc doFirstBetween(Date JavaDoc start, Date JavaDoc end)
198     {
199         //System.out.println("doFirstBetween: start = " + start.toString());
200
//System.out.println("doFirstBetween: end = " + end.toString());
201

202         synchronized(calendar) {
203             // Figure out when this holiday lands in the given year
204
Date JavaDoc result = computeInYear(start, calendar);
205
206          //System.out.println(" result = " + result.toString());
207

208             // We might have gotten a date that's in the same year as "start", but
209
// earlier in the year. If so, go to next year
210
if (result.before(start))
211             {
212                 calendar.setTime(start);
213                 calendar.get(Calendar.YEAR); // JDK 1.1.2 bug workaround
214
calendar.add(Calendar.YEAR, 1);
215
216                 //System.out.println(" Result before start, going to next year: "
217
// + calendar.getTime().toString());
218

219                 result = computeInYear(calendar.getTime(), calendar);
220                 //System.out.println(" result = " + result.toString());
221
}
222
223             if (end != null && result.after(end)) {
224                 //System.out.println("Result after end, returning null");
225
return null;
226             }
227             return result;
228         }
229     }
230
231     /**
232      * Compute the month and date on which this holiday falls in the year
233      * containing the date "date". First figure out which date Easter
234      * lands on in this year, and then add the offset for this holiday to get
235      * the right date.
236      * <p>
237      * The algorithm here is taken from the
238      * <a HREF="http://www.faqs.org/faqs/calendars/faq/">Calendar FAQ</a>.
239      */

240     private Date JavaDoc computeInYear(Date JavaDoc date, GregorianCalendar cal)
241     {
242         if (cal == null) cal = calendar;
243
244         synchronized(cal) {
245             cal.setTime(date);
246
247             int year = cal.get(Calendar.YEAR);
248             int g = year % 19; // "Golden Number" of year - 1
249
int i = 0; // # of days from 3/21 to the Paschal full moon
250
int j = 0; // Weekday (0-based) of Paschal full moon
251

252             if (cal.getTime().after( cal.getGregorianChange()))
253             {
254                 // We're past the Gregorian switchover, so use the Gregorian rules.
255
int c = year / 100;
256                 int h = (c - c/4 - (8*c+13)/25 + 19*g + 15) % 30;
257                 i = h - (h/28)*(1 - (h/28)*(29/(h+1))*((21-g)/11));
258                 j = (year + year/4 + i + 2 - c + c/4) % 7;
259             }
260             else
261             {
262                 // Use the old Julian rules.
263
i = (19*g + 15) % 30;
264                 j = (year + year/4 + i) % 7;
265             }
266             int l = i - j;
267             int m = 3 + (l+40)/44; // 1-based month in which Easter falls
268
int d = l + 28 - 31*(m/4); // Date of Easter within that month
269

270             cal.clear();
271             cal.set(Calendar.ERA, GregorianCalendar.AD);
272             cal.set(Calendar.YEAR, year);
273             cal.set(Calendar.MONTH, m-1); // 0-based
274
cal.set(Calendar.DATE, d);
275             cal.getTime(); // JDK 1.1.2 bug workaround
276
cal.add(Calendar.DATE, daysAfterEaster);
277
278             return cal.getTime();
279         }
280     }
281
282     private static GregorianCalendar gregorian = new GregorianCalendar(/* new SimpleTimeZone(0, "UTC") */);
283     private static GregorianCalendar orthodox = new GregorianCalendar(/* new SimpleTimeZone(0, "UTC") */);
284
285     private int daysAfterEaster;
286     private GregorianCalendar calendar = gregorian;
287 }
288
Popular Tags