OSDN Git Service

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