OSDN Git Service

2002-08-30 Jesse Rosenstock <jmr@ugcs.caltech.edu>
[pf3gnuchains/gcc-fork.git] / libjava / java / util / Calendar.java
1 /* java.util.Calendar
2    Copyright (C) 1998, 1999, 2000, 2001, 2002 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    * @specnote This was made public in 1.4.
508    */
509   public long getTimeInMillis()
510   {
511     if (!isTimeSet)
512       computeTime();
513     return time;
514   }
515
516   /**
517    * Sets this Calendar's time to the given Time.  All time fields
518    * are invalidated by this method.
519    * @param time the time in milliseconds since the epoch
520    * @specnote This was made public in 1.4.
521    */
522   public void setTimeInMillis(long time)
523   {
524     this.time = time;
525     isTimeSet = true;
526     computeFields();
527   }
528
529   /**
530    * Gets the value of the specified field.  They are recomputed
531    * if they are invalid.
532    * @param field the time field. One of the time field constants.
533    * @return the value of the specified field
534    */
535   public final int get(int field)
536   {
537     // If the requested field is invalid, force all fields to be recomputed.
538     if (!isSet[field])
539       areFieldsSet = false;
540     complete();
541     return fields[field];
542   }
543
544   /**
545    * Gets the value of the specified field. This method doesn't 
546    * recompute the fields, if they are invalid.
547    * @param field the time field. One of the time field constants.
548    * @return the value of the specified field, undefined if
549    * <code>areFieldsSet</code> or <code>isSet[field]</code> is false.
550    */
551   protected final int internalGet(int field)
552   {
553     return fields[field];
554   }
555
556   /**
557    * Sets the time field with the given value.  This does invalidate
558    * the time in milliseconds.
559    * @param field the time field. One of the time field constants
560    * @param value the value to be set.
561    */
562   public final void set(int field, int value)
563   {
564     isTimeSet = false;
565     fields[field] = value;
566     isSet[field] = true;
567     switch (field)
568       {
569       case YEAR:
570       case MONTH:
571       case DATE:
572         isSet[WEEK_OF_YEAR] = false;
573         isSet[DAY_OF_YEAR] = false;
574         isSet[WEEK_OF_MONTH] = false;
575         isSet[DAY_OF_WEEK] = false;
576         isSet[DAY_OF_WEEK_IN_MONTH] = false;
577         break;
578       case AM_PM:
579         isSet[HOUR_OF_DAY] = false;
580         break;
581       case HOUR_OF_DAY:
582         isSet[AM_PM] = false;
583         isSet[HOUR] = false;
584         break;
585       case HOUR:
586         isSet[HOUR_OF_DAY] = false;
587         break;
588       }
589   }
590
591   /**
592    * Sets the fields for year, month, and date
593    * @param year the year.
594    * @param month the month, one of the constants JANUARY..UNDICEMBER.
595    * @param date the day of the month
596    */
597   public final void set(int year, int month, int date)
598   {
599     isTimeSet = false;
600     fields[YEAR] = year;
601     fields[MONTH] = month;
602     fields[DATE] = date;
603     isSet[YEAR] = isSet[MONTH] = isSet[DATE] = true;
604     isSet[WEEK_OF_YEAR] = false;
605     isSet[DAY_OF_YEAR] = false;
606     isSet[WEEK_OF_MONTH] = false;
607     isSet[DAY_OF_WEEK] = false;
608     isSet[DAY_OF_WEEK_IN_MONTH] = false;
609   }
610
611   /**
612    * Sets the fields for year, month, date, hour, and minute
613    * @param year the year.
614    * @param month the month, one of the constants JANUARY..UNDICEMBER.
615    * @param date the day of the month
616    * @param hour the hour of day.
617    * @param minute the minute.
618    */
619   public final void set(int year, int month, int date, int hour, int minute)
620   {
621     set(year, month, date);
622     fields[HOUR_OF_DAY] = hour;
623     fields[MINUTE] = minute;
624     isSet[HOUR_OF_DAY] = isSet[MINUTE] = true;
625     isSet[AM_PM] = false;
626     isSet[HOUR] = false;
627   }
628
629   /**
630    * Sets the fields for year, month, date, hour, and minute
631    * @param year the year.
632    * @param month the month, one of the constants JANUARY..UNDICEMBER.
633    * @param date the day of the month
634    * @param hour the hour of day.
635    * @param minute the minute.
636    * @param second the second.
637    */
638   public final void set(int year, int month, int date,
639                         int hour, int minute, int second)
640   {
641     set(year, month, date, hour, minute);
642     fields[SECOND] = second;
643     isSet[SECOND] = true;
644   }
645
646   /**
647    * Clears the values of all the time fields.
648    */
649   public final void clear()
650   {
651     isTimeSet = false;
652     areFieldsSet = false;
653     for (int i = 0; i < FIELD_COUNT; i++)
654       {
655         isSet[i] = false;
656         fields[i] = 0;
657       }
658   }
659
660   /**
661    * Clears the values of the specified time field.
662    * @param field the time field. One of the time field constants.
663    */
664   public final void clear(int field)
665   {
666     isTimeSet = false;
667     areFieldsSet = false;
668     isSet[field] = false;
669     fields[field] = 0;
670   }
671
672   /**
673    * Determines if the specified field has a valid value.
674    * @return true if the specified field has a value.
675    */
676   public final boolean isSet(int field)
677   {
678     return isSet[field];
679   }
680
681   /**
682    * Fills any unset fields in the time field list
683    * @return true if the specified field has a value.  
684    */
685   protected void complete()
686   {
687     if (!isTimeSet)
688       computeTime();
689     if (!areFieldsSet)
690       computeFields();
691   }
692
693   /**
694    * Compares the given calendar with this.  
695    * @param o the object to that we should compare.
696    * @return true, if the given object is a calendar, that represents
697    * the same time (but doesn't necessary have the same fields).
698    */
699   public boolean equals(Object o)
700   {
701     return (o instanceof Calendar)
702       && getTimeInMillis() == ((Calendar) o).getTimeInMillis();
703   }
704
705   /**
706    * Returns a hash code for this calendar.
707    * @return a hash code, which fullfits the general contract of 
708    * <code>hashCode()</code>
709    */
710   public int hashCode()
711   {
712     long time = getTimeInMillis();
713     return (int) ((time & 0xffffffffL) ^ (time >> 32));
714   }
715
716   /**
717    * Compares the given calendar with this.  
718    * @param o the object to that we should compare.
719    * @return true, if the given object is a calendar, and this calendar
720    * represents a smaller time than the calendar o.
721    * @exception ClassCastException if o is not an calendar.
722    * @since JDK1.2 you don't need to override this method
723    */
724   public boolean before(Object o)
725   {
726     return getTimeInMillis() < ((Calendar) o).getTimeInMillis();
727   }
728
729   /**
730    * Compares the given calendar with this.  
731    * @param o the object to that we should compare.
732    * @return true, if the given object is a calendar, and this calendar
733    * represents a bigger time than the calendar o.
734    * @exception ClassCastException if o is not an calendar.
735    * @since JDK1.2 you don't need to override this method
736    */
737   public boolean after(Object o)
738   {
739     return getTimeInMillis() > ((Calendar) o).getTimeInMillis();
740   }
741
742   /**
743    * Adds the specified amount of time to the given time field.  The
744    * amount may be negative to subtract the time.  If the field overflows
745    * it does what you expect: Jan, 25 + 10 Days is Feb, 4.
746    * @param field the time field. One of the time field constants.
747    * @param amount the amount of time.
748    */
749   public abstract void add(int field, int amount);
750
751   /**
752    * Rolls the specified time field up or down.  This means add one
753    * to the specified field, but don't change the other fields.  If
754    * the maximum for this field is reached, start over with the 
755    * minimum value.  <br>
756    *
757    * <strong>Note:</strong> There may be situation, where the other
758    * fields must be changed, e.g rolling the month on May, 31. 
759    * The date June, 31 is automatically converted to July, 1.
760    * @param field the time field. One of the time field constants.
761    * @param up the direction, true for up, false for down.
762    */
763   public abstract void roll(int field, boolean up);
764
765   /**
766    * Rolls up or down the specified time field by the given amount.
767    * A negative amount rolls down.  The default implementation is
768    * call <code>roll(int, boolean)</code> for the specified amount.
769    *
770    * Subclasses should override this method to do more intuitiv things.
771    *
772    * @param field the time field. One of the time field constants.
773    * @param amount the amount to roll by, positive for rolling up,
774    * negative for rolling down.  
775    * @since JDK1.2
776    */
777   public void roll(int field, int amount)
778   {
779     while (amount > 0)
780       {
781         roll(field, true);
782         amount--;
783       }
784     while (amount < 0)
785       {
786         roll(field, false);
787         amount++;
788       }
789   }
790
791
792   /**
793    * Sets the time zone to the specified value.
794    * @param zone the new time zone
795    */
796   public void setTimeZone(TimeZone zone)
797   {
798     this.zone = zone;
799   }
800
801   /**
802    * Gets the time zone of this calendar
803    * @return the current time zone.
804    */
805   public TimeZone getTimeZone()
806   {
807     return zone;
808   }
809
810   /**
811    * Specifies if the date/time interpretation should be lenient.
812    * If the flag is set, a date such as "February 30, 1996" will be
813    * treated as the 29th day after the February 1.  If this flag
814    * is false, such dates will cause an exception.
815    * @param lenient true, if the date should be interpreted linient,
816    * false if it should be interpreted strict.
817    */
818   public void setLenient(boolean lenient)
819   {
820     this.lenient = lenient;
821   }
822
823   /**
824    * Tells if the date/time interpretation is lenient.
825    * @return true, if the date should be interpreted linient,
826    * false if it should be interpreted strict.
827    */
828   public boolean isLenient()
829   {
830     return lenient;
831   }
832
833   /**
834    * Sets what the first day of week is.  This is used for
835    * WEEK_OF_MONTH and WEEK_OF_YEAR fields. 
836    * @param value the first day of week.  One of SUNDAY to SATURDAY.
837    */
838   public void setFirstDayOfWeek(int value)
839   {
840     firstDayOfWeek = value;
841   }
842
843   /**
844    * Gets what the first day of week is.  This is used for
845    * WEEK_OF_MONTH and WEEK_OF_YEAR fields. 
846    * @return the first day of week.  One of SUNDAY to SATURDAY.
847    */
848   public int getFirstDayOfWeek()
849   {
850     return firstDayOfWeek;
851   }
852
853   /**
854    * Sets how many days are required in the first week of the year.
855    * If the first day of the year should be the first week you should
856    * set this value to 1.  If the first week must be a full week, set
857    * it to 7.
858    * @param value the minimal days required in the first week.
859    */
860   public void setMinimalDaysInFirstWeek(int value)
861   {
862     minimalDaysInFirstWeek = value;
863   }
864
865   /**
866    * Gets how many days are required in the first week of the year.
867    * @return the minimal days required in the first week.
868    * @see #setMinimalDaysInFirstWeek
869    */
870   public int getMinimalDaysInFirstWeek()
871   {
872     return minimalDaysInFirstWeek;
873   }
874
875   /**
876    * Gets the smallest value that is allowed for the specified field.
877    * @param field the time field. One of the time field constants.
878    * @return the smallest value.
879    */
880   public abstract int getMinimum(int field);
881
882   /**
883    * Gets the biggest value that is allowed for the specified field.
884    * @param field the time field. One of the time field constants.
885    * @return the biggest value.
886    */
887   public abstract int getMaximum(int field);
888
889
890   /**
891    * Gets the greatest minimum value that is allowed for the specified field.
892    * @param field the time field. One of the time field constants.
893    * @return the greatest minimum value.
894    */
895   public abstract int getGreatestMinimum(int field);
896
897   /**
898    * Gets the smallest maximum value that is allowed for the
899    * specified field.  For example this is 28 for DAY_OF_MONTH.
900    * @param field the time field. One of the time field constants.
901    * @return the least maximum value.  
902    */
903   public abstract int getLeastMaximum(int field);
904
905   /**
906    * Gets the actual minimum value that is allowed for the specified field.
907    * This value is dependent on the values of the other fields.
908    * @param field the time field. One of the time field constants.
909    * @return the actual minimum value.
910    * @since jdk1.2
911    */
912   // FIXME: XXX: Not abstract in JDK 1.2.
913   public abstract int getActualMinimum(int field);
914
915   /**
916    * Gets the actual maximum value that is allowed for the specified field.
917    * This value is dependent on the values of the other fields.
918    * @param field the time field. One of the time field constants.
919    * @return the actual maximum value.  
920    * @since jdk1.2
921    */
922   // FIXME: XXX: Not abstract in JDK 1.2.
923   public abstract int getActualMaximum(int field);
924
925   /**
926    * Return a clone of this object.
927    */
928   public Object clone()
929   {
930     try
931       {
932         Calendar cal = (Calendar) super.clone();
933         cal.fields = (int[]) fields.clone();
934         cal.isSet = (boolean[])isSet.clone();
935         return cal;
936       }
937     catch (CloneNotSupportedException ex)
938       {
939         return null;
940       }
941   }
942
943   private final static String[] fieldNames = {
944     ",ERA=", ",YEAR=", ",MONTH=",
945     ",WEEK_OF_YEAR=", ",WEEK_OF_MONTH=",
946     ",DAY_OF_MONTH=", ",DAY_OF_YEAR=", ",DAY_OF_WEEK=",
947     ",DAY_OF_WEEK_IN_MONTH=",
948     ",AM_PM=", ",HOUR=", ",HOUR_OF_DAY=",
949     ",MINUTE=", ",SECOND=", ",MILLISECOND=",
950     ",ZONE_OFFSET=", ",DST_OFFSET="
951   };
952
953
954   /**
955    * Returns a string representation of this object.  It is mainly
956    * for debugging purposes and its content is implementation
957    * specific.
958    */
959   public String toString()
960   {
961     StringBuffer sb = new StringBuffer();
962     sb.append(getClass().getName()).append('[');
963     sb.append("time=");
964     if (isTimeSet)
965       sb.append(time);
966     else
967       sb.append("?");
968     sb.append(",zone=" + zone);
969     sb.append(",areFieldsSet=" + areFieldsSet);
970     for (int i = 0; i < FIELD_COUNT; i++)
971       {
972         sb.append(fieldNames[i]);
973         if (isSet[i])
974           sb.append(fields[i]);
975         else
976           sb.append("?");
977       }
978     sb.append(",lenient=").append(lenient);
979     sb.append(",firstDayOfWeek=").append(firstDayOfWeek);
980     sb.append(",minimalDaysInFirstWeek=").append(minimalDaysInFirstWeek);
981     sb.append("]");
982     return sb.toString();
983   }
984
985   /**
986    * Saves the state of the object to the stream.  Ideally we would
987    * only write the time field, but we need to be compatible with
988    * earlier versions. <br>
989    *
990    * This doesn't write the JDK1.1 field nextStamp to the stream, as
991    * I don't know what it is good for, and because the documentation
992    * says, that it could be omitted.  */
993   private void writeObject(ObjectOutputStream stream) throws IOException
994   {
995     if (!isTimeSet)
996       computeTime();
997     stream.defaultWriteObject();
998   }
999
1000   /**
1001    * Reads the object back from stream (deserialization).
1002    */
1003   private void readObject(ObjectInputStream stream)
1004     throws IOException, ClassNotFoundException
1005   {
1006     stream.defaultReadObject();
1007     if (!isTimeSet)
1008       computeTime();
1009
1010     if (serialVersionOnStream > 1)
1011       {
1012         // This is my interpretation of the serial number:
1013         // Sun wants to remove all fields from the stream someday
1014         // and will then increase the serialVersion number again.
1015         // We prepare to be compatible.
1016
1017         fields = new int[FIELD_COUNT];
1018         isSet = new boolean[FIELD_COUNT];
1019         areFieldsSet = false;
1020       }
1021   }
1022 }