001: /*
002: * Copyright (C) 1996-2006, International Business Machines
003: * Corporation and others. All Rights Reserved.
004: */
005: package com.ibm.icu.util;
006:
007: import java.util.Date;
008: import java.util.Locale;
009:
010: /**
011: * <code>GregorianCalendar</code> is a concrete subclass of
012: * {@link Calendar}
013: * and provides the standard calendar used by most of the world.
014: *
015: * <p>
016: * The standard (Gregorian) calendar has 2 eras, BC and AD.
017: *
018: * <p>
019: * This implementation handles a single discontinuity, which corresponds by
020: * default to the date the Gregorian calendar was instituted (October 15, 1582
021: * in some countries, later in others). The cutover date may be changed by the
022: * caller by calling <code>setGregorianChange()</code>.
023: *
024: * <p>
025: * Historically, in those countries which adopted the Gregorian calendar first,
026: * October 4, 1582 was thus followed by October 15, 1582. This calendar models
027: * this correctly. Before the Gregorian cutover, <code>GregorianCalendar</code>
028: * implements the Julian calendar. The only difference between the Gregorian
029: * and the Julian calendar is the leap year rule. The Julian calendar specifies
030: * leap years every four years, whereas the Gregorian calendar omits century
031: * years which are not divisible by 400.
032: *
033: * <p>
034: * <code>GregorianCalendar</code> implements <em>proleptic</em> Gregorian and
035: * Julian calendars. That is, dates are computed by extrapolating the current
036: * rules indefinitely far backward and forward in time. As a result,
037: * <code>GregorianCalendar</code> may be used for all years to generate
038: * meaningful and consistent results. However, dates obtained using
039: * <code>GregorianCalendar</code> are historically accurate only from March 1, 4
040: * AD onward, when modern Julian calendar rules were adopted. Before this date,
041: * leap year rules were applied irregularly, and before 45 BC the Julian
042: * calendar did not even exist.
043: *
044: * <p>
045: * Prior to the institution of the Gregorian calendar, New Year's Day was
046: * March 25. To avoid confusion, this calendar always uses January 1. A manual
047: * adjustment may be made if desired for dates that are prior to the Gregorian
048: * changeover and which fall between January 1 and March 24.
049: *
050: * <p>Values calculated for the <code>WEEK_OF_YEAR</code> field range from 1 to
051: * 53. Week 1 for a year is the earliest seven day period starting on
052: * <code>getFirstDayOfWeek()</code> that contains at least
053: * <code>getMinimalDaysInFirstWeek()</code> days from that year. It thus
054: * depends on the values of <code>getMinimalDaysInFirstWeek()</code>,
055: * <code>getFirstDayOfWeek()</code>, and the day of the week of January 1.
056: * Weeks between week 1 of one year and week 1 of the following year are
057: * numbered sequentially from 2 to 52 or 53 (as needed).
058:
059: * <p>For example, January 1, 1998 was a Thursday. If
060: * <code>getFirstDayOfWeek()</code> is <code>MONDAY</code> and
061: * <code>getMinimalDaysInFirstWeek()</code> is 4 (these are the values
062: * reflecting ISO 8601 and many national standards), then week 1 of 1998 starts
063: * on December 29, 1997, and ends on January 4, 1998. If, however,
064: * <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>, then week 1 of 1998
065: * starts on January 4, 1998, and ends on January 10, 1998; the first three days
066: * of 1998 then are part of week 53 of 1997.
067: *
068: * <p>Values calculated for the <code>WEEK_OF_MONTH</code> field range from 0 or
069: * 1 to 4 or 5. Week 1 of a month (the days with <code>WEEK_OF_MONTH =
070: * 1</code>) is the earliest set of at least
071: * <code>getMinimalDaysInFirstWeek()</code> contiguous days in that month,
072: * ending on the day before <code>getFirstDayOfWeek()</code>. Unlike
073: * week 1 of a year, week 1 of a month may be shorter than 7 days, need
074: * not start on <code>getFirstDayOfWeek()</code>, and will not include days of
075: * the previous month. Days of a month before week 1 have a
076: * <code>WEEK_OF_MONTH</code> of 0.
077: *
078: * <p>For example, if <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>
079: * and <code>getMinimalDaysInFirstWeek()</code> is 4, then the first week of
080: * January 1998 is Sunday, January 4 through Saturday, January 10. These days
081: * have a <code>WEEK_OF_MONTH</code> of 1. Thursday, January 1 through
082: * Saturday, January 3 have a <code>WEEK_OF_MONTH</code> of 0. If
083: * <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1
084: * through January 3 have a <code>WEEK_OF_MONTH</code> of 1.
085: *
086: * <p>
087: * <strong>Example:</strong>
088: * <blockquote>
089: * <pre>
090: * // get the supported ids for GMT-08:00 (Pacific Standard Time)
091: * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
092: * // if no ids were returned, something is wrong. get out.
093: * if (ids.length == 0)
094: * System.exit(0);
095: *
096: * // begin output
097: * System.out.println("Current Time");
098: *
099: * // create a Pacific Standard Time time zone
100: * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
101: *
102: * // set up rules for daylight savings time
103: * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
104: * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
105: *
106: * // create a GregorianCalendar with the Pacific Daylight time zone
107: * // and the current date and time
108: * Calendar calendar = new GregorianCalendar(pdt);
109: * Date trialTime = new Date();
110: * calendar.setTime(trialTime);
111: *
112: * // print out a bunch of interesting things
113: * System.out.println("ERA: " + calendar.get(Calendar.ERA));
114: * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
115: * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
116: * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
117: * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
118: * System.out.println("DATE: " + calendar.get(Calendar.DATE));
119: * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
120: * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
121: * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
122: * System.out.println("DAY_OF_WEEK_IN_MONTH: "
123: * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
124: * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
125: * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
126: * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
127: * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
128: * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
129: * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
130: * System.out.println("ZONE_OFFSET: "
131: * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
132: * System.out.println("DST_OFFSET: "
133: * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
134:
135: * System.out.println("Current Time, with hour reset to 3");
136: * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
137: * calendar.set(Calendar.HOUR, 3);
138: * System.out.println("ERA: " + calendar.get(Calendar.ERA));
139: * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
140: * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
141: * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
142: * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
143: * System.out.println("DATE: " + calendar.get(Calendar.DATE));
144: * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
145: * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
146: * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
147: * System.out.println("DAY_OF_WEEK_IN_MONTH: "
148: * + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
149: * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
150: * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
151: * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
152: * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
153: * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
154: * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
155: * System.out.println("ZONE_OFFSET: "
156: * + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
157: * System.out.println("DST_OFFSET: "
158: * + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours</pre>
159: * </blockquote>
160: * <p>
161: * GregorianCalendar usually should be instantiated using
162: * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
163: * with the tag <code>"@calendar=gregorian"</code>.</p>
164:
165: * @see Calendar
166: * @see TimeZone
167: * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
168: * @stable ICU 2.0
169: */
170: public class GregorianCalendar extends Calendar {
171: // jdk1.4.2 serialver
172: private static final long serialVersionUID = 9199388694351062137L;
173:
174: /*
175: * Implementation Notes
176: *
177: * The Julian day number, as used here, is a modified number which has its
178: * onset at midnight, rather than noon.
179: *
180: * The epoch is the number of days or milliseconds from some defined
181: * starting point. The epoch for java.util.Date is used here; that is,
182: * milliseconds from January 1, 1970 (Gregorian), midnight UTC. Other
183: * epochs which are used are January 1, year 1 (Gregorian), which is day 1
184: * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is
185: * day 1 of the Julian calendar.
186: *
187: * We implement the proleptic Julian and Gregorian calendars. This means we
188: * implement the modern definition of the calendar even though the
189: * historical usage differs. For example, if the Gregorian change is set
190: * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which
191: * labels dates preceding the invention of the Gregorian calendar in 1582 as
192: * if the calendar existed then.
193: *
194: * Likewise, with the Julian calendar, we assume a consistent 4-year leap
195: * rule, even though the historical pattern of leap years is irregular,
196: * being every 3 years from 45 BC through 9 BC, then every 4 years from 8 AD
197: * onwards, with no leap years in-between. Thus date computations and
198: * functions such as isLeapYear() are not intended to be historically
199: * accurate.
200: *
201: * Given that milliseconds are a long, day numbers such as Julian day
202: * numbers, Gregorian or Julian calendar days, or epoch days, are also
203: * longs. Years can fit into an int.
204: */
205:
206: //////////////////
207: // Class Variables
208: //////////////////
209: /**
210: * Value of the <code>ERA</code> field indicating
211: * the period before the common era (before Christ), also known as BCE.
212: * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
213: * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
214: * @see Calendar#ERA
215: * @stable ICU 2.0
216: */
217: public static final int BC = 0;
218:
219: /**
220: * Value of the <code>ERA</code> field indicating
221: * the common era (Anno Domini), also known as CE.
222: * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
223: * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
224: * @see Calendar#ERA
225: * @stable ICU 2.0
226: */
227: public static final int AD = 1;
228:
229: private static final int EPOCH_YEAR = 1970;
230:
231: private static final int[][] MONTH_COUNT = {
232: //len len2 st st2
233: { 31, 31, 0, 0 }, // Jan
234: { 28, 29, 31, 31 }, // Feb
235: { 31, 31, 59, 60 }, // Mar
236: { 30, 30, 90, 91 }, // Apr
237: { 31, 31, 120, 121 }, // May
238: { 30, 30, 151, 152 }, // Jun
239: { 31, 31, 181, 182 }, // Jul
240: { 31, 31, 212, 213 }, // Aug
241: { 30, 30, 243, 244 }, // Sep
242: { 31, 31, 273, 274 }, // Oct
243: { 30, 30, 304, 305 }, // Nov
244: { 31, 31, 334, 335 } // Dec
245: // len length of month
246: // len2 length of month in a leap year
247: // st days in year before start of month
248: // st2 days in year before month in leap year
249: };
250:
251: /**
252: * Old year limits were least max 292269054, max 292278994.
253: */
254: private static final int LIMITS[][] = {
255: // Minimum Greatest Least Maximum
256: // Minimum Maximum
257: { 0, 0, 1, 1 }, // ERA
258: { 1, 1, 5828963, 5838270 }, // YEAR
259: { 0, 0, 11, 11 }, // MONTH
260: { 1, 1, 52, 53 }, // WEEK_OF_YEAR
261: { 0, 0, 4, 6 }, // WEEK_OF_MONTH
262: { 1, 1, 28, 31 }, // DAY_OF_MONTH
263: { 1, 1, 365, 366 }, // DAY_OF_YEAR
264: {/* */}, // DAY_OF_WEEK
265: { -1, -1, 4, 6 }, // DAY_OF_WEEK_IN_MONTH
266: {/* */}, // AM_PM
267: {/* */}, // HOUR
268: {/* */}, // HOUR_OF_DAY
269: {/* */}, // MINUTE
270: {/* */}, // SECOND
271: {/* */}, // MILLISECOND
272: {/* */}, // ZONE_OFFSET
273: {/* */}, // DST_OFFSET
274: { -5838270, -5838270, 5828964, 5838271 }, // YEAR_WOY
275: {/* */}, // DOW_LOCAL
276: { -5838269, -5838269, 5828963, 5838270 }, // EXTENDED_YEAR
277: {/* */}, // JULIAN_DAY
278: {/* */}, // MILLISECONDS_IN_DAY
279: };
280:
281: /**
282: * @stable ICU 2.0
283: */
284: protected int handleGetLimit(int field, int limitType) {
285: return LIMITS[field][limitType];
286: }
287:
288: /////////////////////
289: // Instance Variables
290: /////////////////////
291:
292: /**
293: * The point at which the Gregorian calendar rules are used, measured in
294: * milliseconds from the standard epoch. Default is October 15, 1582
295: * (Gregorian) 00:00:00 UTC or -12219292800000L. For this value, October 4,
296: * 1582 (Julian) is followed by October 15, 1582 (Gregorian). This
297: * corresponds to Julian day number 2299161.
298: * @serial
299: */
300: private long gregorianCutover = -12219292800000L;
301:
302: /**
303: * Julian day number of the Gregorian cutover.
304: */
305: private transient int cutoverJulianDay = 2299161;
306:
307: /**
308: * The year of the gregorianCutover, with 0 representing
309: * 1 BC, -1 representing 2 BC, etc.
310: */
311: private transient int gregorianCutoverYear = 1582;
312:
313: /**
314: * Used by handleComputeJulianDay() and handleComputeMonthStart().
315: * @stable ICU 2.0
316: */
317: transient protected boolean isGregorian;
318:
319: /**
320: * Used by handleComputeJulianDay() and handleComputeMonthStart().
321: * @stable ICU 2.0
322: */
323: transient protected boolean invertGregorian;
324:
325: ///////////////
326: // Constructors
327: ///////////////
328:
329: /**
330: * Constructs a default GregorianCalendar using the current time
331: * in the default time zone with the default locale.
332: * @stable ICU 2.0
333: */
334: public GregorianCalendar() {
335: this (TimeZone.getDefault(), ULocale.getDefault());
336: }
337:
338: /**
339: * Constructs a GregorianCalendar based on the current time
340: * in the given time zone with the default locale.
341: * @param zone the given time zone.
342: * @stable ICU 2.0
343: */
344: public GregorianCalendar(TimeZone zone) {
345: this (zone, ULocale.getDefault());
346: }
347:
348: /**
349: * Constructs a GregorianCalendar based on the current time
350: * in the default time zone with the given locale.
351: * @param aLocale the given locale.
352: * @stable ICU 2.0
353: */
354: public GregorianCalendar(Locale aLocale) {
355: this (TimeZone.getDefault(), aLocale);
356: }
357:
358: /**
359: * Constructs a GregorianCalendar based on the current time
360: * in the default time zone with the given locale.
361: * @param locale the given ulocale.
362: * @draft ICU 3.2
363: * @provisional This API might change or be removed in a future release.
364: */
365: public GregorianCalendar(ULocale locale) {
366: this (TimeZone.getDefault(), locale);
367: }
368:
369: /**
370: * Constructs a GregorianCalendar based on the current time
371: * in the given time zone with the given locale.
372: * @param zone the given time zone.
373: * @param aLocale the given locale.
374: * @stable ICU 2.0
375: */
376: public GregorianCalendar(TimeZone zone, Locale aLocale) {
377: super (zone, aLocale);
378: setTimeInMillis(System.currentTimeMillis());
379: }
380:
381: /**
382: * Constructs a GregorianCalendar based on the current time
383: * in the given time zone with the given locale.
384: * @param zone the given time zone.
385: * @param locale the given ulocale.
386: * @draft ICU 3.2
387: * @provisional This API might change or be removed in a future release.
388: */
389: public GregorianCalendar(TimeZone zone, ULocale locale) {
390: super (zone, locale);
391: setTimeInMillis(System.currentTimeMillis());
392: }
393:
394: /**
395: * Constructs a GregorianCalendar with the given date set
396: * in the default time zone with the default locale.
397: * @param year the value used to set the YEAR time field in the calendar.
398: * @param month the value used to set the MONTH time field in the calendar.
399: * Month value is 0-based. e.g., 0 for January.
400: * @param date the value used to set the DATE time field in the calendar.
401: * @stable ICU 2.0
402: */
403: public GregorianCalendar(int year, int month, int date) {
404: super (TimeZone.getDefault(), ULocale.getDefault());
405: set(ERA, AD);
406: set(YEAR, year);
407: set(MONTH, month);
408: set(DATE, date);
409: }
410:
411: /**
412: * Constructs a GregorianCalendar with the given date
413: * and time set for the default time zone with the default locale.
414: * @param year the value used to set the YEAR time field in the calendar.
415: * @param month the value used to set the MONTH time field in the calendar.
416: * Month value is 0-based. e.g., 0 for January.
417: * @param date the value used to set the DATE time field in the calendar.
418: * @param hour the value used to set the HOUR_OF_DAY time field
419: * in the calendar.
420: * @param minute the value used to set the MINUTE time field
421: * in the calendar.
422: * @stable ICU 2.0
423: */
424: public GregorianCalendar(int year, int month, int date, int hour,
425: int minute) {
426: super (TimeZone.getDefault(), ULocale.getDefault());
427: set(ERA, AD);
428: set(YEAR, year);
429: set(MONTH, month);
430: set(DATE, date);
431: set(HOUR_OF_DAY, hour);
432: set(MINUTE, minute);
433: }
434:
435: /**
436: * Constructs a GregorianCalendar with the given date
437: * and time set for the default time zone with the default locale.
438: * @param year the value used to set the YEAR time field in the calendar.
439: * @param month the value used to set the MONTH time field in the calendar.
440: * Month value is 0-based. e.g., 0 for January.
441: * @param date the value used to set the DATE time field in the calendar.
442: * @param hour the value used to set the HOUR_OF_DAY time field
443: * in the calendar.
444: * @param minute the value used to set the MINUTE time field
445: * in the calendar.
446: * @param second the value used to set the SECOND time field
447: * in the calendar.
448: * @stable ICU 2.0
449: */
450: public GregorianCalendar(int year, int month, int date, int hour,
451: int minute, int second) {
452: super (TimeZone.getDefault(), ULocale.getDefault());
453: set(ERA, AD);
454: set(YEAR, year);
455: set(MONTH, month);
456: set(DATE, date);
457: set(HOUR_OF_DAY, hour);
458: set(MINUTE, minute);
459: set(SECOND, second);
460: }
461:
462: /////////////////
463: // Public methods
464: /////////////////
465:
466: /**
467: * Sets the GregorianCalendar change date. This is the point when the switch
468: * from Julian dates to Gregorian dates occurred. Default is October 15,
469: * 1582. Previous to this, dates will be in the Julian calendar.
470: * <p>
471: * To obtain a pure Julian calendar, set the change date to
472: * <code>Date(Long.MAX_VALUE)</code>. To obtain a pure Gregorian calendar,
473: * set the change date to <code>Date(Long.MIN_VALUE)</code>.
474: *
475: * @param date the given Gregorian cutover date.
476: * @stable ICU 2.0
477: */
478: public void setGregorianChange(Date date) {
479: gregorianCutover = date.getTime();
480:
481: // If the cutover has an extreme value, then create a pure
482: // Gregorian or pure Julian calendar by giving the cutover year and
483: // JD extreme values.
484: if (gregorianCutover <= MIN_MILLIS) {
485: gregorianCutoverYear = cutoverJulianDay = Integer.MIN_VALUE;
486: } else if (gregorianCutover >= MAX_MILLIS) {
487: gregorianCutoverYear = cutoverJulianDay = Integer.MAX_VALUE;
488: } else {
489: // Precompute two internal variables which we use to do the actual
490: // cutover computations. These are the Julian day of the cutover
491: // and the cutover year.
492: cutoverJulianDay = (int) floorDivide(gregorianCutover,
493: ONE_DAY);
494:
495: // Convert cutover millis to extended year
496: GregorianCalendar cal = new GregorianCalendar(getTimeZone());
497: cal.setTime(date);
498: gregorianCutoverYear = cal.get(EXTENDED_YEAR);
499: }
500: }
501:
502: /**
503: * Gets the Gregorian Calendar change date. This is the point when the
504: * switch from Julian dates to Gregorian dates occurred. Default is
505: * October 15, 1582. Previous to this, dates will be in the Julian
506: * calendar.
507: * @return the Gregorian cutover date for this calendar.
508: * @stable ICU 2.0
509: */
510: public final Date getGregorianChange() {
511: return new Date(gregorianCutover);
512: }
513:
514: /**
515: * Determines if the given year is a leap year. Returns true if the
516: * given year is a leap year.
517: * @param year the given year.
518: * @return true if the given year is a leap year; false otherwise.
519: * @stable ICU 2.0
520: */
521: public boolean isLeapYear(int year) {
522: return year >= gregorianCutoverYear ? ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)))
523: : // Gregorian
524: (year % 4 == 0); // Julian
525: }
526:
527: /**
528: * Returns true if the given Calendar object is equivalent to this
529: * one. Calendar override.
530: *
531: * @param other the Calendar to be compared with this Calendar
532: * @stable ICU 2.4
533: */
534: public boolean isEquivalentTo(Calendar other) {
535: return super .isEquivalentTo(other)
536: && gregorianCutover == ((GregorianCalendar) other).gregorianCutover;
537: }
538:
539: /**
540: * Override hashCode.
541: * Generates the hash code for the GregorianCalendar object
542: * @stable ICU 2.0
543: */
544: public int hashCode() {
545: return super .hashCode() ^ (int) gregorianCutover;
546: }
547:
548: /**
549: * Roll a field by a signed amount.
550: * @stable ICU 2.0
551: */
552: public void roll(int field, int amount) {
553:
554: switch (field) {
555: case WEEK_OF_YEAR: {
556: // Unlike WEEK_OF_MONTH, WEEK_OF_YEAR never shifts the day of the
557: // week. Also, rolling the week of the year can have seemingly
558: // strange effects simply because the year of the week of year
559: // may be different from the calendar year. For example, the
560: // date Dec 28, 1997 is the first day of week 1 of 1998 (if
561: // weeks start on Sunday and the minimal days in first week is
562: // <= 3).
563: int woy = get(WEEK_OF_YEAR);
564: // Get the ISO year, which matches the week of year. This
565: // may be one year before or after the calendar year.
566: int isoYear = get(YEAR_WOY);
567: int isoDoy = internalGet(DAY_OF_YEAR);
568: if (internalGet(MONTH) == Calendar.JANUARY) {
569: if (woy >= 52) {
570: isoDoy += handleGetYearLength(isoYear);
571: }
572: } else {
573: if (woy == 1) {
574: isoDoy -= handleGetYearLength(isoYear - 1);
575: }
576: }
577: woy += amount;
578: // Do fast checks to avoid unnecessary computation:
579: if (woy < 1 || woy > 52) {
580: // Determine the last week of the ISO year.
581: // We do this using the standard formula we use
582: // everywhere in this file. If we can see that the
583: // days at the end of the year are going to fall into
584: // week 1 of the next year, we drop the last week by
585: // subtracting 7 from the last day of the year.
586: int lastDoy = handleGetYearLength(isoYear);
587: int lastRelDow = (lastDoy - isoDoy
588: + internalGet(DAY_OF_WEEK) - getFirstDayOfWeek()) % 7;
589: if (lastRelDow < 0)
590: lastRelDow += 7;
591: if ((6 - lastRelDow) >= getMinimalDaysInFirstWeek())
592: lastDoy -= 7;
593: int lastWoy = weekNumber(lastDoy, lastRelDow + 1);
594: woy = ((woy + lastWoy - 1) % lastWoy) + 1;
595: }
596: set(WEEK_OF_YEAR, woy);
597: set(YEAR, isoYear); // Why not YEAR_WOY? - Alan 11/6/00
598: return;
599: }
600:
601: default:
602: super .roll(field, amount);
603: return;
604: }
605: }
606:
607: /**
608: * Return the minimum value that this field could have, given the current date.
609: * For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum().
610: * @stable ICU 2.0
611: */
612: public int getActualMinimum(int field) {
613: return getMinimum(field);
614: }
615:
616: /**
617: * Return the maximum value that this field could have, given the current date.
618: * For example, with the date "Feb 3, 1997" and the DAY_OF_MONTH field, the actual
619: * maximum would be 28; for "Feb 3, 1996" it s 29. Similarly for a Hebrew calendar,
620: * for some years the actual maximum for MONTH is 12, and for others 13.
621: * @stable ICU 2.0
622: */
623: public int getActualMaximum(int field) {
624: /* It is a known limitation that the code here (and in getActualMinimum)
625: * won't behave properly at the extreme limits of GregorianCalendar's
626: * representable range (except for the code that handles the YEAR
627: * field). That's because the ends of the representable range are at
628: * odd spots in the year. For calendars with the default Gregorian
629: * cutover, these limits are Sun Dec 02 16:47:04 GMT 292269055 BC to Sun
630: * Aug 17 07:12:55 GMT 292278994 AD, somewhat different for non-GMT
631: * zones. As a result, if the calendar is set to Aug 1 292278994 AD,
632: * the actual maximum of DAY_OF_MONTH is 17, not 30. If the date is Mar
633: * 31 in that year, the actual maximum month might be Jul, whereas is
634: * the date is Mar 15, the actual maximum might be Aug -- depending on
635: * the precise semantics that are desired. Similar considerations
636: * affect all fields. Nonetheless, this effect is sufficiently arcane
637: * that we permit it, rather than complicating the code to handle such
638: * intricacies. - liu 8/20/98
639:
640: * UPDATE: No longer true, since we have pulled in the limit values on
641: * the year. - Liu 11/6/00 */
642:
643: switch (field) {
644:
645: case YEAR:
646: /* The year computation is no different, in principle, from the
647: * others, however, the range of possible maxima is large. In
648: * addition, the way we know we've exceeded the range is different.
649: * For these reasons, we use the special case code below to handle
650: * this field.
651: *
652: * The actual maxima for YEAR depend on the type of calendar:
653: *
654: * Gregorian = May 17, 292275056 BC - Aug 17, 292278994 AD
655: * Julian = Dec 2, 292269055 BC - Jan 3, 292272993 AD
656: * Hybrid = Dec 2, 292269055 BC - Aug 17, 292278994 AD
657: *
658: * We know we've exceeded the maximum when either the month, date,
659: * time, or era changes in response to setting the year. We don't
660: * check for month, date, and time here because the year and era are
661: * sufficient to detect an invalid year setting. NOTE: If code is
662: * added to check the month and date in the future for some reason,
663: * Feb 29 must be allowed to shift to Mar 1 when setting the year.
664: */
665: {
666: Calendar cal = (Calendar) clone();
667: cal.setLenient(true);
668:
669: int era = cal.get(ERA);
670: Date d = cal.getTime();
671:
672: /* Perform a binary search, with the invariant that lowGood is a
673: * valid year, and highBad is an out of range year.
674: */
675: int lowGood = LIMITS[YEAR][1];
676: int highBad = LIMITS[YEAR][2] + 1;
677: while ((lowGood + 1) < highBad) {
678: int y = (lowGood + highBad) / 2;
679: cal.set(YEAR, y);
680: if (cal.get(YEAR) == y && cal.get(ERA) == era) {
681: lowGood = y;
682: } else {
683: highBad = y;
684: cal.setTime(d); // Restore original fields
685: }
686: }
687:
688: return lowGood;
689: }
690:
691: default:
692: return super .getActualMaximum(field);
693: }
694: }
695:
696: //////////////////////
697: // Proposed public API
698: //////////////////////
699:
700: /**
701: * Return true if the current time for this Calendar is in Daylignt
702: * Savings Time.
703: *
704: * Note -- MAKE THIS PUBLIC AT THE NEXT API CHANGE. POSSIBLY DEPRECATE
705: * AND REMOVE TimeZone.inDaylightTime().
706: */
707: boolean inDaylightTime() {
708: if (!getTimeZone().useDaylightTime())
709: return false;
710: complete(); // Force update of DST_OFFSET field
711: return internalGet(DST_OFFSET) != 0;
712: }
713:
714: /////////////////////
715: // Calendar framework
716: /////////////////////
717:
718: /**
719: * @stable ICU 2.0
720: */
721: protected int handleGetMonthLength(int extendedYear, int month) {
722: return MONTH_COUNT[month][isLeapYear(extendedYear) ? 1 : 0];
723: }
724:
725: /**
726: * @stable ICU 2.0
727: */
728: protected int handleGetYearLength(int eyear) {
729: return isLeapYear(eyear) ? 366 : 365;
730: }
731:
732: /////////////////////////////
733: // Time => Fields computation
734: /////////////////////////////
735:
736: /**
737: * Override Calendar to compute several fields specific to the hybrid
738: * Gregorian-Julian calendar system. These are:
739: *
740: * <ul><li>ERA
741: * <li>YEAR
742: * <li>MONTH
743: * <li>DAY_OF_MONTH
744: * <li>DAY_OF_YEAR
745: * <li>EXTENDED_YEAR</ul>
746: * @stable ICU 2.0
747: */
748: protected void handleComputeFields(int julianDay) {
749: int eyear, month, dayOfMonth, dayOfYear;
750:
751: if (julianDay >= cutoverJulianDay) {
752: month = getGregorianMonth();
753: dayOfMonth = getGregorianDayOfMonth();
754: dayOfYear = getGregorianDayOfYear();
755: eyear = getGregorianYear();
756: } else {
757: // The Julian epoch day (not the same as Julian Day)
758: // is zero on Saturday December 30, 0 (Gregorian).
759: long julianEpochDay = julianDay - (JAN_1_1_JULIAN_DAY - 2);
760: eyear = (int) floorDivide(4 * julianEpochDay + 1464, 1461);
761:
762: // Compute the Julian calendar day number for January 1, eyear
763: long january1 = 365 * (eyear - 1)
764: + floorDivide(eyear - 1, 4);
765: dayOfYear = (int) (julianEpochDay - january1); // 0-based
766:
767: // Julian leap years occurred historically every 4 years starting
768: // with 8 AD. Before 8 AD the spacing is irregular; every 3 years
769: // from 45 BC to 9 BC, and then none until 8 AD. However, we don't
770: // implement this historical detail; instead, we implement the
771: // computatinally cleaner proleptic calendar, which assumes
772: // consistent 4-year cycles throughout time.
773: boolean isLeap = ((eyear & 0x3) == 0); // equiv. to (eyear%4 == 0)
774:
775: // Common Julian/Gregorian calculation
776: int correction = 0;
777: int march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
778: if (dayOfYear >= march1) {
779: correction = isLeap ? 1 : 2;
780: }
781: month = (12 * (dayOfYear + correction) + 6) / 367; // zero-based month
782: dayOfMonth = dayOfYear - MONTH_COUNT[month][isLeap ? 3 : 2]
783: + 1; // one-based DOM
784: ++dayOfYear;
785: }
786: internalSet(MONTH, month);
787: internalSet(DAY_OF_MONTH, dayOfMonth);
788: internalSet(DAY_OF_YEAR, dayOfYear);
789: internalSet(EXTENDED_YEAR, eyear);
790: int era = AD;
791: if (eyear < 1) {
792: era = BC;
793: eyear = 1 - eyear;
794: }
795: internalSet(ERA, era);
796: internalSet(YEAR, eyear);
797: }
798:
799: /////////////////////////////
800: // Fields => Time computation
801: /////////////////////////////
802:
803: /**
804: * @stable ICU 2.0
805: */
806: protected int handleGetExtendedYear() {
807: int year;
808: if (newerField(EXTENDED_YEAR, YEAR) == EXTENDED_YEAR) {
809: year = internalGet(EXTENDED_YEAR, EPOCH_YEAR);
810: } else {
811: // The year defaults to the epoch start, the era to AD
812: int era = internalGet(ERA, AD);
813: if (era == BC) {
814: year = 1 - internalGet(YEAR, 1); // Convert to extended year
815: } else {
816: year = internalGet(YEAR, EPOCH_YEAR);
817: }
818: }
819: return year;
820: }
821:
822: /**
823: * @stable ICU 2.0
824: */
825: protected int handleComputeJulianDay(int bestField) {
826:
827: invertGregorian = false;
828:
829: int jd = super .handleComputeJulianDay(bestField);
830:
831: // The following check handles portions of the cutover year BEFORE the
832: // cutover itself happens.
833: if (isGregorian != (jd >= cutoverJulianDay)) {
834: invertGregorian = true;
835: jd = super .handleComputeJulianDay(bestField);
836: }
837:
838: return jd;
839: }
840:
841: /**
842: * Return JD of start of given month/year
843: * @stable ICU 2.0
844: */
845: protected int handleComputeMonthStart(int eyear, int month,
846: boolean useMonth) {
847:
848: // If the month is out of range, adjust it into range, and
849: // modify the extended year value accordingly.
850: if (month < 0 || month > 11) {
851: int[] rem = new int[1];
852: eyear += floorDivide(month, 12, rem);
853: month = rem[0];
854: }
855:
856: boolean isLeap = eyear % 4 == 0;
857: int y = eyear - 1;
858: int julianDay = 365 * y + floorDivide(y, 4)
859: + (JAN_1_1_JULIAN_DAY - 3);
860:
861: isGregorian = (eyear >= gregorianCutoverYear);
862: if (invertGregorian) {
863: isGregorian = !isGregorian;
864: }
865: if (isGregorian) {
866: isLeap = isLeap
867: && ((eyear % 100 != 0) || (eyear % 400 == 0));
868: // Add 2 because Gregorian calendar starts 2 days after
869: // Julian calendar
870: julianDay += floorDivide(y, 400) - floorDivide(y, 100) + 2;
871: }
872:
873: // At this point julianDay indicates the day BEFORE the first
874: // day of January 1, <eyear> of either the Julian or Gregorian
875: // calendar.
876:
877: if (month != 0) {
878: julianDay += MONTH_COUNT[month][isLeap ? 3 : 2];
879: }
880:
881: return julianDay;
882: }
883:
884: /**
885: * Return the current Calendar type.
886: * @return type of calendar (gregorian, etc.)
887: * @internal ICU 3.0
888: * @deprecated This API is ICU internal only.
889: */
890: public String getType() {
891: return "gregorian";
892: }
893:
894: /*
895: private static CalendarFactory factory;
896: public static CalendarFactory factory() {
897: if (factory == null) {
898: factory = new CalendarFactory() {
899: public Calendar create(TimeZone tz, ULocale loc) {
900: return new GregorianCalendar(tz, loc);
901: }
902:
903: public String factoryName() {
904: return "Gregorian";
905: }
906: };
907: }
908: return factory;
909: }
910: */
911: }
|