OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [java/] [util/] [Calendar.java] - Blame information for rev 771

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 771 jeremybenn
/* Calendar.java --
2
   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006,
3
   Free Software Foundation, Inc.
4
 
5
This file is part of GNU Classpath.
6
 
7
GNU Classpath is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
10
any later version.
11
 
12
GNU Classpath is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with GNU Classpath; see the file COPYING.  If not, write to the
19
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20
02110-1301 USA.
21
 
22
Linking this library statically or dynamically with other modules is
23
making a combined work based on this library.  Thus, the terms and
24
conditions of the GNU General Public License cover the whole
25
combination.
26
 
27
As a special exception, the copyright holders of this library give you
28
permission to link this library with independent modules to produce an
29
executable, regardless of the license terms of these independent
30
modules, and to copy and distribute the resulting executable under
31
terms of your choice, provided that you also meet, for each linked
32
independent module, the terms and conditions of the license of that
33
module.  An independent module is a module which is not derived from
34
or based on this library.  If you modify this library, you may extend
35
this exception to your version of the library, but you are not
36
obligated to do so.  If you do not wish to do so, delete this
37
exception statement from your version. */
38
 
39
 
40
package java.util;
41
 
42
import gnu.java.lang.CPStringBuilder;
43
 
44
import java.io.IOException;
45
import java.io.ObjectInputStream;
46
import java.io.ObjectOutputStream;
47
import java.io.Serializable;
48
 
49
import java.lang.reflect.Constructor;
50
import java.lang.reflect.InvocationTargetException;
51
 
52
import java.text.DateFormatSymbols;
53
 
54
/**
55
 * This class is an abstract base class for Calendars, which can be
56
 * used to convert between <code>Date</code> objects and a set of
57
 * integer fields which represent <code>YEAR</code>,
58
 * <code>MONTH</code>, <code>DAY</code>, etc.  The <code>Date</code>
59
 * object represents a time in milliseconds since the Epoch. <br>
60
 *
61
 * This class is locale sensitive.  To get the Object matching the
62
 * current locale you can use <code>getInstance</code>.  You can even provide
63
 * a locale or a timezone.  <code>getInstance</code> returns currently
64
 * a <code>GregorianCalendar</code> for the current date. <br>
65
 *
66
 * If you want to convert a date from the Year, Month, Day, DayOfWeek,
67
 * etc.  Representation to a <code>Date</code>-Object, you can create
68
 * a new Calendar with <code>getInstance()</code>,
69
 * <code>clear()</code> all fields, <code>set(int,int)</code> the
70
 * fields you need and convert it with <code>getTime()</code>. <br>
71
 *
72
 * If you want to convert a <code>Date</code>-object to the Calendar
73
 * representation, create a new Calendar, assign the
74
 * <code>Date</code>-Object with <code>setTime()</code>, and read the
75
 * fields with <code>get(int)</code>. <br>
76
 *
77
 * When computing the date from time fields, it may happen, that there
78
 * are either two few fields set, or some fields are inconsistent.  This
79
 * cases will handled in a calendar specific way.  Missing fields are
80
 * replaced by the fields of the epoch: 1970 January 1 00:00. <br>
81
 *
82
 * To understand, how the day of year is computed out of the fields
83
 * look at the following table.  It is traversed from top to bottom,
84
 * and for the first line all fields are set, that line is used to
85
 * compute the day. <br>
86
 *
87
 *
88
<pre>month + day_of_month
89
month + week_of_month + day_of_week
90
month + day_of_week_of_month + day_of_week
91
day_of_year
92
day_of_week + week_of_year</pre>
93
 *
94
 * The hour_of_day-field takes precedence over the ampm and
95
 * hour_of_ampm fields. <br>
96
 *
97
 * <STRONG>Note:</STRONG> This can differ for non-Gregorian calendar. <br>
98
 *
99
 * To convert a calendar to a human readable form and vice versa,  use
100
 * the <code>java.text.DateFormat</code> class. <br>
101
 *
102
 * Other useful things you can do with an calendar, is
103
 * <code>roll</code>ing fields (that means increase/decrease a
104
 * specific field by one, propagating overflows), or
105
 * <code>add</code>ing/substracting a fixed amount to a field.
106
 *
107
 * @author Aaron M. Renn (arenn@urbanophile.com)
108
 * @author Jochen Hoenicke (Jochen.Hoenicke@Informatik.Uni-Oldenburg.de)
109
 * @author Warren Levy (warrenl@cygnus.com)
110
 * @author Jeff Sturm (jsturm@one-point.com)
111
 * @author Tom Tromey (tromey@redhat.com)
112
 * @author Bryce McKinlay (mckinlay@redhat.com)
113
 * @author Ingo Proetel (proetel@aicas.com)
114
 * @author Jerry Quinn (jlquinn@optonline.net)
115
 * @author Jeroen Frijters (jeroen@frijters.net)
116
 * @author Noa Resare (noa@resare.com)
117
 * @author Sven de Marothy (sven@physto.se)
118
 * @author David Gilbert (david.gilbert@object-refinery.com)
119
 * @author Olivier Jolly (olivier.jolly@pcedev.com)
120
 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
121
 * @see Date
122
 * @see GregorianCalendar
123
 * @see TimeZone
124
 * @see java.text.DateFormat
125
 */
126
public abstract class Calendar
127
  implements Serializable, Cloneable, Comparable<Calendar>
128
{
129
  /**
130
   * Constant representing the era time field.
131
   */
132
  public static final int ERA = 0;
133
 
134
  /**
135
   * Constant representing the year time field.
136
   */
137
  public static final int YEAR = 1;
138
 
139
  /**
140
   * Constant representing the month time field.  This field
141
   * should contain one of the JANUARY,...,DECEMBER constants below.
142
   */
143
  public static final int MONTH = 2;
144
 
145
  /**
146
   * Constant representing the week of the year field.
147
   * @see #setFirstDayOfWeek(int)
148
   */
149
  public static final int WEEK_OF_YEAR = 3;
150
 
151
  /**
152
   * Constant representing the week of the month time field.
153
   * @see #setFirstDayOfWeek(int)
154
   */
155
  public static final int WEEK_OF_MONTH = 4;
156
 
157
  /**
158
   * Constant representing the day time field, synonym for DAY_OF_MONTH.
159
   */
160
  public static final int DATE = 5;
161
 
162
  /**
163
   * Constant representing the day time field.
164
   */
165
  public static final int DAY_OF_MONTH = 5;
166
 
167
  /**
168
   * Constant representing the day of year time field.  This is
169
   * 1 for the first day in month.
170
   */
171
  public static final int DAY_OF_YEAR = 6;
172
 
173
  /**
174
   * Constant representing the day of week time field.  This field
175
   * should contain one of the SUNDAY,...,SATURDAY constants below.
176
   */
177
  public static final int DAY_OF_WEEK = 7;
178
 
179
  /**
180
   * Constant representing the day-of-week-in-month field.  For
181
   * instance this field contains 2 for the second thursday in a
182
   * month.  If you give a negative number here, the day will count
183
   * from the end of the month.
184
   */
185
  public static final int DAY_OF_WEEK_IN_MONTH = 8;
186
 
187
  /**
188
   * Constant representing the part of the day for 12-hour clock.  This
189
   * should be one of AM or PM.
190
   */
191
  public static final int AM_PM = 9;
192
 
193
  /**
194
   * Constant representing the hour time field for 12-hour clock.
195
   */
196
  public static final int HOUR = 10;
197
 
198
  /**
199
   * Constant representing the hour of day time field for 24-hour clock.
200
   */
201
  public static final int HOUR_OF_DAY = 11;
202
 
203
  /**
204
   * Constant representing the minute of hour time field.
205
   */
206
  public static final int MINUTE = 12;
207
 
208
  /**
209
   * Constant representing the second time field.
210
   */
211
  public static final int SECOND = 13;
212
 
213
  /**
214
   * Constant representing the millisecond time field.
215
   */
216
  public static final int MILLISECOND = 14;
217
 
218
  /**
219
   * Constant representing the time zone offset time field for the
220
   * time given in the other fields.  It is measured in
221
   * milliseconds.  The default is the offset of the time zone.
222
   */
223
  public static final int ZONE_OFFSET = 15;
224
 
225
  /**
226
   * Constant representing the daylight saving time offset in
227
   * milliseconds.  The default is the value given by the time zone.
228
   */
229
  public static final int DST_OFFSET = 16;
230
 
231
  /**
232
   * Number of time fields.
233
   */
234
  public static final int FIELD_COUNT = 17;
235
 
236
  /**
237
   * Constant representing Sunday.
238
   */
239
  public static final int SUNDAY = 1;
240
 
241
  /**
242
   * Constant representing Monday.
243
   */
244
  public static final int MONDAY = 2;
245
 
246
  /**
247
   * Constant representing Tuesday.
248
   */
249
  public static final int TUESDAY = 3;
250
 
251
  /**
252
   * Constant representing Wednesday.
253
   */
254
  public static final int WEDNESDAY = 4;
255
 
256
  /**
257
   * Constant representing Thursday.
258
   */
259
  public static final int THURSDAY = 5;
260
 
261
  /**
262
   * Constant representing Friday.
263
   */
264
  public static final int FRIDAY = 6;
265
 
266
  /**
267
   * Constant representing Saturday.
268
   */
269
  public static final int SATURDAY = 7;
270
 
271
  /**
272
   * Constant representing January.
273
   */
274
  public static final int JANUARY = 0;
275
 
276
  /**
277
   * Constant representing February.
278
   */
279
  public static final int FEBRUARY = 1;
280
 
281
  /**
282
   * Constant representing March.
283
   */
284
  public static final int MARCH = 2;
285
 
286
  /**
287
   * Constant representing April.
288
   */
289
  public static final int APRIL = 3;
290
 
291
  /**
292
   * Constant representing May.
293
   */
294
  public static final int MAY = 4;
295
 
296
  /**
297
   * Constant representing June.
298
   */
299
  public static final int JUNE = 5;
300
 
301
  /**
302
   * Constant representing July.
303
   */
304
  public static final int JULY = 6;
305
 
306
  /**
307
   * Constant representing August.
308
   */
309
  public static final int AUGUST = 7;
310
 
311
  /**
312
   * Constant representing September.
313
   */
314
  public static final int SEPTEMBER = 8;
315
 
316
  /**
317
   * Constant representing October.
318
   */
319
  public static final int OCTOBER = 9;
320
 
321
  /**
322
   * Constant representing November.
323
   */
324
  public static final int NOVEMBER = 10;
325
 
326
  /**
327
   * Constant representing December.
328
   */
329
  public static final int DECEMBER = 11;
330
 
331
  /**
332
   * Constant representing Undecimber. This is an artificial name useful
333
   * for lunar calendars.
334
   */
335
  public static final int UNDECIMBER = 12;
336
 
337
  /**
338
   * Useful constant for 12-hour clock.
339
   */
340
  public static final int AM = 0;
341
 
342
  /**
343
   * Useful constant for 12-hour clock.
344
   */
345
  public static final int PM = 1;
346
 
347
  /**
348
   * A style specifier for {@link #getDisplayNames(int,int,Locale)}
349
   * stating that names should be returned in both long and short variants.
350
   *
351
   * @since 1.6
352
   * @see #SHORT
353
   * @see #LONG
354
   */
355
  public static final int ALL_STYLES = 0;
356
 
357
  /**
358
   * A style specifier for {@link #getDisplayName(int,int,Locale)}
359
   * and {@link #getDisplayNames(int,int,Locale)} stating that names
360
   * should be returned in their short variant if applicable.
361
   *
362
   * @since 1.6
363
   */
364
  public static final int SHORT = 1;
365
 
366
  /**
367
   * A style specifier for {@link #getDisplayName(int,int,Locale)}
368
   * and {@link #getDisplayNames(int,int,Locale)} stating that names
369
   * should be returned in their long variant if applicable.
370
   *
371
   * @since 1.6
372
   */
373
  public static final int LONG = 2;
374
 
375
  /**
376
   * The time fields.  The array is indexed by the constants YEAR to
377
   * DST_OFFSET.
378
   * @serial
379
   */
380
  protected int[] fields = new int[FIELD_COUNT];
381
 
382
  /**
383
   * The flags which tell if the fields above have a value.
384
   * @serial
385
   */
386
  protected boolean[] isSet = new boolean[FIELD_COUNT];
387
 
388
  /**
389
   * The time in milliseconds since the epoch.
390
   * @serial
391
   */
392
  protected long time;
393
 
394
  /**
395
   * Tells if the above field has a valid value.
396
   * @serial
397
   */
398
  protected boolean isTimeSet;
399
 
400
  /**
401
   * Tells if the fields have a valid value.  This superseeds the isSet
402
   * array.
403
   * @serial
404
   */
405
  protected boolean areFieldsSet;
406
 
407
  /**
408
   * The time zone of this calendar.  Used by sub classes to do UTC / local
409
   * time conversion.  Sub classes can access this field with getTimeZone().
410
   * @serial
411
   */
412
  private TimeZone zone;
413
 
414
  /**
415
   * This is the default calendar class, that is returned on
416
   * java.util.Calendar.getInstance().
417
   * XXX - this isn't localized anywhere, is it?
418
   * @see java.util.Calendar#getInstance()
419
   */
420
  private static final String calendarClassName = "java.util.GregorianCalendar";
421
 
422
  /**
423
   * Specifies if the date/time interpretation should be lenient.
424
   * If the flag is set, a date such as "February 30, 1996" will be
425
   * treated as the 29th day after the February 1.  If this flag
426
   * is false, such dates will cause an exception.
427
   * @serial
428
   */
429
  private boolean lenient;
430
 
431
  /**
432
   * Sets what the first day of week is.  This is used for
433
   * WEEK_OF_MONTH and WEEK_OF_YEAR fields.
434
   * @serial
435
   */
436
  private int firstDayOfWeek;
437
 
438
  /**
439
   * Sets how many days are required in the first week of the year.
440
   * If the first day of the year should be the first week you should
441
   * set this value to 1.  If the first week must be a full week, set
442
   * it to 7.
443
   * @serial
444
   */
445
  private int minimalDaysInFirstWeek;
446
 
447
  /**
448
   * Is set to true if DST_OFFSET is explicitly set. In that case
449
   * it's value overrides the value computed from the current
450
   * time and the timezone.
451
   */
452
  private boolean explicitDSTOffset = false;
453
 
454
  /**
455
   * The version of the serialized data on the stream.
456
   * <dl><dt>0 or not present</dt>
457
   * <dd> JDK 1.1.5 or later.</dd>
458
   * <dt>1</dt>
459
   * <dd>JDK 1.1.6 or later.  This always writes a correct `time' value
460
   * on the stream, as well as the other fields, to be compatible with
461
   * earlier versions</dd></dl>
462
   * @since JDK1.1.6
463
   * @serial
464
   */
465
  private int serialVersionOnStream = 1;
466
 
467
  /**
468
   * XXX - I have not checked the compatibility.  The documentation of
469
   * the serialized-form is quite hairy...
470
   */
471
  static final long serialVersionUID = -1807547505821590642L;
472
 
473
  /**
474
   * The name of the resource bundle. Used only by getBundle()
475
   */
476
  private static final String bundleName = "gnu.java.locale.LocaleInformation";
477
 
478
  /**
479
   * get resource bundle:
480
   * The resources should be loaded via this method only. Iff an application
481
   * uses this method, the resourcebundle is required.
482
   */
483
  private static ResourceBundle getBundle(Locale locale)
484
  {
485
    return ResourceBundle.getBundle(bundleName, locale,
486
                                    ClassLoader.getSystemClassLoader());
487
  }
488
 
489
  /**
490
   * The set of properties for obtaining the minimum number of days in
491
   * the first week.
492
   */
493
  private static transient final Properties properties;
494
 
495
  /**
496
   * Reads in the properties.
497
   */
498
  static
499
  {
500
    properties = new Properties();
501
    try
502
      {
503
        properties.load(Calendar.class.getResourceAsStream("weeks.properties"));
504
      }
505
    catch (IOException exception)
506
      {
507
        System.out.println("Failed to load weeks resource: " + exception);
508
      }
509
  }
510
 
511
  /**
512
   * Constructs a new Calendar with the default time zone and the default
513
   * locale.
514
   */
515
  protected Calendar()
516
  {
517
    this(TimeZone.getDefault(), Locale.getDefault());
518
  }
519
 
520
  /**
521
   * Constructs a new Calendar with the given time zone and the given
522
   * locale.
523
   * @param zone a time zone.
524
   * @param locale a locale.
525
   */
526
  protected Calendar(TimeZone zone, Locale locale)
527
  {
528
    this.zone = zone;
529
    lenient = true;
530
    String[] days = { "", "sun", "mon", "tue", "wed", "thu", "fri", "sat" };
531
 
532
    String country = locale.getCountry();
533
    String min = properties.getProperty("minDays." + country);
534
    if (min == null)
535
      min = properties.getProperty("minDays.DEFAULT");
536
    String first = properties.getProperty("firstDay." + country);
537
    if (first == null)
538
      first = properties.getProperty("firstDay.DEFAULT");
539
    try
540
      {
541
        if (min != null)
542
          minimalDaysInFirstWeek = Integer.parseInt(min);
543
      }
544
    catch (NumberFormatException ex)
545
      {
546
        minimalDaysInFirstWeek = 1;
547
      }
548
 
549
    firstDayOfWeek = 1;
550
    if (first != null)
551
      for (int i = 0; i < 8; i++)
552
        if (days[i].equals(first))
553
          firstDayOfWeek = i;
554
 
555
    clear();
556
  }
557
 
558
  /**
559
   * Creates a calendar representing the actual time, using the default
560
   * time zone and locale.
561
   *
562
   * @return The new calendar.
563
   */
564
  public static synchronized Calendar getInstance()
565
  {
566
    return getInstance(TimeZone.getDefault(), Locale.getDefault());
567
  }
568
 
569
  /**
570
   * Creates a calendar representing the actual time, using the given
571
   * time zone and the default locale.
572
   *
573
   * @param zone a time zone (<code>null</code> not permitted).
574
   *
575
   * @return The new calendar.
576
   *
577
   * @throws NullPointerException if <code>zone</code> is <code>null</code>.
578
   */
579
  public static synchronized Calendar getInstance(TimeZone zone)
580
  {
581
    return getInstance(zone, Locale.getDefault());
582
  }
583
 
584
  /**
585
   * Creates a calendar representing the actual time, using the default
586
   * time zone and the given locale.
587
   *
588
   * @param locale a locale (<code>null</code> not permitted).
589
   *
590
   * @return The new calendar.
591
   *
592
   * @throws NullPointerException if <code>locale</code> is <code>null</code>.
593
   */
594
  public static synchronized Calendar getInstance(Locale locale)
595
  {
596
    return getInstance(TimeZone.getDefault(), locale);
597
  }
598
 
599
  /**
600
   * Cache of locale->calendar-class mappings. This avoids having to do a ResourceBundle
601
   * lookup for every getInstance call.
602
   */
603
  private static final HashMap<Locale,Class> cache = new HashMap<Locale,Class>();
604
 
605
  /** Preset argument types for calendar-class constructor lookup.  */
606
  private static Class[] ctorArgTypes = new Class[]
607
                                        {
608
                                          TimeZone.class, Locale.class
609
                                        };
610
 
611
  /**
612
   * Creates a calendar representing the actual time, using the given
613
   * time zone and locale.
614
   *
615
   * @param zone a time zone (<code>null</code> not permitted).
616
   * @param locale a locale (<code>null</code> not permitted).
617
   *
618
   * @return The new calendar.
619
   *
620
   * @throws NullPointerException if <code>zone</code> or <code>locale</code>
621
   *     is <code>null</code>.
622
   */
623
  public static synchronized Calendar getInstance(TimeZone zone, Locale locale)
624
  {
625
    Class calendarClass = cache.get(locale);
626
    Throwable exception = null;
627
 
628
    try
629
      {
630
        if (calendarClass == null)
631
          {
632
            calendarClass = Class.forName(calendarClassName);
633
            if (Calendar.class.isAssignableFrom(calendarClass))
634
              cache.put(locale, calendarClass);
635
          }
636
 
637
        // GregorianCalendar is by far the most common case. Optimize by
638
        // avoiding reflection.
639
        if (calendarClass == GregorianCalendar.class)
640
          return new GregorianCalendar(zone, locale);
641
 
642
        if (Calendar.class.isAssignableFrom(calendarClass))
643
          {
644
            Constructor ctor = calendarClass.getConstructor(ctorArgTypes);
645
            return (Calendar) ctor.newInstance(new Object[] { zone, locale });
646
          }
647
      }
648
    catch (ClassNotFoundException ex)
649
      {
650
        exception = ex;
651
      }
652
    catch (IllegalAccessException ex)
653
      {
654
        exception = ex;
655
      }
656
    catch (NoSuchMethodException ex)
657
      {
658
        exception = ex;
659
      }
660
    catch (InstantiationException ex)
661
      {
662
        exception = ex;
663
      }
664
    catch (InvocationTargetException ex)
665
      {
666
        exception = ex;
667
      }
668
 
669
    throw new RuntimeException("Error instantiating calendar for locale "
670
                               + locale, exception);
671
  }
672
 
673
  /**
674
   * Gets the set of locales for which a Calendar is available.
675
   * @exception MissingResourceException if locale data couldn't be found.
676
   * @return the set of locales.
677
   */
678
  public static synchronized Locale[] getAvailableLocales()
679
  {
680
    ResourceBundle rb = getBundle(new Locale("", ""));
681
    return (Locale[]) rb.getObject("availableLocales");
682
  }
683
 
684
  /**
685
   * Converts the time field values (<code>fields</code>) to
686
   * milliseconds since the epoch UTC (<code>time</code>).  Override
687
   * this method if you write your own Calendar.  */
688
  protected abstract void computeTime();
689
 
690
  /**
691
   * Converts the milliseconds since the epoch UTC
692
   * (<code>time</code>) to time fields
693
   * (<code>fields</code>). Override this method if you write your
694
   * own Calendar.
695
   */
696
  protected abstract void computeFields();
697
 
698
  /**
699
   * Converts the time represented by this object to a
700
   * <code>Date</code>-Object.
701
   * @return the Date.
702
   */
703
  public final Date getTime()
704
  {
705
    if (! isTimeSet)
706
      computeTime();
707
    return new Date(time);
708
  }
709
 
710
  /**
711
   * Sets this Calendar's time to the given Date.  All time fields
712
   * are invalidated by this method.
713
   *
714
   * @param date  the date (<code>null</code> not permitted).
715
   *
716
   * @throws NullPointerException if <code>date</code> is <code>null</code>.
717
   */
718
  public final void setTime(Date date)
719
  {
720
    setTimeInMillis(date.getTime());
721
  }
722
 
723
  /**
724
   * Returns the time represented by this Calendar.
725
   * @return the time in milliseconds since the epoch.
726
   * @specnote This was made public in 1.4.
727
   */
728
  public long getTimeInMillis()
729
  {
730
    if (! isTimeSet)
731
      computeTime();
732
    return time;
733
  }
734
 
735
  /**
736
   * Sets this Calendar's time to the given Time.  All time fields
737
   * are invalidated by this method.
738
   * @param time the time in milliseconds since the epoch
739
   * @specnote This was made public in 1.4.
740
   */
741
  public void setTimeInMillis(long time)
742
  {
743
    clear();
744
    this.time = time;
745
    isTimeSet = true;
746
    computeFields();
747
  }
748
 
749
  /**
750
   * Gets the value of the specified field.  They are recomputed
751
   * if they are invalid.
752
   * @param field the time field. One of the time field constants.
753
   * @return the value of the specified field
754
   * @throws ArrayIndexOutOfBoundsException if the field is outside
755
   *         the valid range.  The value of field must be >= 0 and
756
   *         <= <code>FIELD_COUNT</code>.
757
   * @specnote Not final since JDK 1.4
758
   */
759
  public int get(int field)
760
  {
761
    // If the requested field is invalid, force all fields to be recomputed.
762
    if (! isSet[field])
763
      areFieldsSet = false;
764
    complete();
765
    return fields[field];
766
  }
767
 
768
  /**
769
   * Gets the value of the specified field. This method doesn't
770
   * recompute the fields, if they are invalid.
771
   * @param field the time field. One of the time field constants.
772
   * @return the value of the specified field, undefined if
773
   * <code>areFieldsSet</code> or <code>isSet[field]</code> is false.
774
   * @throws ArrayIndexOutOfBoundsException if the field is outside
775
   *         the valid range.  The value of field must be >= 0 and
776
   *         <= <code>FIELD_COUNT</code>.
777
   */
778
  protected final int internalGet(int field)
779
  {
780
    return fields[field];
781
  }
782
 
783
  /**
784
   * Sets the time field with the given value.  This does invalidate
785
   * the time in milliseconds.
786
   * @param field the time field. One of the time field constants
787
   * @param value the value to be set.
788
   * @throws ArrayIndexOutOfBoundsException if field is outside
789
   *         the valid range.  The value of field must be >= 0 and
790
   *         <= <code>FIELD_COUNT</code>.
791
   * @specnote Not final since JDK 1.4
792
   */
793
  public void set(int field, int value)
794
  {
795
    if (isTimeSet)
796
      for (int i = 0; i < FIELD_COUNT; i++)
797
        isSet[i] = false;
798
    isTimeSet = false;
799
    fields[field] = value;
800
    isSet[field] = true;
801
 
802
    // The five valid date patterns, in order of priority
803
    // 1  YEAR + MONTH + DAY_OF_MONTH
804
    // 2  YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
805
    // 3  YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
806
    // 4  YEAR + DAY_OF_YEAR
807
    // 5  YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
808
    switch (field)
809
      {
810
      case MONTH: // pattern 1,2 or 3
811
        isSet[DAY_OF_YEAR] = false;
812
        isSet[WEEK_OF_YEAR] = false;
813
        break;
814
      case DAY_OF_MONTH: // pattern 1
815
        isSet[YEAR] = true;
816
        isSet[MONTH] = true;
817
        isSet[WEEK_OF_MONTH] = true;
818
        isSet[DAY_OF_WEEK] = false;
819
        isSet[DAY_OF_WEEK_IN_MONTH] = false;
820
        isSet[DAY_OF_YEAR] = false;
821
        isSet[WEEK_OF_YEAR] = false;
822
        break;
823
      case WEEK_OF_MONTH: // pattern 2
824
        if (! isSet[DAY_OF_WEEK])
825
          fields[DAY_OF_WEEK] = getFirstDayOfWeek();
826
        isSet[YEAR] = true;
827
        isSet[MONTH] = true;
828
        isSet[DAY_OF_WEEK] = true;
829
        isSet[DAY_OF_MONTH] = false;
830
        isSet[DAY_OF_WEEK_IN_MONTH] = false;
831
        isSet[DAY_OF_YEAR] = false;
832
        isSet[WEEK_OF_YEAR] = false;
833
        break;
834
      case DAY_OF_WEEK_IN_MONTH: // pattern 3
835
        if (! isSet[DAY_OF_WEEK])
836
          fields[DAY_OF_WEEK] = getFirstDayOfWeek();
837
        isSet[YEAR] = true;
838
        isSet[MONTH] = true;
839
        isSet[DAY_OF_WEEK] = true;
840
        isSet[DAY_OF_YEAR] = false;
841
        isSet[DAY_OF_MONTH] = false;
842
        isSet[WEEK_OF_MONTH] = false;
843
        isSet[WEEK_OF_YEAR] = false;
844
        break;
845
      case DAY_OF_YEAR: // pattern 4
846
        isSet[YEAR] = true;
847
        isSet[MONTH] = false;
848
        isSet[WEEK_OF_MONTH] = false;
849
        isSet[DAY_OF_MONTH] = false;
850
        isSet[DAY_OF_WEEK] = false;
851
        isSet[WEEK_OF_YEAR] = false;
852
        isSet[DAY_OF_WEEK_IN_MONTH] = false;
853
        break;
854
      case WEEK_OF_YEAR: // pattern 5
855
        if (! isSet[DAY_OF_WEEK])
856
          fields[DAY_OF_WEEK] = getFirstDayOfWeek();
857
        isSet[YEAR] = true;
858
        isSet[DAY_OF_WEEK] = true;
859
        isSet[MONTH] = false;
860
        isSet[DAY_OF_MONTH] = false;
861
        isSet[WEEK_OF_MONTH] = false;
862
        isSet[DAY_OF_YEAR] = false;
863
        isSet[DAY_OF_WEEK_IN_MONTH] = false;
864
        break;
865
      case AM_PM:
866
        isSet[HOUR] = true;
867
        isSet[HOUR_OF_DAY] = false;
868
        break;
869
      case HOUR_OF_DAY:
870
        isSet[AM_PM] = false;
871
        isSet[HOUR] = false;
872
        break;
873
      case HOUR:
874
        isSet[AM_PM] = true;
875
        isSet[HOUR_OF_DAY] = false;
876
        break;
877
      case DST_OFFSET:
878
        explicitDSTOffset = true;
879
      }
880
 
881
    // May have crossed over a DST boundary.
882
    if (! explicitDSTOffset && (field != DST_OFFSET && field != ZONE_OFFSET))
883
      isSet[DST_OFFSET] = false;
884
  }
885
 
886
  /**
887
   * Sets the fields for year, month, and date
888
   * @param year the year.
889
   * @param month the month, one of the constants JANUARY..UNDICEMBER.
890
   * @param date the day of the month
891
   */
892
  public final void set(int year, int month, int date)
893
  {
894
    isTimeSet = false;
895
    fields[YEAR] = year;
896
    fields[MONTH] = month;
897
    fields[DATE] = date;
898
    isSet[YEAR] = isSet[MONTH] = isSet[DATE] = true;
899
    isSet[WEEK_OF_YEAR] = false;
900
    isSet[DAY_OF_YEAR] = false;
901
    isSet[WEEK_OF_MONTH] = false;
902
    isSet[DAY_OF_WEEK] = false;
903
    isSet[DAY_OF_WEEK_IN_MONTH] = false;
904
    isSet[ERA] = false;
905
 
906
    if (! explicitDSTOffset)
907
      isSet[DST_OFFSET] = false; // May have crossed a DST boundary.
908
  }
909
 
910
  /**
911
   * Sets the fields for year, month, date, hour, and minute
912
   * @param year the year.
913
   * @param month the month, one of the constants JANUARY..UNDICEMBER.
914
   * @param date the day of the month
915
   * @param hour the hour of day.
916
   * @param minute the minute.
917
   */
918
  public final void set(int year, int month, int date, int hour, int minute)
919
  {
920
    set(year, month, date);
921
    fields[HOUR_OF_DAY] = hour;
922
    fields[MINUTE] = minute;
923
    isSet[HOUR_OF_DAY] = isSet[MINUTE] = true;
924
    isSet[AM_PM] = false;
925
    isSet[HOUR] = false;
926
  }
927
 
928
  /**
929
   * Sets the fields for year, month, date, hour, and minute
930
   * @param year the year.
931
   * @param month the month, one of the constants JANUARY..UNDICEMBER.
932
   * @param date the day of the month
933
   * @param hour the hour of day.
934
   * @param minute the minute.
935
   * @param second the second.
936
   */
937
  public final void set(int year, int month, int date, int hour, int minute,
938
                        int second)
939
  {
940
    set(year, month, date, hour, minute);
941
    fields[SECOND] = second;
942
    isSet[SECOND] = true;
943
  }
944
 
945
  /**
946
   * Clears the values of all the time fields.
947
   */
948
  public final void clear()
949
  {
950
    isTimeSet = false;
951
    areFieldsSet = false;
952
    int zoneOffs = zone.getRawOffset();
953
    int[] tempFields =
954
                       {
955
                         1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0,
956
                         0, 0, zoneOffs, 0
957
                       };
958
    fields = tempFields;
959
    for (int i = 0; i < FIELD_COUNT; i++)
960
      isSet[i] = false;
961
  }
962
 
963
  /**
964
   * Clears the values of the specified time field.
965
   * @param field the time field. One of the time field constants.
966
   * @throws ArrayIndexOutOfBoundsException if field is outside
967
   *         the valid range.  The value of field must be >= 0 and
968
   *         <= <code>FIELD_COUNT</code>.
969
   */
970
  public final void clear(int field)
971
  {
972
    int[] tempFields =
973
                       {
974
                         1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0,
975
                         0, 0, zone.getRawOffset(), 0
976
                       };
977
    complete();
978
    isTimeSet = false;
979
    areFieldsSet = false;
980
    isSet[field] = false;
981
    fields[field] = tempFields[field];
982
  }
983
 
984
  /**
985
   * Determines if the specified field has a valid value.
986
   * @return true if the specified field has a value.
987
   * @throws ArrayIndexOutOfBoundsException if the field is outside
988
   *         the valid range.  The value of field must be >= 0 and
989
   *         <= <code>FIELD_COUNT</code>.
990
   */
991
  public final boolean isSet(int field)
992
  {
993
    return isSet[field];
994
  }
995
 
996
  /**
997
   * Fills any unset fields in the time field list
998
   */
999
  protected void complete()
1000
  {
1001
    if (! isTimeSet)
1002
      computeTime();
1003
    if (! areFieldsSet)
1004
      computeFields();
1005
  }
1006
 
1007
  /**
1008
   * Compares the given calendar with this.
1009
   * @param o the object to that we should compare.
1010
   * @return true, if the given object is a calendar, that represents
1011
   * the same time (but doesn't necessary have the same fields).
1012
   */
1013
  public boolean equals(Object o)
1014
  {
1015
    if (! (o instanceof Calendar))
1016
      return false;
1017
    Calendar cal = (Calendar) o;
1018
    if (getTimeInMillis() == ((Calendar) o).getTimeInMillis()
1019
        && cal.getFirstDayOfWeek() == getFirstDayOfWeek()
1020
        && cal.isLenient() == isLenient()
1021
        && cal.getMinimalDaysInFirstWeek() == getMinimalDaysInFirstWeek())
1022
      {
1023
        TimeZone self = getTimeZone();
1024
        TimeZone oth = cal.getTimeZone();
1025
        return self == null ? oth == null : self.equals(oth);
1026
      }
1027
    return false;
1028
  }
1029
 
1030
  /**
1031
   * Returns a hash code for this calendar.
1032
   * @return a hash code, which fullfits the general contract of
1033
   * <code>hashCode()</code>
1034
   */
1035
  public int hashCode()
1036
  {
1037
    long time = getTimeInMillis();
1038
    int val = (int) ((time & 0xffffffffL) ^ (time >> 32));
1039
    val += (getFirstDayOfWeek() + (isLenient() ? 1230 : 1237)
1040
            + getMinimalDaysInFirstWeek());
1041
    TimeZone self = getTimeZone();
1042
    if (self != null)
1043
      val ^= self.hashCode();
1044
    return val;
1045
  }
1046
 
1047
  /**
1048
   * Compares the given calendar with this.
1049
   * @param o the object to that we should compare.
1050
   * @return true, if the given object is a calendar, and this calendar
1051
   * represents a smaller time than the calendar o.
1052
   * @exception ClassCastException if o is not an calendar.
1053
   * @since JDK1.2 you don't need to override this method
1054
   */
1055
  public boolean before(Object o)
1056
  {
1057
    return getTimeInMillis() < ((Calendar) o).getTimeInMillis();
1058
  }
1059
 
1060
  /**
1061
   * Compares the given calendar with this.
1062
   * @param o the object to that we should compare.
1063
   * @return true, if the given object is a calendar, and this calendar
1064
   * represents a bigger time than the calendar o.
1065
   * @exception ClassCastException if o is not an calendar.
1066
   * @since JDK1.2 you don't need to override this method
1067
   */
1068
  public boolean after(Object o)
1069
  {
1070
    return getTimeInMillis() > ((Calendar) o).getTimeInMillis();
1071
  }
1072
 
1073
  /**
1074
   * Adds the specified amount of time to the given time field.  The
1075
   * amount may be negative to subtract the time.  If the field overflows
1076
   * it does what you expect: Jan, 25 + 10 Days is Feb, 4.
1077
   * @param field the time field. One of the time field constants.
1078
   * @param amount the amount of time.
1079
   * @throws ArrayIndexOutOfBoundsException if the field is outside
1080
   *         the valid range.  The value of field must be >= 0 and
1081
   *         <= <code>FIELD_COUNT</code>.
1082
   */
1083
  public abstract void add(int field, int amount);
1084
 
1085
  /**
1086
   * Rolls the specified time field up or down.  This means add one
1087
   * to the specified field, but don't change the other fields.  If
1088
   * the maximum for this field is reached, start over with the
1089
   * minimum value.  <br>
1090
   *
1091
   * <strong>Note:</strong> There may be situation, where the other
1092
   * fields must be changed, e.g rolling the month on May, 31.
1093
   * The date June, 31 is automatically converted to July, 1.
1094
   * @param field the time field. One of the time field constants.
1095
   * @param up the direction, true for up, false for down.
1096
   * @throws ArrayIndexOutOfBoundsException if the field is outside
1097
   *         the valid range.  The value of field must be >= 0 and
1098
   *         <= <code>FIELD_COUNT</code>.
1099
   */
1100
  public abstract void roll(int field, boolean up);
1101
 
1102
  /**
1103
   * Rolls up or down the specified time field by the given amount.
1104
   * A negative amount rolls down.  The default implementation is
1105
   * call <code>roll(int, boolean)</code> for the specified amount.
1106
   *
1107
   * Subclasses should override this method to do more intuitiv things.
1108
   *
1109
   * @param field the time field. One of the time field constants.
1110
   * @param amount the amount to roll by, positive for rolling up,
1111
   * negative for rolling down.
1112
   * @throws ArrayIndexOutOfBoundsException if the field is outside
1113
   *         the valid range.  The value of field must be >= 0 and
1114
   *         <= <code>FIELD_COUNT</code>.
1115
   * @since JDK1.2
1116
   */
1117
  public void roll(int field, int amount)
1118
  {
1119
    while (amount > 0)
1120
      {
1121
        roll(field, true);
1122
        amount--;
1123
      }
1124
    while (amount < 0)
1125
      {
1126
        roll(field, false);
1127
        amount++;
1128
      }
1129
  }
1130
 
1131
  /**
1132
   * Sets the time zone to the specified value.
1133
   * @param zone the new time zone
1134
   */
1135
  public void setTimeZone(TimeZone zone)
1136
  {
1137
    this.zone = zone;
1138
    computeTime();
1139
    computeFields();
1140
  }
1141
 
1142
  /**
1143
   * Gets the time zone of this calendar
1144
   * @return the current time zone.
1145
   */
1146
  public TimeZone getTimeZone()
1147
  {
1148
    return zone;
1149
  }
1150
 
1151
  /**
1152
   * Specifies if the date/time interpretation should be lenient.
1153
   * If the flag is set, a date such as "February 30, 1996" will be
1154
   * treated as the 29th day after the February 1.  If this flag
1155
   * is false, such dates will cause an exception.
1156
   * @param lenient true, if the date should be interpreted linient,
1157
   * false if it should be interpreted strict.
1158
   */
1159
  public void setLenient(boolean lenient)
1160
  {
1161
    this.lenient = lenient;
1162
  }
1163
 
1164
  /**
1165
   * Tells if the date/time interpretation is lenient.
1166
   * @return true, if the date should be interpreted linient,
1167
   * false if it should be interpreted strict.
1168
   */
1169
  public boolean isLenient()
1170
  {
1171
    return lenient;
1172
  }
1173
 
1174
  /**
1175
   * Sets what the first day of week is.  This is used for
1176
   * WEEK_OF_MONTH and WEEK_OF_YEAR fields.
1177
   * @param value the first day of week.  One of SUNDAY to SATURDAY.
1178
   */
1179
  public void setFirstDayOfWeek(int value)
1180
  {
1181
    firstDayOfWeek = value;
1182
  }
1183
 
1184
  /**
1185
   * Gets what the first day of week is.  This is used for
1186
   * WEEK_OF_MONTH and WEEK_OF_YEAR fields.
1187
   * @return the first day of week.  One of SUNDAY to SATURDAY.
1188
   */
1189
  public int getFirstDayOfWeek()
1190
  {
1191
    return firstDayOfWeek;
1192
  }
1193
 
1194
  /**
1195
   * Sets how many days are required in the first week of the year.
1196
   * If the first day of the year should be the first week you should
1197
   * set this value to 1.  If the first week must be a full week, set
1198
   * it to 7.
1199
   * @param value the minimal days required in the first week.
1200
   */
1201
  public void setMinimalDaysInFirstWeek(int value)
1202
  {
1203
    minimalDaysInFirstWeek = value;
1204
  }
1205
 
1206
  /**
1207
   * Gets how many days are required in the first week of the year.
1208
   * @return the minimal days required in the first week.
1209
   * @see #setMinimalDaysInFirstWeek
1210
   */
1211
  public int getMinimalDaysInFirstWeek()
1212
  {
1213
    return minimalDaysInFirstWeek;
1214
  }
1215
 
1216
  /**
1217
   * Gets the smallest value that is allowed for the specified field.
1218
   * @param field the time field. One of the time field constants.
1219
   * @return the smallest value.
1220
   */
1221
  public abstract int getMinimum(int field);
1222
 
1223
  /**
1224
   * Gets the biggest value that is allowed for the specified field.
1225
   * @param field the time field. One of the time field constants.
1226
   * @return the biggest value.
1227
   */
1228
  public abstract int getMaximum(int field);
1229
 
1230
  /**
1231
   * Gets the greatest minimum value that is allowed for the specified field.
1232
   * @param field the time field. One of the time field constants.
1233
   * @return the greatest minimum value.
1234
   */
1235
  public abstract int getGreatestMinimum(int field);
1236
 
1237
  /**
1238
   * Gets the smallest maximum value that is allowed for the
1239
   * specified field.  For example this is 28 for DAY_OF_MONTH.
1240
   * @param field the time field. One of the time field constants.
1241
   * @return the least maximum value.
1242
   */
1243
  public abstract int getLeastMaximum(int field);
1244
 
1245
  /**
1246
   * Gets the actual minimum value that is allowed for the specified field.
1247
   * This value is dependent on the values of the other fields.
1248
   * @param field the time field. One of the time field constants.
1249
   * @return the actual minimum value.
1250
   * @throws ArrayIndexOutOfBoundsException if the field is outside
1251
   *         the valid range.  The value of field must be >= 0 and
1252
   *         <= <code>FIELD_COUNT</code>.
1253
   * @since jdk1.2
1254
   */
1255
  public int getActualMinimum(int field)
1256
  {
1257
    Calendar tmp = (Calendar) clone(); // To avoid restoring state
1258
    int min = tmp.getGreatestMinimum(field);
1259
    int end = tmp.getMinimum(field);
1260
    tmp.set(field, min);
1261
    for (; min > end; min--)
1262
      {
1263
        tmp.add(field, -1); // Try to get smaller
1264
        if (tmp.get(field) != min - 1)
1265
          break; // Done if not successful
1266
      }
1267
    return min;
1268
  }
1269
 
1270
  /**
1271
   * Gets the actual maximum value that is allowed for the specified field.
1272
   * This value is dependent on the values of the other fields.
1273
   * @param field the time field. One of the time field constants.
1274
   * @return the actual maximum value.
1275
   * @throws ArrayIndexOutOfBoundsException if the field is outside
1276
   *         the valid range.  The value of field must be >= 0 and
1277
   *         <= <code>FIELD_COUNT</code>.
1278
   * @since jdk1.2
1279
   */
1280
  public int getActualMaximum(int field)
1281
  {
1282
    Calendar tmp = (Calendar) clone(); // To avoid restoring state
1283
    int max = tmp.getLeastMaximum(field);
1284
    int end = tmp.getMaximum(field);
1285
    tmp.set(field, max);
1286
    for (; max < end; max++)
1287
      {
1288
        tmp.add(field, 1);
1289
        if (tmp.get(field) != max + 1)
1290
          break;
1291
      }
1292
    return max;
1293
  }
1294
 
1295
  /**
1296
   * Compares the time of two calendar instances.
1297
   * @param cal the calendar to which the time should be compared.
1298
   * @return 0 if the two calendars are set to the same time,
1299
   * less than 0 if the time of this calendar is before that of
1300
   * <code>cal</code>, or more than 0 if the time of this calendar is after
1301
   * that of <code>cal</code>.
1302
   *
1303
   * @param cal the calendar to compare this instance with.
1304
   * @throws NullPointerException if <code>cal</code> is null.
1305
   * @throws IllegalArgumentException if either calendar has fields set to
1306
   * invalid values.
1307
   * @since 1.5
1308
   */
1309
  public int compareTo(Calendar cal)
1310
  {
1311
    long t1 = getTimeInMillis();
1312
    long t2 = cal.getTimeInMillis();
1313
    if(t1 == t2)
1314
      return 0;
1315
    if(t1 > t2)
1316
      return 1;
1317
    return -1;
1318
  }
1319
 
1320
  /**
1321
   * Return a clone of this object.
1322
   */
1323
  public Object clone()
1324
  {
1325
    try
1326
      {
1327
        Calendar cal = (Calendar) super.clone();
1328
        cal.fields = (int[]) fields.clone();
1329
        cal.isSet = (boolean[]) isSet.clone();
1330
        return cal;
1331
      }
1332
    catch (CloneNotSupportedException ex)
1333
      {
1334
        return null;
1335
      }
1336
  }
1337
 
1338
  private static final String[] fieldNames =
1339
                                             {
1340
                                               ",ERA=", ",YEAR=", ",MONTH=",
1341
                                               ",WEEK_OF_YEAR=",
1342
                                               ",WEEK_OF_MONTH=",
1343
                                               ",DAY_OF_MONTH=",
1344
                                               ",DAY_OF_YEAR=", ",DAY_OF_WEEK=",
1345
                                               ",DAY_OF_WEEK_IN_MONTH=",
1346
                                               ",AM_PM=", ",HOUR=",
1347
                                               ",HOUR_OF_DAY=", ",MINUTE=",
1348
                                               ",SECOND=", ",MILLISECOND=",
1349
                                               ",ZONE_OFFSET=", ",DST_OFFSET="
1350
                                             };
1351
 
1352
  /**
1353
   * Returns a string representation of this object.  It is mainly
1354
   * for debugging purposes and its content is implementation
1355
   * specific.
1356
   */
1357
  public String toString()
1358
  {
1359
    CPStringBuilder sb = new CPStringBuilder(getClass().getName());
1360
    sb.append('[');
1361
    sb.append("time=");
1362
    if (isTimeSet)
1363
      sb.append(time);
1364
    else
1365
      sb.append("?");
1366
    sb.append(",zone=" + zone);
1367
    sb.append(",areFieldsSet=" + areFieldsSet);
1368
    for (int i = 0; i < FIELD_COUNT; i++)
1369
      {
1370
        sb.append(fieldNames[i]);
1371
        if (isSet[i])
1372
          sb.append(fields[i]);
1373
        else
1374
          sb.append("?");
1375
      }
1376
    sb.append(",lenient=").append(lenient);
1377
    sb.append(",firstDayOfWeek=").append(firstDayOfWeek);
1378
    sb.append(",minimalDaysInFirstWeek=").append(minimalDaysInFirstWeek);
1379
    sb.append("]");
1380
    return sb.toString();
1381
  }
1382
 
1383
  /**
1384
   * Saves the state of the object to the stream.  Ideally we would
1385
   * only write the time field, but we need to be compatible with
1386
   * earlier versions. <br>
1387
   *
1388
   * This doesn't write the JDK1.1 field nextStamp to the stream, as
1389
   * I don't know what it is good for, and because the documentation
1390
   * says, that it could be omitted.  */
1391
  private void writeObject(ObjectOutputStream stream) throws IOException
1392
  {
1393
    if (! isTimeSet)
1394
      computeTime();
1395
    stream.defaultWriteObject();
1396
  }
1397
 
1398
  /**
1399
   * Reads the object back from stream (deserialization).
1400
   */
1401
  private void readObject(ObjectInputStream stream)
1402
    throws IOException, ClassNotFoundException
1403
  {
1404
    stream.defaultReadObject();
1405
    if (! isTimeSet)
1406
      computeTime();
1407
 
1408
    if (serialVersionOnStream > 1)
1409
      {
1410
        // This is my interpretation of the serial number:
1411
        // Sun wants to remove all fields from the stream someday
1412
        // and will then increase the serialVersion number again.
1413
        // We prepare to be compatible.
1414
        fields = new int[FIELD_COUNT];
1415
        isSet = new boolean[FIELD_COUNT];
1416
        areFieldsSet = false;
1417
      }
1418
  }
1419
 
1420
  /**
1421
   * Returns a localised textual representation of the current value
1422
   * of the given field using the specified style.  If there is no
1423
   * applicable textual representation (e.g. the field has a numeric
1424
   * value), then <code>null</code> is returned.  If one does exist,
1425
   * then the value is obtained from {@link #get(int)} and converted
1426
   * appropriately.  For example, if the <code>MONTH</code> field is
1427
   * requested, then <code>get(MONTH)</code> is called.  This is then
1428
   * converted to a textual representation based on its value and
1429
   * the style requested; if the <code>LONG</code> style is requested
1430
   * and the returned value is <code>11</code> from a
1431
   * {@link GregorianCalendar} implementation, then <code>"December"</code>
1432
   * is returned.  By default, a textual representation is available
1433
   * for all fields which have an applicable value obtainable from
1434
   * {@link java.text.DateFormatSymbols}.
1435
   *
1436
   * @param field the calendar field whose textual representation should
1437
   *              be obtained.
1438
   * @param style the style to use; either {@link #LONG} or {@link #SHORT}.
1439
   * @param locale the locale to use for translation.
1440
   * @return the textual representation of the given field in the specified
1441
   *         style, or <code>null</code> if none is applicable.
1442
   * @throws IllegalArgumentException if <code>field</code> or <code>style</code>
1443
   *                                  or invalid, or the calendar is non-lenient
1444
   *                                  and has invalid values.
1445
   * @throws NullPointerException if <code>locale</code> is <code>null</code>.
1446
   * @since 1.6
1447
   */
1448
  public String getDisplayName(int field, int style, Locale locale)
1449
  {
1450
    if (field < 0 || field >= FIELD_COUNT)
1451
      throw new IllegalArgumentException("The field value, " + field +
1452
                                         ", is invalid.");
1453
    if (style != SHORT && style != LONG)
1454
      throw new IllegalArgumentException("The style must be either " +
1455
                                         "short or long.");
1456
    if (field == YEAR || field == WEEK_OF_YEAR ||
1457
        field == WEEK_OF_MONTH || field == DAY_OF_MONTH ||
1458
        field == DAY_OF_YEAR || field == DAY_OF_WEEK_IN_MONTH ||
1459
        field == HOUR || field == HOUR_OF_DAY || field == MINUTE ||
1460
        field == SECOND || field == MILLISECOND)
1461
      return null;
1462
 
1463
    int value = get(field);
1464
    DateFormatSymbols syms = DateFormatSymbols.getInstance(locale);
1465
    if (field == ERA)
1466
      return syms.getEras()[value];
1467
    if (field == MONTH)
1468
      if (style == LONG)
1469
        return syms.getMonths()[value];
1470
      else
1471
        return syms.getShortMonths()[value];
1472
    if (field == DAY_OF_WEEK)
1473
      if (style == LONG)
1474
        return syms.getWeekdays()[value];
1475
      else
1476
        return syms.getShortWeekdays()[value];
1477
    if (field == AM_PM)
1478
      return syms.getAmPmStrings()[value];
1479
    if (field == ZONE_OFFSET)
1480
      if (style == LONG)
1481
        return syms.getZoneStrings()[value][1];
1482
      else
1483
        return syms.getZoneStrings()[value][2];
1484
    if (field == DST_OFFSET)
1485
      if (style == LONG)
1486
        return syms.getZoneStrings()[value][3];
1487
      else
1488
        return syms.getZoneStrings()[value][4];
1489
 
1490
    throw new InternalError("Failed to resolve field " + field +
1491
                            " with style " + style + " for locale " +
1492
                            locale);
1493
  }
1494
 
1495
  /**
1496
   * Returns a map linking all specified textual representations
1497
   * of the given field to their numerical values.  The textual
1498
   * representations included are determined by the specified
1499
   * style and locale.  For example, if the style <code>LONG</code>
1500
   * is specified and the German locale, then the map will
1501
   * contain "Montag" to {@link #MONDAY}, "Dienstag" to
1502
   * {@link #TUESDAY}, "Mittwoch" to {@link #WEDNESDAY} and
1503
   * so on.  The default implementation uses the values returned
1504
   * by {@link DateFormatSymbols} so, for example, the style
1505
   * {@link #ALL_STYLES} and the field {@link #MONTH} will return
1506
   * a map filled with the values returned from
1507
   * {@link DateFormatSymbols#getMonths()} and
1508
   * {@link DateFormatSymbols#getShortMonths()}.  If there are
1509
   * no textual representations for a given field (usually because
1510
   * it is purely numeric, such as the year in the
1511
   * {@link GregorianCalendar}), <code>null</code> is returned.
1512
   *
1513
   * @param field the calendar field whose textual representation should
1514
   *              be obtained.
1515
   * @param style the style to use; either {@link #LONG}, {@link #SHORT}
1516
   *              or {@link ALL_STYLES}.
1517
   * @param locale the locale to use for translation.
1518
   * @return a map of the textual representations of the given field in the
1519
   *         specified style to their numeric values, or <code>null</code>
1520
   *         if none is applicable.
1521
   * @throws IllegalArgumentException if <code>field</code> or <code>style</code>
1522
   *                                  or invalid, or the calendar is non-lenient
1523
   *                                  and has invalid values.
1524
   * @throws NullPointerException if <code>locale</code> is <code>null</code>.
1525
   * @since 1.6
1526
   */
1527
  public Map<String,Integer> getDisplayNames(int field, int style, Locale locale)
1528
  {
1529
    if (field < 0 || field >= FIELD_COUNT)
1530
      throw new IllegalArgumentException("The field value, " + field +
1531
                                         ", is invalid.");
1532
    if (style != SHORT && style != LONG && style != ALL_STYLES)
1533
      throw new IllegalArgumentException("The style must be either " +
1534
                                         "short, long or all styles.");
1535
    if (field == YEAR || field == WEEK_OF_YEAR ||
1536
        field == WEEK_OF_MONTH || field == DAY_OF_MONTH ||
1537
        field == DAY_OF_YEAR || field == DAY_OF_WEEK_IN_MONTH ||
1538
        field == HOUR || field == HOUR_OF_DAY || field == MINUTE ||
1539
        field == SECOND || field == MILLISECOND)
1540
      return null;
1541
 
1542
    DateFormatSymbols syms = DateFormatSymbols.getInstance(locale);
1543
    Map<String,Integer> map = new HashMap<String,Integer>();
1544
    if (field == ERA)
1545
      {
1546
        String[] eras = syms.getEras();
1547
        for (int a = 0; a < eras.length; ++a)
1548
          map.put(eras[a], a);
1549
        return map;
1550
      }
1551
    if (field == MONTH)
1552
      {
1553
        if (style == LONG || style == ALL_STYLES)
1554
          {
1555
            String[] months = syms.getMonths();
1556
            for (int a = 0; a < months.length; ++a)
1557
              map.put(months[a], a);
1558
          }
1559
        if (style == SHORT || style == ALL_STYLES)
1560
          {
1561
            String[] months = syms.getShortMonths();
1562
            for (int a = 0; a < months.length; ++a)
1563
              map.put(months[a], a);
1564
          }
1565
        return map;
1566
      }
1567
    if (field == DAY_OF_WEEK)
1568
      {
1569
        if (style == LONG || style == ALL_STYLES)
1570
          {
1571
            String[] weekdays = syms.getWeekdays();
1572
            for (int a = SUNDAY; a < weekdays.length; ++a)
1573
              map.put(weekdays[a], a);
1574
          }
1575
        if (style == SHORT || style == ALL_STYLES)
1576
          {
1577
            String[] weekdays = syms.getShortWeekdays();
1578
            for (int a = SUNDAY; a < weekdays.length; ++a)
1579
              map.put(weekdays[a], a);
1580
          }
1581
        return map;
1582
      }
1583
    if (field == AM_PM)
1584
      {
1585
        String[] ampms = syms.getAmPmStrings();
1586
        for (int a = 0; a < ampms.length; ++a)
1587
          map.put(ampms[a], a);
1588
        return map;
1589
      }
1590
    if (field == ZONE_OFFSET)
1591
      {
1592
        String[][] zones = syms.getZoneStrings();
1593
        for (int a = 0; a < zones.length; ++a)
1594
          {
1595
            if (style == LONG || style == ALL_STYLES)
1596
              map.put(zones[a][1], a);
1597
            if (style == SHORT || style == ALL_STYLES)
1598
              map.put(zones[a][2], a);
1599
          }
1600
        return map;
1601
      }
1602
    if (field == DST_OFFSET)
1603
      {
1604
        String[][] zones = syms.getZoneStrings();
1605
        for (int a = 0; a < zones.length; ++a)
1606
          {
1607
            if (style == LONG || style == ALL_STYLES)
1608
              map.put(zones[a][3], a);
1609
            if (style == SHORT || style == ALL_STYLES)
1610
              map.put(zones[a][4], a);
1611
          }
1612
        return map;
1613
      }
1614
 
1615
    throw new InternalError("Failed to resolve field " + field +
1616
                            " with style " + style + " for locale " +
1617
                            locale);
1618
  }
1619
 
1620
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.