2004-11-07 Andrew John Hughes <gnu_andrew@member.fsf.org>
[official-gcc.git] / libjava / java / util / GregorianCalendar.java
blobc54691c36a67bd28711bc7dbb69620374abbc7ac
1 /* java.util.GregorianCalendar
2 Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package java.util;
42 import java.io.IOException;
43 import java.io.ObjectInputStream;
45 /**
46 * <p>
47 * This class represents the Gregorian calendar, that is used in most
48 * countries all over the world. It does also handle the Julian calendar
49 * for dates smaller than the date of the change to the Gregorian calendar.
50 * The Gregorian calendar differs from the Julian calendar by a different
51 * leap year rule (no leap year every 100 years, except if year is divisible
52 * by 400).
53 * </p>
54 * <p>
55 * This change date is different from country to country, and can be changed with
56 * <code>setGregorianChange</code>. The first countries to adopt the Gregorian
57 * calendar did so on the 15th of October, 1582. This date followed October
58 * the 4th, 1582 in the Julian calendar system. The non-existant days that were
59 * omitted when the change took place are interpreted as Gregorian dates.
60 * </p>
61 * <p>
62 * Prior to the changeover date, New Year's Day occurred on the 25th of March.
63 * However, this class always takes New Year's Day as being the 1st of January.
64 * Client code should manually adapt the year value, if required, for dates
65 * between January the 1st and March the 24th in years prior to the changeover.
66 * </p>
67 * <p>
68 * Any date infinitely forwards or backwards in time can be represented by
69 * this class. A <em>proleptic</em> calendar system is used, which allows
70 * future dates to be created via the existing rules. This allows meaningful
71 * and consistent dates to be produced for all years. However, dates are only
72 * historically accurate following March the 1st, 4AD when the Julian calendar
73 * system was adopted. Prior to this, leap year rules were applied erraticly.
74 * </p>
75 * <p>
76 * There are two eras available for the Gregorian calendar, namely BC and AD.
77 * </p>
78 * <p>
79 * Weeks are defined as a period of seven days, beginning on the first day
80 * of the week, as returned by <code>getFirstDayOfWeek()</code>, and ending
81 * on the day prior to this.
82 * </p>
83 * <p>
84 * The weeks of the year are numbered from 1 to a possible 53. The first week
85 * of the year is defined as the first week that contains at least the minimum
86 * number of days of the first week in the new year (retrieved via
87 * <code>getMinimalDaysInFirstWeek()</code>). All weeks after this are numbered
88 * from 2 onwards.
89 * </p>
90 * <p>
91 * For example, take the year 2004. It began on a Thursday. The first week
92 * of 2004 depends both on where a week begins and how long it must minimally
93 * last. Let's say that the week begins on a Monday and must have a minimum
94 * of 5 days. In this case, the first week begins on Monday, the 5th of January.
95 * The first 4 days (Thursday to Sunday) are not eligible, as they are too few
96 * to make up the minimum number of days of the first week which must be in
97 * the new year. If the minimum was lowered to 4 days, then the first week
98 * would instead begin on Monday, the 29th of December, 2003. This first week
99 * has 4 of its days in the new year, and is now eligible.
100 * </p>
101 * <p>
102 * The weeks of the month are numbered from 0 to a possible 6. The first week
103 * of the month (numbered 1) is a set of days, prior to the first day of the week,
104 * which number at least the minimum number of days in a week. Unlike the first
105 * week of the year, the first week of the month only uses days from that particular
106 * month. As a consequence, it may have a variable number of days (from the minimum
107 * number required up to a full week of 7) and it need not start on the first day of
108 * the week. It must, however, be following by the first day of the week, as this
109 * marks the beginning of week 2. Any days of the month which occur prior to the
110 * first week (because the first day of the week occurs before the minimum number
111 * of days is met) are seen as week 0.
112 * </p>
113 * <p>
114 * Again, we will take the example of the year 2004 to demonstrate this. September
115 * 2004 begins on a Wednesday. Taking our first day of the week as Monday, and the
116 * minimum length of the first week as 6, we find that week 1 runs from Monday,
117 * the 6th of September to Sunday the 12th. Prior to the 6th, there are only
118 * 5 days (Wednesday through to Sunday). This is too small a number to meet the
119 * minimum, so these are classed as being days in week 0. Week 2 begins on the
120 * 13th, and so on. This changes if we reduce the minimum to 5. In this case,
121 * week 1 is a truncated week from Wednesday the 1st to Sunday the 5th, and week
122 * 0 doesn't exist. The first seven day week is week 2, starting on the 6th.
123 * </p>
124 * <p>
125 * On using the <code>clear()</code> method, the Gregorian calendar returns
126 * to its default value of the 1st of January, 1970 AD 00:00:00 (the epoch).
127 * The day of the week is set to the correct day for that particular time.
128 * The day is also the first of the month, and the date is in week 0.
129 * </p>
131 * @see Calendar
132 * @see TimeZone
133 * @see Calendar#getFirstDayOfWeek()
134 * @see Calendar#getMinimalDaysInFirstWeek()
136 public class GregorianCalendar extends Calendar
139 * Constant representing the era BC (Before Christ).
141 public static final int BC = 0;
144 * Constant representing the era AD (Anno Domini).
146 public static final int AD = 1;
149 * The point at which the Gregorian calendar rules were used.
150 * This is locale dependent; the default for most catholic
151 * countries is midnight (UTC) on October 5, 1582 (Julian),
152 * or October 15, 1582 (Gregorian).
154 * @serial the changeover point from the Julian calendar
155 * system to the Gregorian.
157 private long gregorianCutover;
160 * For compatability with Sun's JDK.
162 static final long serialVersionUID = -8125100834729963327L;
165 * The name of the resource bundle. Used only by getBundle()
167 private static final String bundleName = "gnu.java.locale.Calendar";
170 * Retrieves the resource bundle. The resources should be loaded
171 * via this method only. Iff an application uses this method, the
172 * resourcebundle is required.
174 * @param locale the locale in use for this calendar.
175 * @return A resource bundle for the calendar for the specified locale.
177 private static ResourceBundle getBundle(Locale locale)
179 return ResourceBundle.getBundle(bundleName, locale,
180 ClassLoader.getSystemClassLoader());
184 * Constructs a new GregorianCalender representing the current
185 * time, using the default time zone and the default locale.
187 public GregorianCalendar()
189 this(TimeZone.getDefault(), Locale.getDefault());
193 * Constructs a new GregorianCalender representing the current
194 * time, using the specified time zone and the default locale.
196 * @param zone a time zone.
198 public GregorianCalendar(TimeZone zone)
200 this(zone, Locale.getDefault());
204 * Constructs a new GregorianCalender representing the current
205 * time, using the default time zone and the specified locale.
207 * @param locale a locale.
209 public GregorianCalendar(Locale locale)
211 this(TimeZone.getDefault(), locale);
215 * Constructs a new GregorianCalender representing the current
216 * time with the given time zone and the given locale.
218 * @param zone a time zone.
219 * @param locale a locale.
221 public GregorianCalendar(TimeZone zone, Locale locale)
223 super(zone, locale);
224 ResourceBundle rb = getBundle(locale);
225 gregorianCutover = ((Date) rb.getObject("gregorianCutOver")).getTime();
226 setTimeInMillis(System.currentTimeMillis());
230 * Constructs a new GregorianCalendar representing midnight on the
231 * given date with the default time zone and locale.
232 * @param year corresponds to the YEAR time field.
233 * @param month corresponds to the MONTH time field.
234 * @param day corresponds to the DAY time field.
236 public GregorianCalendar(int year, int month, int day)
238 super();
239 set(year, month, day);
243 * Constructs a new GregorianCalendar representing midnight on the
244 * given date with the default time zone and locale.
246 * @param year corresponds to the YEAR time field.
247 * @param month corresponds to the MONTH time field.
248 * @param day corresponds to the DAY time field.
249 * @param hour corresponds to the HOUR_OF_DAY time field.
250 * @param minute corresponds to the MINUTE time field.
252 public GregorianCalendar(int year, int month, int day, int hour, int minute)
254 super();
255 set(year, month, day, hour, minute);
259 * Constructs a new GregorianCalendar representing midnight on the
260 * given date with the default time zone and locale.
263 * @param year corresponds to the YEAR time field.
264 * @param month corresponds to the MONTH time field.
265 * @param day corresponds to the DAY time field.
266 * @param hour corresponds to the HOUR_OF_DAY time field.
267 * @param minute corresponds to the MINUTE time field.
268 * @param second corresponds to the SECOND time field.
270 public GregorianCalendar(int year, int month, int day,
271 int hour, int minute, int second)
273 super();
274 set(year, month, day, hour, minute, second);
278 * Sets the date of the switch from Julian dates to Gregorian dates.
279 * You can use <code>new Date(Long.MAX_VALUE)</code> to use a pure
280 * Julian calendar, or <code>Long.MIN_VALUE</code> for a pure Gregorian
281 * calendar.
283 * @param date the date of the change.
285 public void setGregorianChange(Date date)
287 gregorianCutover = date.getTime();
291 * Gets the date of the switch from Julian dates to Gregorian dates.
293 * @return the date of the change.
295 public final Date getGregorianChange()
297 return new Date(gregorianCutover);
301 * <p>
302 * Determines if the given year is a leap year. The result is
303 * undefined if the Gregorian change took place in 1800, so that
304 * the end of February is skipped, and that year is specified.
305 * (well...).
306 * </p>
307 * <p>
308 * To specify a year in the BC era, use a negative value calculated
309 * as 1 - y, where y is the required year in BC. So, 1 BC is 0,
310 * 2 BC is -1, 3 BC is -2, etc.
311 * </p>
313 * @param year a year (use a negative value for BC).
314 * @return true, if the given year is a leap year, false otherwise.
316 public boolean isLeapYear(int year)
318 if ((year & 3) != 0)
319 // Only years divisible by 4 can be leap years
320 return false;
322 // compute the linear day of the 29. February of that year.
323 // The 13 is the number of days, that were omitted in the Gregorian
324 // Calender until the epoch.
325 int julianDay = (((year-1) * (365*4+1)) >> 2) + (31+29 -
326 (((1970-1) * (365*4+1)) / 4 + 1 - 13));
328 // If that day is smaller than the gregorianChange the julian
329 // rule applies: This is a leap year since it is divisible by 4.
330 if (julianDay * (24 * 60 * 60 * 1000L) < gregorianCutover)
331 return true;
333 return ((year % 100) != 0 || (year % 400) == 0);
337 * Get the linear time in milliseconds since the epoch. If you
338 * specify a nonpositive year it is interpreted as BC as
339 * following: 0 is 1 BC, -1 is 2 BC and so on. The date is
340 * interpreted as gregorian if the change occurred before that date.
342 * @param year the year of the date.
343 * @param dayOfYear the day of year of the date; 1 based.
344 * @param millis the millisecond in that day.
345 * @return the days since the epoch, may be negative.
347 private long getLinearTime(int year, int dayOfYear, int millis)
349 // The 13 is the number of days, that were omitted in the Gregorian
350 // Calendar until the epoch.
351 // We shift right by 2 instead of dividing by 4, to get correct
352 // results for negative years (and this is even more efficient).
353 int julianDay = ((year * (365 * 4 + 1)) >> 2) + dayOfYear -
354 ((1970 * (365 * 4 + 1)) / 4 + 1 - 13);
355 long time = julianDay * (24 * 60 * 60 * 1000L) + millis;
357 if (time >= gregorianCutover)
359 // subtract the days that are missing in gregorian calendar
360 // with respect to julian calendar.
362 // Okay, here we rely on the fact that the gregorian
363 // calendar was introduced in the AD era. This doesn't work
364 // with negative years.
366 // The additional leap year factor accounts for the fact that
367 // a leap day is not seen on Jan 1 of the leap year.
368 // And on and after the leap day, the leap day has already been
369 // included in dayOfYear.
370 int gregOffset = (year / 400) - (year / 100) + 2;
371 if (isLeapYear (year, true))
372 --gregOffset;
373 time += gregOffset * (24 * 60 * 60 * 1000L);
375 return time;
379 * Retrieves the day of the week corresponding to the specified
380 * day of the specified year.
382 * @param year the year in which the dayOfYear occurs.
383 * @param dayOfYear the day of the year (an integer between 0 and
384 * and 366)
386 private int getWeekDay(int year, int dayOfYear)
388 int day =
389 (int) (getLinearTime(year, dayOfYear, 0) / (24 * 60 * 60 * 1000L));
391 // The epoch was a thursday.
392 int weekday = (day + THURSDAY) % 7;
393 if (weekday <= 0)
394 weekday += 7;
395 return weekday;
399 * <p>
400 * Calculate the dayOfYear from the fields array.
401 * The relativeDays is used, to account for weeks that begin before
402 * the Gregorian change and end after it.
403 * </p>
404 * <p>
405 * We return two values. The first is used to determine, if we
406 * should use the Gregorian calendar or the Julian calendar, in order
407 * to handle the change year. The second is a relative day after the given
408 * day. This is necessary for week calculation in the year in
409 * which the Gregorian change occurs.
410 * </p>
412 * @param year the year, negative for BC.
413 * @return an array of two integer values, the first containing a reference
414 * day in the current year, the second a relative count since this reference
415 * day.
417 private int[] getDayOfYear(int year)
419 if (isSet[MONTH])
421 int dayOfYear;
422 if (fields[MONTH] > FEBRUARY)
425 // The months after February are regular:
426 // 9 is an offset found by try and error.
427 dayOfYear = (fields[MONTH] * (31 + 30 + 31 + 30 + 31) - 9) / 5;
428 if (isLeapYear(year))
429 dayOfYear++;
431 else
432 dayOfYear = 31 * fields[MONTH];
434 if (isSet[DAY_OF_MONTH])
436 return new int[]
438 dayOfYear + fields[DAY_OF_MONTH], 0};
440 if (isSet[WEEK_OF_MONTH] && isSet[DAY_OF_WEEK])
442 // the weekday of the first day in that month is:
443 int weekday = getWeekDay(year, ++dayOfYear);
445 return new int[]
447 dayOfYear,
448 // the day of week in the first week
449 // (weeks starting on sunday) is:
450 fields[DAY_OF_WEEK] - weekday +
451 // Now jump to the right week and correct the possible
452 // error made by assuming sunday is the first week day.
453 7 * (fields[WEEK_OF_MONTH]
454 + (fields[DAY_OF_WEEK] < getFirstDayOfWeek()? 0 : -1)
455 + (weekday < getFirstDayOfWeek()? -1 : 0))};
457 if (isSet[DAY_OF_WEEK] && isSet[DAY_OF_WEEK_IN_MONTH])
459 // the weekday of the first day in that month is:
460 int weekday = getWeekDay(year, ++dayOfYear);
461 return new int[] {
462 dayOfYear,
463 fields[DAY_OF_WEEK] - weekday +
464 7 * (fields[DAY_OF_WEEK_IN_MONTH]
465 + (fields[DAY_OF_WEEK] < weekday ? 0 : -1))};
469 // MONTH + something did not succeed.
470 if (isSet[DAY_OF_YEAR])
472 return new int[] {0, fields[DAY_OF_YEAR]};
475 if (isSet[DAY_OF_WEEK] && isSet[WEEK_OF_YEAR])
477 int dayOfYear = getMinimalDaysInFirstWeek();
478 // the weekday of the day, that begins the first week
479 // in that year is:
480 int weekday = getWeekDay(year, dayOfYear);
482 return new int[] {
483 dayOfYear,
484 // the day of week in the first week
485 // (weeks starting on sunday) is:
486 fields[DAY_OF_WEEK] - weekday
487 // Now jump to the right week and correct the possible
488 // error made by assuming sunday is the first week day.
489 + 7 * (fields[WEEK_OF_YEAR]
490 + (fields[DAY_OF_WEEK] < getFirstDayOfWeek()? 0 : -1)
491 + (weekday < getFirstDayOfWeek()? -1 : 0))};
494 // As last resort return Jan, 1st.
495 return new int[] {1, 0};
499 * Converts the time field values (<code>fields</code>) to
500 * milliseconds since the epoch UTC (<code>time</code>).
502 * @throws IllegalArgumentException if any calendar fields
503 * are invalid.
505 protected synchronized void computeTime()
507 int era = isSet[ERA] ? fields[ERA] : AD;
508 int year = isSet[YEAR] ? fields[YEAR] : 1970;
509 if (era == BC)
510 year = 1 - year;
512 int[] daysOfYear = getDayOfYear(year);
514 int hour = 0;
515 if (isSet[HOUR_OF_DAY])
516 hour = fields[HOUR_OF_DAY];
517 else if (isSet[HOUR])
519 hour = fields[HOUR];
520 if (isSet[AM_PM] && fields[AM_PM] == PM)
521 if (hour != 12) /* not Noon */
522 hour += 12;
523 /* Fix the problem of the status of 12:00 AM (midnight). */
524 if (isSet[AM_PM] && fields[AM_PM] == AM && hour == 12)
525 hour = 0;
528 int minute = isSet[MINUTE] ? fields[MINUTE] : 0;
529 int second = isSet[SECOND] ? fields[SECOND] : 0;
530 int millis = isSet[MILLISECOND] ? fields[MILLISECOND] : 0;
531 int millisInDay;
533 if (isLenient())
535 // prevent overflow
536 long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L
537 + millis;
538 daysOfYear[1] += allMillis / (24 * 60 * 60 * 1000L);
539 millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
541 else
543 if (hour < 0 || hour >= 24 || minute < 0 || minute > 59
544 || second < 0 || second > 59 || millis < 0 || millis >= 1000)
545 throw new IllegalArgumentException();
546 millisInDay = (((hour * 60) + minute) * 60 + second) * 1000 + millis;
548 time = getLinearTime(year, daysOfYear[0], millisInDay);
550 // Add the relative days after calculating the linear time, to
551 // get right behaviour when jumping over the gregorianCutover.
552 time += daysOfYear[1] * (24 * 60 * 60 * 1000L);
555 TimeZone zone = getTimeZone();
556 int rawOffset = isSet[ZONE_OFFSET]
557 ? fields[ZONE_OFFSET] : zone.getRawOffset();
559 int dayOfYear = daysOfYear[0] + daysOfYear[1];
560 // This formula isn't right, so check for month as a quick fix.
561 // It doesn't compensate for leap years and puts day 30 in month 1
562 // instead of month 0.
563 int month = isSet[MONTH]
564 ? fields[MONTH] : (dayOfYear * 5 + 3) / (31 + 30 + 31 + 30 + 31);
565 // This formula isn't right, so check for day as a quick fix. It
566 // doesn't compensate for leap years, either.
567 int day = isSet[DAY_OF_MONTH] ? fields[DAY_OF_MONTH]
568 : (6 + (dayOfYear * 5 + 3) % (31 + 30 + 31 + 30 + 31)) / 5;
569 int weekday = ((int) (time / (24 * 60 * 60 * 1000L)) + THURSDAY) % 7;
570 if (weekday <= 0)
571 weekday += 7;
572 int dstOffset = isSet[DST_OFFSET]
573 ? fields[DST_OFFSET] : (zone.getOffset((year < 0) ? BC : AD,
574 (year < 0) ? 1 - year : year,
575 month, day, weekday, millisInDay)
576 - zone.getRawOffset());
577 time -= rawOffset + dstOffset;
578 isTimeSet = true;
582 * <p>
583 * Determines if the given year is a leap year.
584 * </p>
585 * <p>
586 * To specify a year in the BC era, use a negative value calculated
587 * as 1 - y, where y is the required year in BC. So, 1 BC is 0,
588 * 2 BC is -1, 3 BC is -2, etc.
589 * </p>
591 * @param year a year (use a negative value for BC).
592 * @param gregorian if true, use the gregorian leap year rule.
593 * @return true, if the given year is a leap year, false otherwise.
595 private boolean isLeapYear(int year, boolean gregorian)
597 if ((year & 3) != 0)
598 // Only years divisible by 4 can be leap years
599 return false;
601 if (!gregorian)
602 return true;
604 // We rely on AD area here.
605 return ((year % 100) != 0 || (year % 400) == 0);
609 * Get the linear day in days since the epoch, using the
610 * Julian or Gregorian calendar as specified. If you specify a
611 * nonpositive year it is interpreted as BC as following: 0 is 1
612 * BC, -1 is 2 BC and so on.
614 * @param year the year of the date.
615 * @param dayOfYear the day of year of the date; 1 based.
616 * @param gregorian <code>true</code>, if we should use the Gregorian rules.
617 * @return the days since the epoch, may be negative.
619 private int getLinearDay(int year, int dayOfYear, boolean gregorian)
621 // The 13 is the number of days, that were omitted in the Gregorian
622 // Calender until the epoch.
623 // We shift right by 2 instead of dividing by 4, to get correct
624 // results for negative years (and this is even more efficient).
625 int julianDay = ((year * (365 * 4 + 1)) >> 2) + dayOfYear -
626 ((1970 * (365 * 4 + 1)) / 4 + 1 - 13);
628 if (gregorian)
630 // subtract the days that are missing in gregorian calendar
631 // with respect to julian calendar.
633 // Okay, here we rely on the fact that the gregorian
634 // calendar was introduced in the AD era. This doesn't work
635 // with negative years.
637 // The additional leap year factor accounts for the fact that
638 // a leap day is not seen on Jan 1 of the leap year.
639 int gregOffset = (year / 400) - (year / 100) + 2;
640 if (isLeapYear (year, true) && dayOfYear < 31 + 29)
641 --gregOffset;
642 julianDay += gregOffset;
644 return julianDay;
648 * Converts the given linear day into era, year, month,
649 * day_of_year, day_of_month, day_of_week, and writes the result
650 * into the fields array.
652 * @param day the linear day.
653 * @param gregorian true, if we should use Gregorian rules.
655 private void calculateDay(int day, boolean gregorian)
657 // the epoch is a Thursday.
658 int weekday = (day + THURSDAY) % 7;
659 if (weekday <= 0)
660 weekday += 7;
661 fields[DAY_OF_WEEK] = weekday;
663 // get a first approximation of the year. This may be one
664 // year too big.
665 int year = 1970 + (gregorian
666 ? ((day - 100) * 400) / (365 * 400 + 100 - 4 + 1)
667 : ((day - 100) * 4) / (365 * 4 + 1));
668 if (day >= 0)
669 year++;
671 int firstDayOfYear = getLinearDay(year, 1, gregorian);
673 // Now look in which year day really lies.
674 if (day < firstDayOfYear)
676 year--;
677 firstDayOfYear = getLinearDay(year, 1, gregorian);
680 day -= firstDayOfYear - 1; // day of year, one based.
682 fields[DAY_OF_YEAR] = day;
683 if (year <= 0)
685 fields[ERA] = BC;
686 fields[YEAR] = 1 - year;
688 else
690 fields[ERA] = AD;
691 fields[YEAR] = year;
694 int leapday = isLeapYear(year, gregorian) ? 1 : 0;
695 if (day <= 31 + 28 + leapday)
697 fields[MONTH] = day / 32; // 31->JANUARY, 32->FEBRUARY
698 fields[DAY_OF_MONTH] = day - 31 * fields[MONTH];
700 else
702 // A few more magic formulas
703 int scaledDay = (day - leapday) * 5 + 8;
704 fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31);
705 fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1;
710 * Converts the milliseconds since the epoch UTC
711 * (<code>time</code>) to time fields
712 * (<code>fields</code>).
714 protected synchronized void computeFields()
716 boolean gregorian = (time >= gregorianCutover);
718 TimeZone zone = getTimeZone();
719 fields[ZONE_OFFSET] = zone.getRawOffset();
720 long localTime = time + fields[ZONE_OFFSET];
722 int day = (int) (localTime / (24 * 60 * 60 * 1000L));
723 int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L));
724 if (millisInDay < 0)
726 millisInDay += (24 * 60 * 60 * 1000);
727 day--;
730 calculateDay(day, gregorian);
731 fields[DST_OFFSET] =
732 zone.getOffset(fields[ERA], fields[YEAR], fields[MONTH],
733 fields[DAY_OF_MONTH], fields[DAY_OF_WEEK],
734 millisInDay) - fields[ZONE_OFFSET];
736 millisInDay += fields[DST_OFFSET];
737 if (millisInDay >= 24 * 60 * 60 * 1000)
739 millisInDay -= 24 * 60 * 60 * 1000;
740 calculateDay(++day, gregorian);
743 fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7;
745 // which day of the week are we (0..6), relative to getFirstDayOfWeek
746 int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7;
748 fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] - relativeWeekday + 12) / 7;
750 int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7;
752 // Do the Correction: getMinimalDaysInFirstWeek() is always in the
753 // first week.
754 int minDays = getMinimalDaysInFirstWeek();
755 int firstWeekday =
756 (7 + getWeekDay(fields[YEAR], minDays) - getFirstDayOfWeek()) % 7;
757 if (minDays - firstWeekday < 1)
758 weekOfYear++;
759 fields[WEEK_OF_YEAR] = weekOfYear;
762 int hourOfDay = millisInDay / (60 * 60 * 1000);
763 fields[AM_PM] = (hourOfDay < 12) ? AM : PM;
764 int hour = hourOfDay % 12;
765 fields[HOUR] = (hour == 0) ? 12 : hour;
766 fields[HOUR_OF_DAY] = hourOfDay;
767 millisInDay %= (60 * 60 * 1000);
768 fields[MINUTE] = millisInDay / (60 * 1000);
769 millisInDay %= (60 * 1000);
770 fields[SECOND] = millisInDay / (1000);
771 fields[MILLISECOND] = millisInDay % 1000;
774 areFieldsSet = isSet[ERA] = isSet[YEAR] = isSet[MONTH] =
775 isSet[WEEK_OF_YEAR] = isSet[WEEK_OF_MONTH] =
776 isSet[DAY_OF_MONTH] = isSet[DAY_OF_YEAR] = isSet[DAY_OF_WEEK] =
777 isSet[DAY_OF_WEEK_IN_MONTH] = isSet[AM_PM] = isSet[HOUR] =
778 isSet[HOUR_OF_DAY] = isSet[MINUTE] = isSet[SECOND] =
779 isSet[MILLISECOND] = isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true;
784 * Compares the given calendar with this. An object, o, is
785 * equivalent to this if it is also a <code>GregorianCalendar</code>
786 * with the same time since the epoch under the same conditions
787 * (same change date and same time zone).
789 * @param o the object to that we should compare.
790 * @return true, if the given object is a calendar, that represents
791 * the same time (but doesn't necessarily have the same fields).
792 * @throws IllegalArgumentException if one of the fields
793 * <code>ZONE_OFFSET</code> or <code>DST_OFFSET</code> is
794 * specified, if an unknown field is specified or if one
795 * of the calendar fields receives an illegal value when
796 * leniancy is not enabled.
798 public boolean equals(Object o)
800 if (!(o instanceof GregorianCalendar))
801 return false;
803 GregorianCalendar cal = (GregorianCalendar) o;
804 return (cal.getTimeInMillis() == getTimeInMillis());
807 // /**
808 // * Compares the given calender with this.
809 // * @param o the object to that we should compare.
810 // * @return true, if the given object is a calendar, and this calendar
811 // * represents a smaller time than the calender o.
812 // */
813 // public boolean before(Object o) {
814 // if (!(o instanceof GregorianCalendar))
815 // return false;
817 // GregorianCalendar cal = (GregorianCalendar) o;
818 // return (cal.getTimeInMillis() < getTimeInMillis());
819 // }
821 // /**
822 // * Compares the given calender with this.
823 // * @param o the object to that we should compare.
824 // * @return true, if the given object is a calendar, and this calendar
825 // * represents a bigger time than the calender o.
826 // */
827 // public boolean after(Object o) {
828 // if (!(o instanceof GregorianCalendar))
829 // return false;
831 // GregorianCalendar cal = (GregorianCalendar) o;
832 // return (cal.getTimeInMillis() > getTimeInMillis());
833 // }
836 * Adds the specified amount of time to the given time field. The
837 * amount may be negative to subtract the time. If the field overflows
838 * it does what you expect: Jan, 25 + 10 Days is Feb, 4.
839 * @param field one of the time field constants.
840 * @param amount the amount of time to add.
841 * @exception IllegalArgumentException if <code>field</code> is
842 * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or invalid; or
843 * if <code>amount</code> contains an out-of-range value and the calendar
844 * is not in lenient mode.
846 public void add(int field, int amount)
848 switch (field)
850 case YEAR:
851 complete();
852 fields[YEAR] += amount;
853 isTimeSet = false;
854 break;
855 case MONTH:
856 complete();
857 int months = fields[MONTH] + amount;
858 fields[YEAR] += months / 12;
859 fields[MONTH] = months % 12;
860 if (fields[MONTH] < 0)
862 fields[MONTH] += 12;
863 fields[YEAR]--;
865 isTimeSet = false;
866 int maxDay = getActualMaximum(DAY_OF_MONTH);
867 if (fields[DAY_OF_MONTH] > maxDay)
869 fields[DAY_OF_MONTH] = maxDay;
870 isTimeSet = false;
872 break;
873 case DAY_OF_MONTH:
874 case DAY_OF_YEAR:
875 case DAY_OF_WEEK:
876 if (!isTimeSet)
877 computeTime();
878 time += amount * (24 * 60 * 60 * 1000L);
879 areFieldsSet = false;
880 break;
881 case WEEK_OF_YEAR:
882 case WEEK_OF_MONTH:
883 case DAY_OF_WEEK_IN_MONTH:
884 if (!isTimeSet)
885 computeTime();
886 time += amount * (7 * 24 * 60 * 60 * 1000L);
887 areFieldsSet = false;
888 break;
889 case AM_PM:
890 if (!isTimeSet)
891 computeTime();
892 time += amount * (12 * 60 * 60 * 1000L);
893 areFieldsSet = false;
894 break;
895 case HOUR:
896 case HOUR_OF_DAY:
897 if (!isTimeSet)
898 computeTime();
899 time += amount * (60 * 60 * 1000L);
900 areFieldsSet = false;
901 break;
902 case MINUTE:
903 if (!isTimeSet)
904 computeTime();
905 time += amount * (60 * 1000L);
906 areFieldsSet = false;
907 break;
908 case SECOND:
909 if (!isTimeSet)
910 computeTime();
911 time += amount * (1000L);
912 areFieldsSet = false;
913 break;
914 case MILLISECOND:
915 if (!isTimeSet)
916 computeTime();
917 time += amount;
918 areFieldsSet = false;
919 break;
920 case ZONE_OFFSET:
921 case DST_OFFSET:
922 default:
923 throw new IllegalArgumentException("Invalid or unknown field");
929 * Rolls the specified time field up or down. This means add one
930 * to the specified field, but don't change the other fields. If
931 * the maximum for this field is reached, start over with the
932 * minimum value.
934 * <strong>Note:</strong> There may be situation, where the other
935 * fields must be changed, e.g rolling the month on May, 31.
936 * The date June, 31 is automatically converted to July, 1.
937 * This requires lenient settings.
939 * @param field the time field. One of the time field constants.
940 * @param up the direction, true for up, false for down.
941 * @throws IllegalArgumentException if one of the fields
942 * <code>ZONE_OFFSET</code> or <code>DST_OFFSET</code> is
943 * specified, if an unknown field is specified or if one
944 * of the calendar fields receives an illegal value when
945 * leniancy is not enabled.
947 public void roll(int field, boolean up)
949 roll(field, up ? 1 : -1);
953 * Checks that the fields are still within their legal bounds,
954 * following use of the <code>roll()</code> method.
956 * @param field the field to check.
957 * @param delta multipler for alterations to the <code>time</code>.
958 * @see #roll(int, boolean)
959 * @see #roll(int, int)
961 private void cleanUpAfterRoll(int field, int delta)
963 switch (field)
965 case ERA:
966 case YEAR:
967 case MONTH:
968 // check that day of month is still in correct range
969 if (fields[DAY_OF_MONTH] > getActualMaximum(DAY_OF_MONTH))
970 fields[DAY_OF_MONTH] = getActualMaximum(DAY_OF_MONTH);
971 isTimeSet = false;
972 isSet[WEEK_OF_MONTH] = false;
973 isSet[DAY_OF_WEEK] = false;
974 isSet[DAY_OF_WEEK_IN_MONTH] = false;
975 isSet[DAY_OF_YEAR] = false;
976 isSet[WEEK_OF_YEAR] = false;
977 break;
979 case DAY_OF_MONTH:
980 isSet[WEEK_OF_MONTH] = false;
981 isSet[DAY_OF_WEEK] = false;
982 isSet[DAY_OF_WEEK_IN_MONTH] = false;
983 isSet[DAY_OF_YEAR] = false;
984 isSet[WEEK_OF_YEAR] = false;
985 time += delta * (24 * 60 * 60 * 1000L);
986 break;
988 case WEEK_OF_MONTH:
989 isSet[DAY_OF_MONTH] = false;
990 isSet[DAY_OF_WEEK_IN_MONTH] = false;
991 isSet[DAY_OF_YEAR] = false;
992 isSet[WEEK_OF_YEAR] = false;
993 time += delta * (7 * 24 * 60 * 60 * 1000L);
994 break;
995 case DAY_OF_WEEK_IN_MONTH:
996 isSet[DAY_OF_MONTH] = false;
997 isSet[WEEK_OF_MONTH] = false;
998 isSet[DAY_OF_YEAR] = false;
999 isSet[WEEK_OF_YEAR] = false;
1000 time += delta * (7 * 24 * 60 * 60 * 1000L);
1001 break;
1002 case DAY_OF_YEAR:
1003 isSet[MONTH] = false;
1004 isSet[DAY_OF_MONTH] = false;
1005 isSet[WEEK_OF_MONTH] = false;
1006 isSet[DAY_OF_WEEK_IN_MONTH] = false;
1007 isSet[DAY_OF_WEEK] = false;
1008 isSet[WEEK_OF_YEAR] = false;
1009 time += delta * (24 * 60 * 60 * 1000L);
1010 break;
1011 case WEEK_OF_YEAR:
1012 isSet[MONTH] = false;
1013 isSet[DAY_OF_MONTH] = false;
1014 isSet[WEEK_OF_MONTH] = false;
1015 isSet[DAY_OF_WEEK_IN_MONTH] = false;
1016 isSet[DAY_OF_YEAR] = false;
1017 time += delta * (7 * 24 * 60 * 60 * 1000L);
1018 break;
1020 case AM_PM:
1021 isSet[HOUR_OF_DAY] = false;
1022 time += delta * (12 * 60 * 60 * 1000L);
1023 break;
1024 case HOUR:
1025 isSet[HOUR_OF_DAY] = false;
1026 time += delta * (60 * 60 * 1000L);
1027 break;
1028 case HOUR_OF_DAY:
1029 isSet[HOUR] = false;
1030 isSet[AM_PM] = false;
1031 time += delta * (60 * 60 * 1000L);
1032 break;
1034 case MINUTE:
1035 time += delta * (60 * 1000L);
1036 break;
1037 case SECOND:
1038 time += delta * (1000L);
1039 break;
1040 case MILLISECOND:
1041 time += delta;
1042 break;
1047 * Rolls the specified time field by the given amount. This means
1048 * add amount to the specified field, but don't change the other
1049 * fields. If the maximum for this field is reached, start over
1050 * with the minimum value and vice versa for negative amounts.
1052 * <strong>Note:</strong> There may be situation, where the other
1053 * fields must be changed, e.g rolling the month on May, 31.
1054 * The date June, 31 is automatically corrected to June, 30.
1056 * @param field the time field. One of the time field constants.
1057 * @param amount the amount by which we should roll.
1058 * @throws IllegalArgumentException if one of the fields
1059 * <code>ZONE_OFFSET</code> or <code>DST_OFFSET</code> is
1060 * specified, if an unknown field is specified or if one
1061 * of the calendar fields receives an illegal value when
1062 * leniancy is not enabled.
1064 public void roll(int field, int amount)
1066 switch (field)
1068 case DAY_OF_WEEK:
1069 // day of week is special: it rolls automatically
1070 add(field, amount);
1071 return;
1072 case ZONE_OFFSET:
1073 case DST_OFFSET:
1074 throw new IllegalArgumentException("Can't roll time zone");
1076 complete();
1077 int min = getActualMinimum(field);
1078 int range = getActualMaximum(field) - min + 1;
1079 int oldval = fields[field];
1080 int newval = (oldval - min + range + amount) % range + min;
1081 if (newval < min)
1082 newval += range;
1083 fields[field] = newval;
1084 cleanUpAfterRoll(field, newval - oldval);
1088 * The minimum values for the calendar fields.
1090 private static final int[] minimums =
1091 { BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1,
1092 AM, 1, 0, 1, 1, 1, -(12*60*60*1000), 0 };
1095 * The maximum values for the calendar fields.
1097 private static final int[] maximums =
1098 { AD, 5000000, 11, 53, 5, 31, 366, SATURDAY, 5,
1099 PM, 12, 23, 59, 59, 999, +(12*60*60*1000), (12*60*60*1000) };
1102 * Gets the smallest value that is allowed for the specified field.
1104 * @param field one of the time field constants.
1105 * @return the smallest value for the specified field.
1107 public int getMinimum(int field)
1109 return minimums[field];
1113 * Gets the biggest value that is allowed for the specified field.
1115 * @param field one of the time field constants.
1116 * @return the biggest value.
1118 public int getMaximum(int field)
1120 return maximums[field];
1125 * Gets the greatest minimum value that is allowed for the specified field.
1126 * This is the largest value returned by the <code>getActualMinimum(int)</code>
1127 * method.
1129 * @param field the time field. One of the time field constants.
1130 * @return the greatest minimum value.
1131 * @see #getActualMinimum(int)
1133 public int getGreatestMinimum(int field)
1135 if (field == WEEK_OF_YEAR)
1136 return 1;
1137 return minimums[field];
1141 * Gets the smallest maximum value that is allowed for the
1142 * specified field. This is the smallest value returned
1143 * by the <code>getActualMaximum(int)</code>. For example,
1144 * this is 28 for DAY_OF_MONTH (as all months have at least
1145 * 28 days).
1147 * @param field the time field. One of the time field constants.
1148 * @return the least maximum value.
1149 * @see #getActualMaximum(int)
1150 * @since 1.2
1152 public int getLeastMaximum(int field)
1154 switch (field)
1156 case WEEK_OF_YEAR:
1157 return 52;
1158 case DAY_OF_MONTH:
1159 return 28;
1160 case DAY_OF_YEAR:
1161 return 365;
1162 case DAY_OF_WEEK_IN_MONTH:
1163 case WEEK_OF_MONTH:
1164 return 4;
1165 default:
1166 return maximums[field];
1171 * Gets the actual minimum value that is allowed for the specified field.
1172 * This value is dependent on the values of the other fields. Note that
1173 * this calls <code>complete()</code> if not enough fields are set. This
1174 * can have ugly side effects. The value given depends on the current
1175 * time used by this instance.
1177 * @param field the time field. One of the time field constants.
1178 * @return the actual minimum value.
1179 * @since 1.2
1181 public int getActualMinimum(int field)
1183 if (field == WEEK_OF_YEAR)
1185 int min = getMinimalDaysInFirstWeek();
1186 if (min == 0)
1187 return 1;
1188 if (!areFieldsSet || !isSet[ERA] || !isSet[YEAR])
1189 complete();
1191 int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1192 int weekday = getWeekDay(year, min);
1193 if ((7 + weekday - getFirstDayOfWeek()) % 7 >= min - 1)
1194 return 1;
1195 return 0;
1197 return minimums[field];
1201 * Gets the actual maximum value that is allowed for the specified field.
1202 * This value is dependent on the values of the other fields. Note that
1203 * this calls <code>complete()</code> if not enough fields are set. This
1204 * can have ugly side effects. The value given depends on the current time
1205 * used by this instance; thus, leap years have a maximum day of month value of
1206 * 29, rather than 28.
1208 * @param field the time field. One of the time field constants.
1209 * @return the actual maximum value.
1211 public int getActualMaximum(int field)
1213 switch (field)
1215 case WEEK_OF_YEAR:
1217 if (!areFieldsSet || !isSet[ERA] || !isSet[YEAR])
1218 complete();
1219 // This is wrong for the year that contains the gregorian change.
1220 // I.e it gives the weeks in the julian year or in the gregorian
1221 // year in that case.
1222 int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1223 int lastDay = isLeapYear(year) ? 366 : 365;
1224 int weekday = getWeekDay(year, lastDay);
1225 int week = (lastDay + 6
1226 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1228 int minimalDays = getMinimalDaysInFirstWeek();
1229 int firstWeekday = getWeekDay(year, minimalDays);
1231 * Is there a set of days at the beginning of the year, before the
1232 * first day of the week, equal to or greater than the minimum number
1233 * of days required in the first week?
1235 if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1)
1236 return week + 1; /* Add week 1: firstWeekday through to firstDayOfWeek */
1238 case DAY_OF_MONTH:
1240 if (!areFieldsSet || !isSet[MONTH])
1241 complete();
1242 int month = fields[MONTH];
1243 // If you change this, you should also change
1244 // SimpleTimeZone.getDaysInMonth();
1245 if (month == FEBRUARY)
1247 if (!isSet[YEAR] || !isSet[ERA])
1248 complete();
1249 int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1250 return isLeapYear(year) ? 29 : 28;
1252 else if (month < AUGUST)
1253 return 31 - (month & 1);
1254 else
1255 return 30 + (month & 1);
1257 case DAY_OF_YEAR:
1259 if (!areFieldsSet || !isSet[ERA] || !isSet[YEAR])
1260 complete();
1261 int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1262 return isLeapYear(year) ? 366 : 365;
1264 case DAY_OF_WEEK_IN_MONTH:
1266 // This is wrong for the month that contains the gregorian change.
1267 int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1268 // That's black magic, I know
1269 return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7;
1271 case WEEK_OF_MONTH:
1273 int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1274 int weekday = (daysInMonth - fields[DAY_OF_MONTH]
1275 + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY;
1276 return (daysInMonth + 6
1277 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1279 default:
1280 return maximums[field];