OSDN Git Service

Fix for PR libgcj/1358:
[pf3gnuchains/gcc-fork.git] / libjava / java / util / Calendar.java
1 /* java.util.Calendar
2    Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 As a special exception, if you link this library with other files to
22 produce an executable, this library does not by itself cause the
23 resulting executable to be covered by the GNU General Public License.
24 This exception does not however invalidate any other reasons why the
25 executable file might be covered by the GNU General Public License. */
26
27
28 package java.util;
29 import java.lang.reflect.InvocationTargetException;
30 import java.io.*;
31
32 /**
33  * This class is an abstract base class for Calendars, which can be
34  * used to convert between <code>Date</code> objects and a set of
35  * integer fields which represent <code>YEAR</code>,
36  * <code>MONTH</code>, <code>DAY</code>, etc.  The <code>Date</code>
37  * object represents a time in milliseconds since the Epoch. <br>
38  * 
39  * This class is locale sensitive.  To get the Object matching the
40  * current locale you can use <code>getInstance</code>.  You can even provide
41  * a locale or a timezone.  <code>getInstance</code> returns currently
42  * a <code>GregorianCalendar</code> for the current date. <br>
43  *
44  * If you want to convert a date from the Year, Month, Day, DayOfWeek,
45  * etc.  Representation to a <code>Date</code>-Object, you can create
46  * a new Calendar with <code>getInstance()</code>,
47  * <code>clear()</code> all fields, <code>set(int,int)</code> the
48  * fields you need and convert it with <code>getTime()</code>. <br>
49  *
50  * If you want to convert a <code>Date</code>-object to the Calendar
51  * representation, create a new Calendar, assign the
52  * <code>Date</code>-Object with <code>setTime()</code>, and read the
53  * fields with <code>get(int)</code>. <br>
54  *
55  * When computing the date from time fields, it may happen, that there
56  * are either two few fields set, or some fields are inconsistent.  This
57  * cases will handled in a calender specific way.  Missing fields are
58  * replaced by the fields of the epoch: 1970 January 1 00:00. <br>
59  *
60  * To understand, how the day of year is computed out of the fields
61  * look at the following table.  It is traversed from top to bottom,
62  * and for the first line all fields are set, that line is used to
63  * compute the day. <br>
64  *
65  * <pre>
66  * month + day_of_month
67  * month + week_of_month + day_of_week
68  * month + day_of_week_of_month + day_of_week
69  * day_of_year
70  * day_of_week + week_of_year
71  * </pre>
72  * 
73  * The hour_of_day-field takes precedence over the ampm and
74  * hour_of_ampm fields. <br>
75  *
76  * <STRONG>Note:</STRONG> This can differ for non-Gregorian calendar. <br>
77  *
78  * To convert a calendar to a human readable form and vice versa,  use
79  * the <code>java.text.DateFormat</code> class. <br>
80  * 
81  * Other useful things you can do with an calendar, is
82  * <code>roll</code>ing fields (that means increase/decrease a
83  * specific field by one, propagating overflows), or
84  * <code>add</code>ing/substracting a fixed amount to a field.
85  *
86  * @see Date
87  * @see GregorianCalendar
88  * @see TimeZone
89  * @see java.text.DateFormat 
90  */
91 public abstract class Calendar implements Serializable, Cloneable
92 {
93   /**
94    * Constant representing the era time field.
95    */
96   public static final int ERA = 0;
97   /**
98    * Constant representing the year time field.
99    */
100   public static final int YEAR = 1;
101   /**
102    * Constant representing the month time field.  This field
103    * should contain one of the JANUARY,...,DECEMBER constants below.
104    */
105   public static final int MONTH = 2;
106   /**
107    * Constant representing the week of the year field.
108    * @see #setFirstDayOfWeek(int)
109    */
110   public static final int WEEK_OF_YEAR = 3;
111   /**
112    * Constant representing the week of the month time field.
113    * @see #setFirstDayOfWeek(int)
114    */
115   public static final int WEEK_OF_MONTH = 4;
116   /**
117    * Constant representing the day time field, synonym for DAY_OF_MONTH.
118    */
119   public static final int DATE = 5;
120   /**
121    * Constant representing the day time field.
122    */
123   public static final int DAY_OF_MONTH = 5;
124   /**
125    * Constant representing the day of year time field.  This is
126    * 1 for the first day in month.
127    */
128   public static final int DAY_OF_YEAR = 6;
129   /**
130    * Constant representing the day of week time field.  This field
131    * should contain one of the SUNDAY,...,SATURDAY constants below.
132    */
133   public static final int DAY_OF_WEEK = 7;
134   /**
135    * Constant representing the day-of-week-in-month field.  For
136    * instance this field contains 2 for the second thursday in a
137    * month.  If you give a negative number here, the day will count
138    * from the end of the month.
139    */
140   public static final int DAY_OF_WEEK_IN_MONTH = 8;
141   /**
142    * Constant representing the part of the day for 12-hour clock.  This
143    * should be one of AM or PM.
144    */
145   public static final int AM_PM = 9;
146   /**
147    * Constant representing the hour time field for 12-hour clock.
148    */
149   public static final int HOUR = 10;
150   /**
151    * Constant representing the hour of day time field for 24-hour clock.
152    */
153   public static final int HOUR_OF_DAY = 11;
154   /**
155    * Constant representing the minute of hour time field.
156    */
157   public static final int MINUTE = 12;
158   /**
159    * Constant representing the second time field.
160    */
161   public static final int SECOND = 13;
162   /**
163    * Constant representing the millisecond time field.
164    */
165   public static final int MILLISECOND = 14;
166   /**
167    * Constant representing the time zone offset time field for the
168    * time given in the other fields.  It is measured in
169    * milliseconds.  The default is the offset of the time zone.  
170    */
171   public static final int ZONE_OFFSET = 15;
172   /**
173    * Constant representing the daylight saving time offset in
174    * milliseconds.  The default is the value given by the time zone.  
175    */
176   public static final int DST_OFFSET = 16;
177   /**
178    * Number of time fields.
179    */
180   public static final int FIELD_COUNT = 17;
181
182   /**
183    * Constant representing Sunday.
184    */
185   public static final int SUNDAY = 1;
186   /**
187    * Constant representing Monday.
188    */
189   public static final int MONDAY = 2;
190   /**
191    * Constant representing Tuesday.
192    */
193   public static final int TUESDAY = 3;
194   /**
195    * Constant representing Wednesday.
196    */
197   public static final int WEDNESDAY = 4;
198   /**
199    * Constant representing Thursday.
200    */
201   public static final int THURSDAY = 5;
202   /**
203    * Constant representing Friday.
204    */
205   public static final int FRIDAY = 6;
206   /**
207    * Constant representing Saturday.
208    */
209   public static final int SATURDAY = 7;
210
211   /**
212    * Constant representing January.
213    */
214   public static final int JANUARY = 0;
215   /**
216    * Constant representing February.
217    */
218   public static final int FEBRUARY = 1;
219   /**
220    * Constant representing March.
221    */
222   public static final int MARCH = 2;
223   /**
224    * Constant representing April.
225    */
226   public static final int APRIL = 3;
227   /**
228    * Constant representing May.
229    */
230   public static final int MAY = 4;
231   /**
232    * Constant representing June.
233    */
234   public static final int JUNE = 5;
235   /**
236    * Constant representing July.
237    */
238   public static final int JULY = 6;
239   /**
240    * Constant representing August.
241    */
242   public static final int AUGUST = 7;
243   /**
244    * Constant representing September.
245    */
246   public static final int SEPTEMBER = 8;
247   /**
248    * Constant representing October.
249    */
250   public static final int OCTOBER = 9;
251   /**
252    * Constant representing November.
253    */
254   public static final int NOVEMBER = 10;
255   /**
256    * Constant representing December.
257    */
258   public static final int DECEMBER = 11;
259   /**
260    * Constant representing Undecimber. This is an artificial name useful
261    * for lunar calendars.
262    */
263   public static final int UNDECIMBER = 12;
264
265   /**
266    * Useful constant for 12-hour clock.
267    */
268   public static final int AM = 0;
269   /**
270    * Useful constant for 12-hour clock.
271    */
272   public static final int PM = 1;
273
274   /**
275    * The time fields.  The array is indexed by the constants YEAR to
276    * DST_OFFSET.
277    * @serial
278    */
279   protected int[] fields = new int[FIELD_COUNT];
280   /**
281    * The flags which tell if the fields above have a value.
282    * @serial
283    */
284   protected boolean[] isSet = new boolean[FIELD_COUNT];
285   /**
286    * The time in milliseconds since the epoch.
287    * @serial
288    */
289   protected long time;
290   /**
291    * Tells if the above field has a valid value.
292    * @serial
293    */
294   protected boolean isTimeSet;
295   /**
296    * Tells if the fields have a valid value.  This superseeds the isSet
297    * array.
298    * @serial
299    */
300   protected boolean areFieldsSet;
301
302   /**
303    * The time zone of this calendar.  Used by sub classes to do UTC / local
304    * time conversion.  Sub classes can access this field with getTimeZone().
305    * @serial
306    */
307   private TimeZone zone;
308
309   /**
310    * Specifies if the date/time interpretation should be lenient.
311    * If the flag is set, a date such as "February 30, 1996" will be
312    * treated as the 29th day after the February 1.  If this flag
313    * is false, such dates will cause an exception.
314    * @serial
315    */
316   private boolean lenient;
317
318   /**
319    * Sets what the first day of week is.  This is used for
320    * WEEK_OF_MONTH and WEEK_OF_YEAR fields. 
321    * @serial
322    */
323   private int firstDayOfWeek;
324
325   /**
326    * Sets how many days are required in the first week of the year.
327    * If the first day of the year should be the first week you should
328    * set this value to 1.  If the first week must be a full week, set
329    * it to 7.
330    * @serial
331    */
332   private int minimalDaysInFirstWeek;
333
334   /**
335    * The version of the serialized data on the stream. 
336    * <dl><dt>0 or not present</dt>
337    * <dd> JDK 1.1.5 or later.</dd>
338    * <dl><dt>1</dt>
339    * <dd>JDK 1.1.6 or later.  This always writes a correct `time' value
340    * on the stream, as well as the other fields, to be compatible with
341    * earlier versions</dd>
342    * @since JDK1.1.6
343    * @serial
344    */
345   private int serialVersionOnStream = 1;
346
347   /**
348    * XXX - I have not checked the compatibility.  The documentation of
349    * the serialized-form is quite hairy...
350    */
351   static final long serialVersionUID = -1807547505821590642L;
352
353   /**
354    * The name of the resource bundle.
355    */
356   private static final String bundleName = "gnu.java.locale.Calendar";
357
358   /**
359    * Constructs a new Calender with the default time zone and the default
360    * locale.
361    */
362   protected Calendar()
363   {
364     this(TimeZone.getDefault(), Locale.getDefault());
365   }
366
367   /**
368    * Constructs a new Calender with the given time zone and the given
369    * locale.
370    * @param zone a time zone.
371    * @param locale a locale.
372    */
373   protected Calendar(TimeZone zone, Locale locale)
374   {
375     this.zone = zone;
376     lenient = true;
377
378     ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale);
379
380     firstDayOfWeek = ((Integer) rb.getObject("firstDayOfWeek")).intValue();
381     minimalDaysInFirstWeek =
382       ((Integer) rb.getObject("minimalDaysInFirstWeek")).intValue();
383   }
384
385   /**
386    * Creates a calendar representing the actual time, using the default
387    * time zone and locale.
388    */
389   public static synchronized Calendar getInstance()
390   {
391     return getInstance(TimeZone.getDefault(), Locale.getDefault());
392   }
393
394   /**
395    * Creates a calendar representing the actual time, using the given
396    * time zone and the default locale.
397    * @param zone a time zone.
398    */
399   public static synchronized Calendar getInstance(TimeZone zone)
400   {
401     return getInstance(zone, Locale.getDefault());
402   }
403
404   /**
405    * Creates a calendar representing the actual time, using the default
406    * time zone and the given locale.
407    * @param locale a locale.
408    */
409   public static synchronized Calendar getInstance(Locale locale)
410   {
411     return getInstance(TimeZone.getDefault(), locale);
412   }
413
414   /**
415    * Creates a calendar representing the actual time, using the given
416    * time zone and locale.
417    * @param zone a time zone.
418    * @param locale a locale.
419    */
420   public static synchronized Calendar getInstance(TimeZone zone, Locale locale)
421   {
422     String calendarClassName = null;
423     ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale);
424     calendarClassName = rb.getString("calendarClass");
425     if (calendarClassName != null)
426       {
427         try
428           {
429             Class calendarClass = Class.forName(calendarClassName);
430             if (Calendar.class.isAssignableFrom(calendarClass))
431               {
432                 return (Calendar) calendarClass.getConstructor(
433                   new Class[] { TimeZone.class, Locale.class}
434                 ).newInstance(new Object[] {zone, locale} );
435               }
436           }
437         catch (ClassNotFoundException ex) {}
438         catch (IllegalAccessException ex) {}
439         catch (NoSuchMethodException ex) {}
440         catch (InstantiationException ex) {}
441         catch (InvocationTargetException ex) {}
442         // XXX should we ignore these errors or throw an exception ?
443       }
444     return new GregorianCalendar(zone, locale);
445   }
446
447   /**
448    * Gets the set of locales for which a Calendar is availiable.
449    * @exception MissingResourceException if locale data couldn't be found.
450    * @return the set of locales.
451    */
452   public static synchronized Locale[] getAvailableLocales()
453   {
454     ResourceBundle rb = ResourceBundle.getBundle(bundleName,
455                                                  new Locale("", ""));
456     return (Locale[]) rb.getObject("availableLocales");
457   }
458
459   /**
460    * Converts the time field values (<code>fields</code>) to
461    * milliseconds since the epoch UTC (<code>time</code>).  Override
462    * this method if you write your own Calendar.  */
463   protected abstract void computeTime();
464
465   /**
466    * Converts the milliseconds since the epoch UTC
467    * (<code>time</code>) to time fields
468    * (<code>fields</code>). Override this method if you write your
469    * own Calendar.  
470    */
471   protected abstract void computeFields();
472
473   /**
474    * Converts the time represented by this object to a
475    * <code>Date</code>-Object.
476    * @return the Date.
477    */
478   public final Date getTime()
479   {
480     if (!isTimeSet)
481       computeTime();
482     return new Date(time);
483   }
484
485   /**
486    * Sets this Calender's time to the given Date.  All time fields
487    * are invalidated by this method.
488    */
489   public final void setTime(Date date)
490   {
491     setTimeInMillis(date.getTime());
492   }
493
494   /**
495    * Returns the time represented by this Calendar.
496    * @return the time in milliseconds since the epoch.
497    */
498   protected long getTimeInMillis()
499   {
500     if (!isTimeSet)
501       computeTime();
502     return time;
503   }
504
505   /**
506    * Sets this Calender's time to the given Time.  All time fields
507    * are invalidated by this method.
508    * @param time the time in milliseconds since the epoch
509    */
510   protected void setTimeInMillis(long time)
511   {
512     this.time = time;
513     isTimeSet = true;
514     computeFields();
515   }
516
517   /**
518    * Gets the value of the specified field.  They are recomputed
519    * if they are invalid.
520    * @param field the time field. One of the time field constants.
521    * @return the value of the specified field
522    */
523   public final int get(int field)
524   {
525     complete();
526     return fields[field];
527   }
528
529   /**
530    * Gets the value of the specified field. This method doesn't 
531    * recompute the fields, if they are invalid.
532    * @param field the time field. One of the time field constants.
533    * @return the value of the specified field, undefined if
534    * <code>areFieldsSet</code> or <code>isSet[field]</code> is false.
535    */
536   protected final int internalGet(int field)
537   {
538     return fields[field];
539   }
540
541   /**
542    * Sets the time field with the given value.  This does invalidate
543    * the time in milliseconds.
544    * @param field the time field. One of the time field constants
545    * @param value the value to be set.
546    */
547   public final void set(int field, int value)
548   {
549     if (!areFieldsSet)
550       computeFields();
551     isTimeSet = false;
552     fields[field] = value;
553     isSet[field] = true;
554   }
555
556   /**
557    * Sets the fields for year, month, and date
558    * @param year the year.
559    * @param month the month, one of the constants JANUARY..UNDICEMBER.
560    * @param date the day of the month
561    */
562   public final void set(int year, int month, int date)
563   {
564     if (!areFieldsSet)
565       computeFields();
566     isTimeSet = false;
567     fields[YEAR] = year;
568     fields[MONTH] = month;
569     fields[DATE] = date;
570     isSet[YEAR] = isSet[MONTH] = isSet[DATE] = true;
571   }
572
573   /**
574    * Sets the fields for year, month, date, hour, and minute
575    * @param year the year.
576    * @param month the month, one of the constants JANUARY..UNDICEMBER.
577    * @param date the day of the month
578    * @param hour the hour of day.
579    * @param minute the minute.
580    */
581   public final void set(int year, int month, int date, int hour, int minute)
582   {
583     set(year, month, date);
584     fields[HOUR_OF_DAY] = hour;
585     fields[MINUTE] = minute;
586     isSet[HOUR_OF_DAY] = isSet[MINUTE] = true;
587   }
588
589   /**
590    * Sets the fields for year, month, date, hour, and minute
591    * @param year the year.
592    * @param month the month, one of the constants JANUARY..UNDICEMBER.
593    * @param date the day of the month
594    * @param hour the hour of day.
595    * @param minute the minute.
596    * @param second the second.
597    */
598   public final void set(int year, int month, int date,
599                         int hour, int minute, int second)
600   {
601     set(year, month, date, hour, minute);
602     fields[SECOND] = second;
603     isSet[SECOND] = true;
604   }
605
606   /**
607    * Clears the values of all the time fields.
608    */
609   public final void clear()
610   {
611     isTimeSet = false;
612     areFieldsSet = false;
613     for (int i = 0; i < FIELD_COUNT; i++)
614       isSet[i] = false;
615   }
616
617   /**
618    * Clears the values of the specified time field.
619    * @param field the time field. One of the time field constants.
620    */
621   public final void clear(int field)
622   {
623     isTimeSet = false;
624     areFieldsSet = false;
625     isSet[field] = false;
626   }
627
628   /**
629    * Determines if the specified field has a valid value.
630    * @return true if the specified field has a value.
631    */
632   public final boolean isSet(int field)
633   {
634     return isSet[field];
635   }
636
637   /**
638    * Fills any unset fields in the time field list
639    * @return true if the specified field has a value.  
640    */
641   protected void complete()
642   {
643     if (!isTimeSet)
644       computeTime();
645     if (!areFieldsSet)
646       computeFields();
647   }
648
649   /**
650    * Compares the given calender with this.  
651    * @param o the object to that we should compare.
652    * @return true, if the given object is a calendar, that represents
653    * the same time (but doesn't neccessary have the same fields).
654    */
655   public boolean equals(Object o)
656   {
657     return (o instanceof Calendar)
658       && getTimeInMillis() == ((Calendar) o).getTimeInMillis();
659   }
660
661   /**
662    * Returns a hash code for this calendar.
663    * @return a hash code, which fullfits the general contract of 
664    * <code>hashCode()</code>
665    */
666   public int hashCode()
667   {
668     long time = getTimeInMillis();
669     return (int) ((time & 0xffffffffL) ^ (time >> 32));
670   }
671
672   /**
673    * Compares the given calender with this.  
674    * @param o the object to that we should compare.
675    * @return true, if the given object is a calendar, and this calendar
676    * represents a smaller time than the calender o.
677    * @exception ClassCastException if o is not an calendar.
678    * @since JDK1.2 you don't need to override this method
679    */
680   public boolean before(Object o)
681   {
682     return getTimeInMillis() < ((Calendar) o).getTimeInMillis();
683   }
684
685   /**
686    * Compares the given calender with this.  
687    * @param o the object to that we should compare.
688    * @return true, if the given object is a calendar, and this calendar
689    * represents a bigger time than the calender o.
690    * @exception ClassCastException if o is not an calendar.
691    * @since JDK1.2 you don't need to override this method
692    */
693   public boolean after(Object o)
694   {
695     return getTimeInMillis() > ((Calendar) o).getTimeInMillis();
696   }
697
698   /**
699    * Adds the specified amount of time to the given time field.  The
700    * amount may be negative to subtract the time.  If the field overflows
701    * it does what you expect: Jan, 25 + 10 Days is Feb, 4.
702    * @param field the time field. One of the time field constants.
703    * @param amount the amount of time.
704    */
705   public abstract void add(int field, int amount);
706
707   /**
708    * Rolls the specified time field up or down.  This means add one
709    * to the specified field, but don't change the other fields.  If
710    * the maximum for this field is reached, start over with the 
711    * minimum value.  <br>
712    *
713    * <strong>Note:</strong> There may be situation, where the other
714    * fields must be changed, e.g rolling the month on May, 31. 
715    * The date June, 31 is automatically converted to July, 1.
716    * @param field the time field. One of the time field constants.
717    * @param up the direction, true for up, false for down.
718    */
719   public abstract void roll(int field, boolean up);
720
721   /**
722    * Rolls up or down the specified time field by the given amount.
723    * A negative amount rolls down.  The default implementation is
724    * call <code>roll(int, boolean)</code> for the specified amount.
725    *
726    * Subclasses should override this method to do more intuitiv things.
727    *
728    * @param field the time field. One of the time field constants.
729    * @param amount the amount to roll by, positive for rolling up,
730    * negative for rolling down.  
731    * @since JDK1.2
732    */
733   public void roll(int field, int amount)
734   {
735     while (amount > 0)
736       {
737         roll(field, true);
738         amount--;
739       }
740     while (amount < 0)
741       {
742         roll(field, false);
743         amount++;
744       }
745   }
746
747
748   /**
749    * Sets the time zone to the specified value.
750    * @param zone the new time zone
751    */
752   public void setTimeZone(TimeZone zone)
753   {
754     this.zone = zone;
755   }
756
757   /**
758    * Gets the time zone of this calendar
759    * @return the current time zone.
760    */
761   public TimeZone getTimeZone()
762   {
763     return zone;
764   }
765
766   /**
767    * Specifies if the date/time interpretation should be lenient.
768    * If the flag is set, a date such as "February 30, 1996" will be
769    * treated as the 29th day after the February 1.  If this flag
770    * is false, such dates will cause an exception.
771    * @param lenient true, if the date should be interpreted linient,
772    * false if it should be interpreted strict.
773    */
774   public void setLenient(boolean lenient)
775   {
776     this.lenient = lenient;
777   }
778
779   /**
780    * Tells if the date/time interpretation is lenient.
781    * @return true, if the date should be interpreted linient,
782    * false if it should be interpreted strict.
783    */
784   public boolean isLenient()
785   {
786     return lenient;
787   }
788
789   /**
790    * Sets what the first day of week is.  This is used for
791    * WEEK_OF_MONTH and WEEK_OF_YEAR fields. 
792    * @param value the first day of week.  One of SUNDAY to SATURDAY.
793    */
794   public void setFirstDayOfWeek(int value)
795   {
796     firstDayOfWeek = value;
797   }
798
799   /**
800    * Gets what the first day of week is.  This is used for
801    * WEEK_OF_MONTH and WEEK_OF_YEAR fields. 
802    * @return the first day of week.  One of SUNDAY to SATURDAY.
803    */
804   public int getFirstDayOfWeek()
805   {
806     return firstDayOfWeek;
807   }
808
809   /**
810    * Sets how many days are required in the first week of the year.
811    * If the first day of the year should be the first week you should
812    * set this value to 1.  If the first week must be a full week, set
813    * it to 7.
814    * @param value the minimal days required in the first week.
815    */
816   public void setMinimalDaysInFirstWeek(int value)
817   {
818     minimalDaysInFirstWeek = value;
819   }
820
821   /**
822    * Gets how many days are required in the first week of the year.
823    * @return the minimal days required in the first week.
824    * @see #setMinimalDaysInFirstWeek
825    */
826   public int getMinimalDaysInFirstWeek()
827   {
828     return minimalDaysInFirstWeek;
829   }
830
831   /**
832    * Gets the smallest value that is allowed for the specified field.
833    * @param field the time field. One of the time field constants.
834    * @return the smallest value.
835    */
836   public abstract int getMinimum(int field);
837
838   /**
839    * Gets the biggest value that is allowed for the specified field.
840    * @param field the time field. One of the time field constants.
841    * @return the biggest value.
842    */
843   public abstract int getMaximum(int field);
844
845
846   /**
847    * Gets the greatest minimum value that is allowed for the specified field.
848    * @param field the time field. One of the time field constants.
849    * @return the greatest minimum value.
850    */
851   public abstract int getGreatestMinimum(int field);
852
853   /**
854    * Gets the smallest maximum value that is allowed for the
855    * specified field.  For example this is 28 for DAY_OF_MONTH.
856    * @param field the time field. One of the time field constants.
857    * @return the least maximum value.  
858    */
859   public abstract int getLeastMaximum(int field);
860
861   /**
862    * Gets the actual minimum value that is allowed for the specified field.
863    * This value is dependant on the values of the other fields.
864    * @param field the time field. One of the time field constants.
865    * @return the actual minimum value.
866    * @since jdk1.2
867    */
868   // FIXME: XXX: Not abstract in JDK 1.2.
869   // public abstract int getActualMinimum(int field);
870
871   /**
872    * Gets the actual maximum value that is allowed for the specified field.
873    * This value is dependant on the values of the other fields.
874    * @param field the time field. One of the time field constants.
875    * @return the actual maximum value.  
876    * @since jdk1.2
877    */
878   // FIXME: XXX: Not abstract in JDK 1.2.
879   // public abstract int getActualMaximum(int field);
880
881   /**
882    * Return a clone of this object.
883    */
884   public Object clone()
885   {
886     try
887       {
888         Calendar cal = (Calendar) super.clone();
889         cal.fields = (int[]) fields.clone();
890         cal.isSet = (boolean[])isSet.clone();
891         return cal;
892       }
893     catch (CloneNotSupportedException ex)
894       {
895         return null;
896       }
897   }
898
899   private final static String[] fieldNames = {
900     ",ERA=", ",YEAR=", ",MONTH=",
901     ",WEEK_OF_YEAR=", ",WEEK_OF_MONTH=",
902     ",DAY_OF_MONTH=", ",DAY_OF_YEAR=", ",DAY_OF_WEEK=",
903     ",DAY_OF_WEEK_IN_MONTH=",
904     ",AM_PM=", ",HOUR=", ",HOUR_OF_DAY=",
905     ",MINUTE=", ",SECOND=", ",MILLISECOND=",
906     ",ZONE_OFFSET=", ",DST_OFFSET="
907   };
908
909
910   /**
911    * Returns a string representation of this object.  It is mainly
912    * for debugging purposes and its content is implementation
913    * specific.
914    */
915   public String toString()
916   {
917     StringBuffer sb = new StringBuffer();
918     sb.append(getClass().getName()).append('[');
919     sb.append("time=");
920     if (isTimeSet)
921       sb.append(time);
922     else
923       sb.append("?");
924     sb.append(",zone=" + zone);
925     sb.append(",areFieldsSet=" + areFieldsSet);
926     for (int i = 0; i < FIELD_COUNT; i++)
927       {
928         sb.append(fieldNames[i]);
929         if (isSet[i])
930           sb.append(fields[i]);
931         else
932           sb.append("?");
933       }
934     sb.append(",lenient=").append(lenient);
935     sb.append(",firstDayOfWeek=").append(firstDayOfWeek);
936     sb.append(",minimalDaysInFirstWeek=").append(minimalDaysInFirstWeek);
937     sb.append("]");
938     return sb.toString();
939   }
940
941   /**
942    * Saves the state of the object to the stream.  Ideally we would
943    * only write the time field, but we need to be compatible with
944    * earlier versions. <br>
945    *
946    * This doesn't write the JDK1.1 field nextStamp to the stream, as
947    * I don't know what it is good for, and because the documentation
948    * says, that it could be omitted.  */
949   private void writeObject(ObjectOutputStream stream) throws IOException
950   {
951     if (!isTimeSet)
952       computeTime();
953     stream.defaultWriteObject();
954   }
955
956   /**
957    * Reads the object back from stream (deserialization).
958    */
959   private void readObject(ObjectInputStream stream)
960     throws IOException, ClassNotFoundException
961   {
962     stream.defaultReadObject();
963     if (!isTimeSet)
964       computeTime();
965
966     if (serialVersionOnStream > 1)
967       {
968         // This is my interpretation of the serial number:
969         // Sun wants to remove all fields from the stream someday
970         // and will then increase the serialVersion number again.
971         // We prepare to be compatible.
972
973         fields = new int[FIELD_COUNT];
974         isSet = new boolean[FIELD_COUNT];
975         areFieldsSet = false;
976       }
977   }
978 }