Source Code Cross Referenced for HebrewCalendar.java in  » Internationalization-Localization » icu4j » com » ibm » icu » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Internationalization Localization » icu4j » com.ibm.icu.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *******************************************************************************
003:         * Copyright (C) 1996-2006, International Business Machines Corporation and    *
004:         * others. All Rights Reserved.                                                *
005:         *******************************************************************************
006:         */
007:        package com.ibm.icu.util;
008:
009:        import com.ibm.icu.util.TimeZone;
010:        import com.ibm.icu.impl.CalendarCache;
011:        import java.util.Date;
012:        import java.util.Locale;
013:
014:        /**
015:         * <code>HebrewCalendar</code> is a subclass of <code>Calendar</code>
016:         * that that implements the traditional Hebrew calendar.
017:         * This is the civil calendar in Israel and the liturgical calendar
018:         * of the Jewish faith worldwide.
019:         * <p>
020:         * The Hebrew calendar is lunisolar and thus has a number of interesting
021:         * properties that distinguish it from the Gregorian.  Months start
022:         * on the day of (an arithmetic approximation of) each new moon.  Since the
023:         * solar year (approximately 365.24 days) is not an even multiple of
024:         * the lunar month (approximately 29.53 days) an extra "leap month" is
025:         * inserted in 7 out of every 19 years.  To make matters even more
026:         * interesting, the start of a year can be delayed by up to three days
027:         * in order to prevent certain holidays from falling on the Sabbath and
028:         * to prevent certain illegal year lengths.  Finally, the lengths of certain
029:         * months can vary depending on the number of days in the year.
030:         * <p>
031:         * The leap month is known as "Adar 1" and is inserted between the
032:         * months of Shevat and Adar in leap years.  Since the leap month does
033:         * not come at the end of the year, calculations involving
034:         * month numbers are particularly complex.  Users of this class should
035:         * make sure to use the {@link #roll roll} and {@link #add add} methods
036:         * rather than attempting to perform date arithmetic by manipulating
037:         * the fields directly.
038:         * <p>
039:         * <b>Note:</b> In the traditional Hebrew calendar, days start at sunset.
040:         * However, in order to keep the time fields in this class
041:         * synchronized with those of the other calendars and with local clock time,
042:         * we treat days and months as beginning at midnight,
043:         * roughly 6 hours after the corresponding sunset.
044:         * <p>
045:         * If you are interested in more information on the rules behind the Hebrew
046:         * calendar, see one of the following references:
047:         * <ul>
048:         * <li>"<a href="http://www.amazon.com/exec/obidos/ASIN/0521564743">Calendrical Calculations</a>",
049:         *      by Nachum Dershowitz & Edward Reingold, Cambridge University Press, 1997, pages 85-91.
050:         *
051:         * <li>Hebrew Calendar Science and Myths,
052:         *      <a href="http://www.geocities.com/Athens/1584/">
053:         *      http://www.geocities.com/Athens/1584/</a>
054:         *
055:         * <li>The Calendar FAQ,
056:         *      <a href="http://www.faqs.org/faqs/calendars/faq/">
057:         *      http://www.faqs.org/faqs/calendars/faq/</a>
058:         * </ul>
059:         *
060:         * <p>
061:         * This class should not be subclassed.</p>
062:         * <p>
063:         * HebrewCalendar usually should be instantiated using 
064:         * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
065:         * with the tag <code>"@calendar=hebrew"</code>.</p>
066:         *
067:         * @see com.ibm.icu.util.GregorianCalendar
068:         * @see com.ibm.icu.util.Calendar
069:         *
070:         * @author Laura Werner
071:         * @author Alan Liu
072:         * @stable ICU 2.8
073:         */
074:        public class HebrewCalendar extends Calendar {
075:            // jdk1.4.2 serialver
076:            private static final long serialVersionUID = -1952524560588825816L;
077:
078:            private static String copyright = "Copyright \u00a9 1997-1998 IBM Corp. All Rights Reserved.";
079:
080:            //-------------------------------------------------------------------------
081:            // Tons o' Constants...
082:            //-------------------------------------------------------------------------
083:
084:            /** 
085:             * Constant for Tishri, the 1st month of the Hebrew year. 
086:             * @stable ICU 2.8 
087:             */
088:            public static final int TISHRI = 0;
089:
090:            /**
091:             * Constant for Heshvan, the 2nd month of the Hebrew year. 
092:             * @stable ICU 2.8 
093:             */
094:            public static final int HESHVAN = 1;
095:
096:            /**
097:             * Constant for Kislev, the 3rd month of the Hebrew year. 
098:             * @stable ICU 2.8 
099:             */
100:            public static final int KISLEV = 2;
101:
102:            /**
103:             * Constant for Tevet, the 4th month of the Hebrew year. 
104:             * @stable ICU 2.8 
105:             */
106:            public static final int TEVET = 3;
107:
108:            /**
109:             * Constant for Shevat, the 5th month of the Hebrew year. 
110:             * @stable ICU 2.8 
111:             */
112:            public static final int SHEVAT = 4;
113:
114:            /**
115:             * Constant for Adar I, the 6th month of the Hebrew year
116:             * (present in leap years only). In non-leap years, the calendar
117:             * jumps from Shevat (5th month) to Adar (7th month).
118:             * @stable ICU 2.8
119:             */
120:            public static final int ADAR_1 = 5;
121:
122:            /** 
123:             * Constant for the Adar, the 7th month of the Hebrew year. 
124:             * @stable ICU 2.8 
125:             */
126:            public static final int ADAR = 6;
127:
128:            /**
129:             * Constant for Nisan, the 8th month of the Hebrew year. 
130:             * @stable ICU 2.8 
131:             */
132:            public static final int NISAN = 7;
133:
134:            /**
135:             * Constant for Iyar, the 9th month of the Hebrew year. 
136:             * @stable ICU 2.8 
137:             */
138:            public static final int IYAR = 8;
139:
140:            /**
141:             * Constant for Sivan, the 10th month of the Hebrew year. 
142:             * @stable ICU 2.8 
143:             */
144:            public static final int SIVAN = 9;
145:
146:            /**
147:             * Constant for Tammuz, the 11th month of the Hebrew year. 
148:             * @stable ICU 2.8 
149:             */
150:            public static final int TAMUZ = 10;
151:
152:            /**
153:             * Constant for Av, the 12th month of the Hebrew year. 
154:             * @stable ICU 2.8 
155:             */
156:            public static final int AV = 11;
157:
158:            /**
159:             * Constant for Elul, the 13th month of the Hebrew year. 
160:             * @stable ICU 2.8 
161:             */
162:            public static final int ELUL = 12;
163:
164:            /**
165:             * The absolute date, in milliseconds since 1/1/1970 AD, Gregorian,
166:             * of the start of the Hebrew calendar.  In order to keep this calendar's
167:             * time of day in sync with that of the Gregorian calendar, we use
168:             * midnight, rather than sunset the day before.
169:             */
170:            //private static final long EPOCH_MILLIS = -180799862400000L; // 1/1/1 HY
171:            private static final int LIMITS[][] = {
172:            // Minimum  Greatest    Least  Maximum
173:                    //           Minimum  Maximum
174:                    { 0, 0, 0, 0 }, // ERA
175:                    { 1, 1, 5000000, 5000000 }, // YEAR
176:                    { 0, 0, 12, 12 }, // MONTH
177:                    { 1, 1, 51, 56 }, // WEEK_OF_YEAR
178:                    { 0, 0, 5, 6 }, // WEEK_OF_MONTH
179:                    { 1, 1, 29, 30 }, // DAY_OF_MONTH
180:                    { 1, 1, 353, 385 }, // DAY_OF_YEAR
181:                    {/*                                  */}, // DAY_OF_WEEK
182:                    { -1, -1, 4, 6 }, // DAY_OF_WEEK_IN_MONTH
183:                    {/*                                  */}, // AM_PM
184:                    {/*                                  */}, // HOUR
185:                    {/*                                  */}, // HOUR_OF_DAY
186:                    {/*                                  */}, // MINUTE
187:                    {/*                                  */}, // SECOND
188:                    {/*                                  */}, // MILLISECOND
189:                    {/*                                  */}, // ZONE_OFFSET
190:                    {/*                                  */}, // DST_OFFSET
191:                    { -5000001, -5000001, 5000001, 5000001 }, // YEAR_WOY
192:                    {/*                                  */}, // DOW_LOCAL
193:                    { -5000000, -5000000, 5000000, 5000000 }, // EXTENDED_YEAR
194:                    {/*                                  */}, // JULIAN_DAY
195:                    {/*                                  */}, // MILLISECONDS_IN_DAY
196:            };
197:
198:            /**
199:             * The lengths of the Hebrew months.  This is complicated, because there
200:             * are three different types of years, or six if you count leap years.
201:             * Due to the rules for postponing the start of the year to avoid having
202:             * certain holidays fall on the sabbath, the year can end up being three
203:             * different lengths, called "deficient", "normal", and "complete".
204:             */
205:            private static final int MONTH_LENGTH[][] = {
206:            // Deficient  Normal     Complete
207:                    { 30, 30, 30 }, //Tishri
208:                    { 29, 29, 30 }, //Heshvan
209:                    { 29, 30, 30 }, //Kislev
210:                    { 29, 29, 29 }, //Tevet
211:                    { 30, 30, 30 }, //Shevat
212:                    { 30, 30, 30 }, //Adar I (leap years only)
213:                    { 29, 29, 29 }, //Adar
214:                    { 30, 30, 30 }, //Nisan
215:                    { 29, 29, 29 }, //Iyar
216:                    { 30, 30, 30 }, //Sivan
217:                    { 29, 29, 29 }, //Tammuz
218:                    { 30, 30, 30 }, //Av
219:                    { 29, 29, 29 }, //Elul
220:            };
221:
222:            /**
223:             * The cumulative # of days to the end of each month in a non-leap year
224:             * Although this can be calculated from the MONTH_LENGTH table,
225:             * keeping it around separately makes some calculations a lot faster
226:             */
227:            private static final int MONTH_START[][] = {
228:            // Deficient  Normal     Complete
229:                    { 0, 0, 0 }, // (placeholder)
230:                    { 30, 30, 30 }, // Tishri
231:                    { 59, 59, 60 }, // Heshvan
232:                    { 88, 89, 90 }, // Kislev
233:                    { 117, 118, 119 }, // Tevet
234:                    { 147, 148, 149 }, // Shevat
235:                    { 147, 148, 149 }, // (Adar I placeholder)
236:                    { 176, 177, 178 }, // Adar
237:                    { 206, 207, 208 }, // Nisan
238:                    { 235, 236, 237 }, // Iyar
239:                    { 265, 266, 267 }, // Sivan
240:                    { 294, 295, 296 }, // Tammuz
241:                    { 324, 325, 326 }, // Av
242:                    { 353, 354, 355 }, // Elul
243:            };
244:
245:            /**
246:             * The cumulative # of days to the end of each month in a leap year
247:             */
248:            private static final int LEAP_MONTH_START[][] = {
249:            // Deficient  Normal     Complete
250:                    { 0, 0, 0 }, // (placeholder)
251:                    { 30, 30, 30 }, // Tishri
252:                    { 59, 59, 60 }, // Heshvan
253:                    { 88, 89, 90 }, // Kislev
254:                    { 117, 118, 119 }, // Tevet
255:                    { 147, 148, 149 }, // Shevat
256:                    { 177, 178, 179 }, // Adar I
257:                    { 206, 207, 208 }, // Adar II
258:                    { 236, 237, 238 }, // Nisan
259:                    { 265, 266, 267 }, // Iyar
260:                    { 295, 296, 297 }, // Sivan
261:                    { 324, 325, 326 }, // Tammuz
262:                    { 354, 355, 356 }, // Av
263:                    { 383, 384, 385 }, // Elul
264:            };
265:
266:            //-------------------------------------------------------------------------
267:            // Data Members...
268:            //-------------------------------------------------------------------------
269:
270:            private static CalendarCache cache = new CalendarCache();
271:
272:            //-------------------------------------------------------------------------
273:            // Constructors...
274:            //-------------------------------------------------------------------------
275:
276:            /**
277:             * Constructs a default <code>HebrewCalendar</code> using the current time
278:             * in the default time zone with the default locale.
279:             * @stable ICU 2.8
280:             */
281:            public HebrewCalendar() {
282:                this (TimeZone.getDefault(), ULocale.getDefault());
283:            }
284:
285:            /**
286:             * Constructs a <code>HebrewCalendar</code> based on the current time
287:             * in the given time zone with the default locale.
288:             *
289:             * @param zone The time zone for the new calendar.
290:             * @stable ICU 2.8
291:             */
292:            public HebrewCalendar(TimeZone zone) {
293:                this (zone, ULocale.getDefault());
294:            }
295:
296:            /**
297:             * Constructs a <code>HebrewCalendar</code> based on the current time
298:             * in the default time zone with the given locale.
299:             *
300:             * @param aLocale The locale for the new calendar.
301:             * @stable ICU 2.8
302:             */
303:            public HebrewCalendar(Locale aLocale) {
304:                this (TimeZone.getDefault(), aLocale);
305:            }
306:
307:            /**
308:             * Constructs a <code>HebrewCalendar</code> based on the current time
309:             * in the default time zone with the given locale.
310:             *
311:             * @param locale The locale for the new calendar.
312:             * @draft ICU 3.2
313:             * @provisional This API might change or be removed in a future release.
314:             */
315:            public HebrewCalendar(ULocale locale) {
316:                this (TimeZone.getDefault(), locale);
317:            }
318:
319:            /**
320:             * Constructs a <code>HebrewCalendar</code> based on the current time
321:             * in the given time zone with the given locale.
322:             *
323:             * @param zone The time zone for the new calendar.
324:             *
325:             * @param aLocale The locale for the new calendar.
326:             * @stable ICU 2.8
327:             */
328:            public HebrewCalendar(TimeZone zone, Locale aLocale) {
329:                super (zone, aLocale);
330:                setTimeInMillis(System.currentTimeMillis());
331:            }
332:
333:            /**
334:             * Constructs a <code>HebrewCalendar</code> based on the current time
335:             * in the given time zone with the given locale.
336:             *
337:             * @param zone The time zone for the new calendar.
338:             *
339:             * @param locale The locale for the new calendar.
340:             * @draft ICU 3.2
341:             * @provisional This API might change or be removed in a future release.
342:             */
343:            public HebrewCalendar(TimeZone zone, ULocale locale) {
344:                super (zone, locale);
345:                setTimeInMillis(System.currentTimeMillis());
346:            }
347:
348:            /**
349:             * Constructs a <code>HebrewCalendar</code> with the given date set
350:             * in the default time zone with the default locale.
351:             *
352:             * @param year      The value used to set the calendar's {@link #YEAR YEAR} time field.
353:             *
354:             * @param month     The value used to set the calendar's {@link #MONTH MONTH} time field.
355:             *                  The value is 0-based. e.g., 0 for Tishri.
356:             *
357:             * @param date      The value used to set the calendar's {@link #DATE DATE} time field.
358:             * @stable ICU 2.8
359:             */
360:            public HebrewCalendar(int year, int month, int date) {
361:                super (TimeZone.getDefault(), ULocale.getDefault());
362:                this .set(YEAR, year);
363:                this .set(MONTH, month);
364:                this .set(DATE, date);
365:            }
366:
367:            /**
368:             * Constructs a <code>HebrewCalendar</code> with the given date set
369:             * in the default time zone with the default locale.
370:             *
371:             * @param date      The date to which the new calendar is set.
372:             * @stable ICU 2.8
373:             */
374:            public HebrewCalendar(Date date) {
375:                super (TimeZone.getDefault(), ULocale.getDefault());
376:                this .setTime(date);
377:            }
378:
379:            /**
380:             * Constructs a <code>HebrewCalendar</code> with the given date
381:             * and time set for the default time zone with the default locale.
382:             *
383:             * @param year      The value used to set the calendar's {@link #YEAR YEAR} time field.
384:             *
385:             * @param month     The value used to set the calendar's {@link #MONTH MONTH} time field.
386:             *                  The value is 0-based. e.g., 0 for Tishri.
387:             *
388:             * @param date      The value used to set the calendar's {@link #DATE DATE} time field.
389:             *
390:             * @param hour      The value used to set the calendar's {@link #HOUR_OF_DAY HOUR_OF_DAY} time field.
391:             *
392:             * @param minute    The value used to set the calendar's {@link #MINUTE MINUTE} time field.
393:             *
394:             * @param second    The value used to set the calendar's {@link #SECOND SECOND} time field.
395:             * @stable ICU 2.8
396:             */
397:            public HebrewCalendar(int year, int month, int date, int hour,
398:                    int minute, int second) {
399:                super (TimeZone.getDefault(), ULocale.getDefault());
400:                this .set(YEAR, year);
401:                this .set(MONTH, month);
402:                this .set(DATE, date);
403:                this .set(HOUR_OF_DAY, hour);
404:                this .set(MINUTE, minute);
405:                this .set(SECOND, second);
406:            }
407:
408:            //-------------------------------------------------------------------------
409:            // Rolling and adding functions overridden from Calendar
410:            //
411:            // These methods call through to the default implementation in IBMCalendar
412:            // for most of the fields and only handle the unusual ones themselves.
413:            //-------------------------------------------------------------------------
414:
415:            /**
416:             * Add a signed amount to a specified field, using this calendar's rules.
417:             * For example, to add three days to the current date, you can call
418:             * <code>add(Calendar.DATE, 3)</code>. 
419:             * <p>
420:             * When adding to certain fields, the values of other fields may conflict and
421:             * need to be changed.  For example, when adding one to the {@link #MONTH MONTH} field
422:             * for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
423:             * must be adjusted so that the result is "29 Elul 5758" rather than the invalid
424:             * "30 Elul 5758".
425:             * <p>
426:             * This method is able to add to
427:             * all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
428:             * and {@link #ZONE_OFFSET ZONE_OFFSET}.
429:             * <p>
430:             * <b>Note:</b> You should always use {@link #roll roll} and add rather
431:             * than attempting to perform arithmetic operations directly on the fields
432:             * of a <tt>HebrewCalendar</tt>.  Since the {@link #MONTH MONTH} field behaves
433:             * discontinuously in non-leap years, simple arithmetic can give invalid results.
434:             * <p>
435:             * @param field     the time field.
436:             * @param amount    the amount to add to the field.
437:             *
438:             * @exception   IllegalArgumentException if the field is invalid or refers
439:             *              to a field that cannot be handled by this method.
440:             * @stable ICU 2.8
441:             */
442:            public void add(int field, int amount) {
443:                switch (field) {
444:                case MONTH: {
445:                    // We can't just do a set(MONTH, get(MONTH) + amount).  The
446:                    // reason is ADAR_1.  Suppose amount is +2 and we land in
447:                    // ADAR_1 -- then we have to bump to ADAR_2 aka ADAR.  But
448:                    // if amount is -2 and we land in ADAR_1, then we have to
449:                    // bump the other way -- down to SHEVAT.  - Alan 11/00
450:                    int month = get(MONTH);
451:                    int year = get(YEAR);
452:                    boolean acrossAdar1;
453:                    if (amount > 0) {
454:                        acrossAdar1 = (month < ADAR_1); // started before ADAR_1?
455:                        month += amount;
456:                        for (;;) {
457:                            if (acrossAdar1 && month >= ADAR_1
458:                                    && !isLeapYear(year)) {
459:                                ++month;
460:                            }
461:                            if (month <= ELUL) {
462:                                break;
463:                            }
464:                            month -= ELUL + 1;
465:                            ++year;
466:                            acrossAdar1 = true;
467:                        }
468:                    } else {
469:                        acrossAdar1 = (month > ADAR_1); // started after ADAR_1?
470:                        month += amount;
471:                        for (;;) {
472:                            if (acrossAdar1 && month <= ADAR_1
473:                                    && !isLeapYear(year)) {
474:                                --month;
475:                            }
476:                            if (month >= 0) {
477:                                break;
478:                            }
479:                            month += ELUL + 1;
480:                            --year;
481:                            acrossAdar1 = true;
482:                        }
483:                    }
484:                    set(MONTH, month);
485:                    set(YEAR, year);
486:                    pinField(DAY_OF_MONTH);
487:                    break;
488:                }
489:
490:                default:
491:                    super .add(field, amount);
492:                    break;
493:                }
494:            }
495:
496:            /**
497:             * Rolls (up/down) a specified amount time on the given field.  For
498:             * example, to roll the current date up by three days, you can call
499:             * <code>roll(Calendar.DATE, 3)</code>.  If the
500:             * field is rolled past its maximum allowable value, it will "wrap" back
501:             * to its minimum and continue rolling.  
502:             * For example, calling <code>roll(Calendar.DATE, 10)</code>
503:             * on a Hebrew calendar set to "25 Av 5758" will result in the date "5 Av 5758".
504:             * <p>
505:             * When rolling certain fields, the values of other fields may conflict and
506:             * need to be changed.  For example, when rolling the {@link #MONTH MONTH} field
507:             * upward by one for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
508:             * must be adjusted so that the result is "29 Elul 5758" rather than the invalid
509:             * "30 Elul".
510:             * <p>
511:             * This method is able to roll
512:             * all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
513:             * and {@link #ZONE_OFFSET ZONE_OFFSET}.  Subclasses may, of course, add support for
514:             * additional fields in their overrides of <code>roll</code>.
515:             * <p>
516:             * <b>Note:</b> You should always use roll and {@link #add add} rather
517:             * than attempting to perform arithmetic operations directly on the fields
518:             * of a <tt>HebrewCalendar</tt>.  Since the {@link #MONTH MONTH} field behaves
519:             * discontinuously in non-leap years, simple arithmetic can give invalid results.
520:             * <p>
521:             * @param field     the time field.
522:             * @param amount    the amount by which the field should be rolled.
523:             *
524:             * @exception   IllegalArgumentException if the field is invalid or refers
525:             *              to a field that cannot be handled by this method.
526:             * @stable ICU 2.8
527:             */
528:            public void roll(int field, int amount) {
529:                switch (field) {
530:                case MONTH: {
531:                    int month = get(MONTH);
532:                    int year = get(YEAR);
533:
534:                    boolean leapYear = isLeapYear(year);
535:                    int yearLength = monthsInYear(year);
536:                    int newMonth = month + (amount % yearLength);
537:                    //
538:                    // If it's not a leap year and we're rolling past the missing month
539:                    // of ADAR_1, we need to roll an extra month to make up for it.
540:                    //
541:                    if (!leapYear) {
542:                        if (amount > 0 && month < ADAR_1 && newMonth >= ADAR_1) {
543:                            newMonth++;
544:                        } else if (amount < 0 && month > ADAR_1
545:                                && newMonth <= ADAR_1) {
546:                            newMonth--;
547:                        }
548:                    }
549:                    set(MONTH, (newMonth + 13) % 13);
550:                    pinField(DAY_OF_MONTH);
551:                    return;
552:                }
553:                default:
554:                    super .roll(field, amount);
555:                }
556:            }
557:
558:            //-------------------------------------------------------------------------
559:            // Support methods
560:            //-------------------------------------------------------------------------
561:
562:            // Hebrew date calculations are performed in terms of days, hours, and
563:            // "parts" (or halakim), which are 1/1080 of an hour, or 3 1/3 seconds.
564:            private static final long HOUR_PARTS = 1080;
565:            private static final long DAY_PARTS = 24 * HOUR_PARTS;
566:
567:            // An approximate value for the length of a lunar month.
568:            // It is used to calculate the approximate year and month of a given
569:            // absolute date.
570:            static private final int MONTH_DAYS = 29;
571:            static private final long MONTH_FRACT = 12 * HOUR_PARTS + 793;
572:            static private final long MONTH_PARTS = MONTH_DAYS * DAY_PARTS
573:                    + MONTH_FRACT;
574:
575:            // The time of the new moon (in parts) on 1 Tishri, year 1 (the epoch)
576:            // counting from noon on the day before.  BAHARAD is an abbreviation of
577:            // Bet (Monday), Hey (5 hours from sunset), Resh-Daled (204).
578:            static private final long BAHARAD = 11 * HOUR_PARTS + 204;
579:
580:            /**
581:             * Finds the day # of the first day in the given Hebrew year.
582:             * To do this, we want to calculate the time of the Tishri 1 new moon
583:             * in that year.
584:             * <p>
585:             * The algorithm here is similar to ones described in a number of
586:             * references, including:
587:             * <ul>
588:             * <li>"Calendrical Calculations", by Nachum Dershowitz & Edward Reingold,
589:             *     Cambridge University Press, 1997, pages 85-91.
590:             *
591:             * <li>Hebrew Calendar Science and Myths,
592:             *     <a href="http://www.geocities.com/Athens/1584/">
593:             *     http://www.geocities.com/Athens/1584/</a>
594:             *
595:             * <li>The Calendar FAQ,
596:             *      <a href="http://www.faqs.org/faqs/calendars/faq/">
597:             *      http://www.faqs.org/faqs/calendars/faq/</a>
598:             * </ul>
599:             */
600:            private static long startOfYear(int year) {
601:                long day = cache.get(year);
602:
603:                if (day == CalendarCache.EMPTY) {
604:                    int months = (235 * year - 234) / 19; // # of months before year
605:
606:                    long frac = months * MONTH_FRACT + BAHARAD; // Fractional part of day #
607:                    day = months * 29 + (frac / DAY_PARTS); // Whole # part of calculation
608:                    frac = frac % DAY_PARTS; // Time of day
609:
610:                    int wd = (int) (day % 7); // Day of week (0 == Monday)
611:
612:                    if (wd == 2 || wd == 4 || wd == 6) {
613:                        // If the 1st is on Sun, Wed, or Fri, postpone to the next day
614:                        day += 1;
615:                        wd = (int) (day % 7);
616:                    }
617:                    if (wd == 1 && frac > 15 * HOUR_PARTS + 204
618:                            && !isLeapYear(year)) {
619:                        // If the new moon falls after 3:11:20am (15h204p from the previous noon)
620:                        // on a Tuesday and it is not a leap year, postpone by 2 days.
621:                        // This prevents 356-day years.
622:                        day += 2;
623:                    } else if (wd == 0 && frac > 21 * HOUR_PARTS + 589
624:                            && isLeapYear(year - 1)) {
625:                        // If the new moon falls after 9:32:43 1/3am (21h589p from yesterday noon)
626:                        // on a Monday and *last* year was a leap year, postpone by 1 day.
627:                        // Prevents 382-day years.
628:                        day += 1;
629:                    }
630:                    cache.put(year, day);
631:                }
632:                return day;
633:            }
634:
635:            /**
636:             * Find the day of the week for a given day
637:             *
638:             * @param day   The # of days since the start of the Hebrew calendar,
639:             *              1-based (i.e. 1/1/1 AM is day 1).
640:             */
641:            ///CLOVER:OFF
642:            private static int absoluteDayToDayOfWeek(long day) {
643:                // We know that 1/1/1 AM is a Monday, which makes the math easy...
644:                return (int) (day % 7) + 1;
645:            }
646:
647:            ///CLOVER:ON
648:
649:            /**
650:             * Returns the the type of a given year.
651:             *  0   "Deficient" year with 353 or 383 days
652:             *  1   "Normal"    year with 354 or 384 days
653:             *  2   "Complete"  year with 355 or 385 days
654:             */
655:            private final int yearType(int year) {
656:                int yearLength = handleGetYearLength(year);
657:
658:                if (yearLength > 380) {
659:                    yearLength -= 30; // Subtract length of leap month.
660:                }
661:
662:                int type = 0;
663:
664:                switch (yearLength) {
665:                case 353:
666:                    type = 0;
667:                    break;
668:                case 354:
669:                    type = 1;
670:                    break;
671:                case 355:
672:                    type = 2;
673:                    break;
674:                default:
675:                    throw new IllegalArgumentException("Illegal year length "
676:                            + yearLength + " in year " + year);
677:
678:                }
679:                return type;
680:            }
681:
682:            /**
683:             * Determine whether a given Hebrew year is a leap year
684:             *
685:             * The rule here is that if (year % 19) == 0, 3, 6, 8, 11, 14, or 17.
686:             * The formula below performs the same test, believe it or not.
687:             */
688:            private static final boolean isLeapYear(int year) {
689:                //return (year * 12 + 17) % 19 >= 12;
690:                int x = (year * 12 + 17) % 19;
691:                return x >= ((x < 0) ? -7 : 12);
692:            }
693:
694:            private static int monthsInYear(int year) {
695:                return isLeapYear(year) ? 13 : 12;
696:            }
697:
698:            //-------------------------------------------------------------------------
699:            // Calendar framework
700:            //-------------------------------------------------------------------------
701:
702:            /**
703:             * @stable ICU 2.8
704:             */
705:            protected int handleGetLimit(int field, int limitType) {
706:                return LIMITS[field][limitType];
707:            }
708:
709:            /**
710:             * Returns the length of the given month in the given year
711:             * @stable ICU 2.8
712:             */
713:            protected int handleGetMonthLength(int extendedYear, int month) {
714:
715:                switch (month) {
716:                case HESHVAN:
717:                case KISLEV:
718:                    // These two month lengths can vary
719:                    return MONTH_LENGTH[month][yearType(extendedYear)];
720:
721:                default:
722:                    // The rest are a fixed length
723:                    return MONTH_LENGTH[month][0];
724:                }
725:            }
726:
727:            /**
728:             * Returns the number of days in the given Hebrew year
729:             * @stable ICU 2.8
730:             */
731:            protected int handleGetYearLength(int eyear) {
732:                return (int) (startOfYear(eyear + 1) - startOfYear(eyear));
733:            }
734:
735:            //-------------------------------------------------------------------------
736:            // Functions for converting from milliseconds to field values
737:            //-------------------------------------------------------------------------
738:
739:            /**
740:             * Subclasses may override this method to compute several fields
741:             * specific to each calendar system.  These are:
742:             *
743:             * <ul><li>ERA
744:             * <li>YEAR
745:             * <li>MONTH
746:             * <li>DAY_OF_MONTH
747:             * <li>DAY_OF_YEAR
748:             * <li>EXTENDED_YEAR</ul>
749:             * 
750:             * Subclasses can refer to the DAY_OF_WEEK and DOW_LOCAL fields,
751:             * which will be set when this method is called.  Subclasses can
752:             * also call the getGregorianXxx() methods to obtain Gregorian
753:             * calendar equivalents for the given Julian day.
754:             *
755:             * <p>In addition, subclasses should compute any subclass-specific
756:             * fields, that is, fields from BASE_FIELD_COUNT to
757:             * getFieldCount() - 1.
758:             * @stable ICU 2.8
759:             */
760:            protected void handleComputeFields(int julianDay) {
761:                long d = julianDay - 347997;
762:                long m = (d * DAY_PARTS) / MONTH_PARTS; // Months (approx)
763:                int year = (int) ((19 * m + 234) / 235) + 1; // Years (approx)
764:                long ys = startOfYear(year); // 1st day of year
765:                int dayOfYear = (int) (d - ys);
766:
767:                // Because of the postponement rules, it's possible to guess wrong.  Fix it.
768:                while (dayOfYear < 1) {
769:                    year--;
770:                    ys = startOfYear(year);
771:                    dayOfYear = (int) (d - ys);
772:                }
773:
774:                // Now figure out which month we're in, and the date within that month
775:                int yearType = yearType(year);
776:                int monthStart[][] = isLeapYear(year) ? LEAP_MONTH_START
777:                        : MONTH_START;
778:
779:                int month = 0;
780:                while (dayOfYear > monthStart[month][yearType]) {
781:                    month++;
782:                }
783:                month--;
784:                int dayOfMonth = dayOfYear - monthStart[month][yearType];
785:
786:                internalSet(ERA, 0);
787:                internalSet(YEAR, year);
788:                internalSet(EXTENDED_YEAR, year);
789:                internalSet(MONTH, month);
790:                internalSet(DAY_OF_MONTH, dayOfMonth);
791:                internalSet(DAY_OF_YEAR, dayOfYear);
792:            }
793:
794:            //-------------------------------------------------------------------------
795:            // Functions for converting from field values to milliseconds
796:            //-------------------------------------------------------------------------
797:
798:            /**
799:             * @stable ICU 2.8
800:             */
801:            protected int handleGetExtendedYear() {
802:                int year;
803:                if (newerField(EXTENDED_YEAR, YEAR) == EXTENDED_YEAR) {
804:                    year = internalGet(EXTENDED_YEAR, 1); // Default to year 1
805:                } else {
806:                    year = internalGet(YEAR, 1); // Default to year 1
807:                }
808:                return year;
809:            }
810:
811:            /**
812:             * Return JD of start of given month/year.
813:             * @stable ICU 2.8
814:             */
815:            protected int handleComputeMonthStart(int eyear, int month,
816:                    boolean useMonth) {
817:
818:                // Resolve out-of-range months.  This is necessary in order to
819:                // obtain the correct year.  We correct to
820:                // a 12- or 13-month year (add/subtract 12 or 13, depending
821:                // on the year) but since we _always_ number from 0..12, and
822:                // the leap year determines whether or not month 5 (Adar 1)
823:                // is present, we allow 0..12 in any given year.
824:                while (month < 0) {
825:                    month += monthsInYear(--eyear);
826:                }
827:                // Careful: allow 0..12 in all years
828:                while (month > 12) {
829:                    month -= monthsInYear(eyear++);
830:                }
831:
832:                long day = startOfYear(eyear);
833:
834:                if (month != 0) {
835:                    if (isLeapYear(eyear)) {
836:                        day += LEAP_MONTH_START[month][yearType(eyear)];
837:                    } else {
838:                        day += MONTH_START[month][yearType(eyear)];
839:                    }
840:                }
841:
842:                return (int) (day + 347997);
843:            }
844:
845:            /**
846:             * Return the current Calendar type.
847:             * @return type of calendar (gregorian, etc.)
848:             * @internal ICU 3.0
849:             * @deprecated This API is ICU internal only.
850:             */
851:            public String getType() {
852:                return "hebrew";
853:            }
854:
855:            /*
856:            private static CalendarFactory factory;
857:            public static CalendarFactory factory() {
858:                if (factory == null) {
859:                    factory = new CalendarFactory() {
860:                        public Calendar create(TimeZone tz, ULocale loc) {
861:                            return new HebrewCalendar(tz, loc);
862:                        }
863:
864:                        public String factoryName() {
865:                            return "Hebrew";
866:                        }
867:                    };
868:                }
869:                return factory;
870:            }
871:             */
872:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.