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