Print this page
rev 5696 : 6336885: RFE: Locale Data Deployment Enhancements
4609153: Provide locale data for Indic locales
5104387: Support for gl_ES locale (galician language)
6337471: desktop/system locale preferences support
7056139: (cal) SPI support for locale-dependent Calendar parameters
7058206: Provide CalendarData SPI for week params and display field value names
7073852: Support multiple scripts for digits and decimal symbols per locale
7079560: [Fmt-Da] Context dependent month names support in SimpleDateFormat
7171324: getAvailableLocales() of locale sensitive services should return the actual availability of locales
7151414: (cal) Support calendar type identification
7168528: LocaleServiceProvider needs to be aware of Locale extensions
7171372: (cal) locale's default Calendar should be created if unknown calendar is specified
Summary: JEP 127: Improve Locale Data Packaging and Adopt Unicode CLDR Data (part 1 w/o packaging changes. by Naoto Sato and Masayoshi Okutsu)

Split Close
Expand all
Collapse all
          --- old/src/share/classes/java/util/Calendar.java
          +++ new/src/share/classes/java/util/Calendar.java
↓ open down ↓ 45 lines elided ↑ open up ↑
  46   46  import java.security.AccessControlContext;
  47   47  import java.security.AccessController;
  48   48  import java.security.PermissionCollection;
  49   49  import java.security.PrivilegedActionException;
  50   50  import java.security.PrivilegedExceptionAction;
  51   51  import java.security.ProtectionDomain;
  52   52  import java.text.DateFormat;
  53   53  import java.text.DateFormatSymbols;
  54   54  import java.util.concurrent.ConcurrentHashMap;
  55   55  import java.util.concurrent.ConcurrentMap;
       56 +import java.util.spi.CalendarDataProvider;
  56   57  import sun.util.BuddhistCalendar;
       58 +import sun.util.locale.provider.LocaleProviderAdapter;
  57   59  import sun.util.calendar.ZoneInfo;
  58      -import sun.util.resources.LocaleData;
       60 +import sun.util.locale.provider.CalendarDataUtility;
  59   61  
  60   62  /**
  61   63   * The <code>Calendar</code> class is an abstract class that provides methods
  62   64   * for converting between a specific instant in time and a set of {@link
  63   65   * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
  64   66   * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, and so on, and for
  65   67   * manipulating the calendar fields, such as getting the date of the next
  66   68   * week. An instant in time can be represented by a millisecond value that is
  67   69   * an offset from the <a name="Epoch"><em>Epoch</em></a>, January 1, 1970
  68   70   * 00:00:00.000 GMT (Gregorian).
↓ open down ↓ 631 lines elided ↑ open up ↑
 700  702       * Value of the {@link #AM_PM} field indicating the
 701  703       * period of the day from noon to just before midnight.
 702  704       */
 703  705      public final static int PM = 1;
 704  706  
 705  707      /**
 706  708       * A style specifier for {@link #getDisplayNames(int, int, Locale)
 707  709       * getDisplayNames} indicating names in all styles, such as
 708  710       * "January" and "Jan".
 709  711       *
      712 +     * @see #SHORT_FORMAT
      713 +     * @see #LONG_FORMAT
      714 +     * @see #SHORT_STANDALONE
      715 +     * @see #LONG_STANDALONE
 710  716       * @see #SHORT
 711  717       * @see #LONG
 712  718       * @since 1.6
 713  719       */
 714  720      public static final int ALL_STYLES = 0;
 715  721  
      722 +    static final int STANDALONE_MASK = 0x8000;
      723 +
 716  724      /**
 717  725       * A style specifier for {@link #getDisplayName(int, int, Locale)
 718  726       * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
 719      -     * getDisplayNames} indicating a short name, such as "Jan".
      727 +     * getDisplayNames} equivalent to {@link #SHORT_FORMAT}.
 720  728       *
      729 +     * @see #SHORT_STANDALONE
 721  730       * @see #LONG
 722  731       * @since 1.6
 723  732       */
 724  733      public static final int SHORT = 1;
 725  734  
 726  735      /**
 727  736       * A style specifier for {@link #getDisplayName(int, int, Locale)
 728  737       * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
 729      -     * getDisplayNames} indicating a long name, such as "January".
      738 +     * getDisplayNames} equivalent to {@link #LONG_FORMAT}.
 730  739       *
      740 +     * @see #LONG_STANDALONE
 731  741       * @see #SHORT
 732  742       * @since 1.6
 733  743       */
 734  744      public static final int LONG = 2;
 735  745  
      746 +    /**
      747 +     * A style specifier for {@link #getDisplayName(int, int, Locale)
      748 +     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
      749 +     * getDisplayNames} indicating a short name used for format.
      750 +     *
      751 +     * @see #SHORT_STANDALONE
      752 +     * @see #LONG_FORMAT
      753 +     * @see #LONG_STANDALONE
      754 +     * @since 1.8
      755 +     */
      756 +    public static final int SHORT_FORMAT = 1;
      757 +
      758 +    /**
      759 +     * A style specifier for {@link #getDisplayName(int, int, Locale)
      760 +     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
      761 +     * getDisplayNames} indicating a long name used for format.
      762 +     *
      763 +     * @see #LONG_STANDALONE
      764 +     * @see #SHORT_FORMAT
      765 +     * @see #SHORT_STANDALONE
      766 +     * @since 1.8
      767 +     */
      768 +    public static final int LONG_FORMAT = 2;
      769 +
      770 +    /**
      771 +     * A style specifier for {@link #getDisplayName(int, int, Locale)
      772 +     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
      773 +     * getDisplayNames} indicating a short name used independently,
      774 +     * such as a month abbreviation as calendar headers.
      775 +     *
      776 +     * @see #SHORT_FORMAT
      777 +     * @see #LONG_FORMAT
      778 +     * @see #LONG_STANDALONE
      779 +     * @since 1.8
      780 +     */
      781 +    public static final int SHORT_STANDALONE = SHORT | STANDALONE_MASK;
      782 +
      783 +    /**
      784 +     * A style specifier for {@link #getDisplayName(int, int, Locale)
      785 +     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
      786 +     * getDisplayNames} indicating a long name used independently,
      787 +     * such as a month name as calendar headers.
      788 +     *
      789 +     * @see #LONG_FORMAT
      790 +     * @see #SHORT_FORMAT
      791 +     * @see #SHORT_STANDALONE
      792 +     * @since 1.8
      793 +     */
      794 +    public static final int LONG_STANDALONE = LONG | STANDALONE_MASK;
      795 +
 736  796      // Internal notes:
 737  797      // Calendar contains two kinds of time representations: current "time" in
 738  798      // milliseconds, and a set of calendar "fields" representing the current time.
 739  799      // The two representations are usually in sync, but can get out of sync
 740  800      // as follows.
 741  801      // 1. Initially, no fields are set, and the time is invalid.
 742  802      // 2. If the time is set, all fields are computed and in sync.
 743  803      // 3. If a single field is set, the time is invalid.
 744  804      // Recomputation of the time and fields happens when the object needs
 745  805      // to return a result to the user, or use a result for a computation.
 746  806  
 747  807      /**
 748  808       * The calendar field values for the currently set time for this calendar.
 749  809       * This is an array of <code>FIELD_COUNT</code> integers, with index values
 750  810       * <code>ERA</code> through <code>DST_OFFSET</code>.
 751  811       * @serial
 752  812       */
      813 +    @SuppressWarnings("ProtectedField")
 753  814      protected int           fields[];
 754  815  
 755  816      /**
 756  817       * The flags which tell if a specified calendar field for the calendar is set.
 757  818       * A new object has no fields set.  After the first call to a method
 758  819       * which generates the fields, they all remain set after that.
 759  820       * This is an array of <code>FIELD_COUNT</code> booleans, with index values
 760  821       * <code>ERA</code> through <code>DST_OFFSET</code>.
 761  822       * @serial
 762  823       */
      824 +    @SuppressWarnings("ProtectedField")
 763  825      protected boolean       isSet[];
 764  826  
 765  827      /**
 766  828       * Pseudo-time-stamps which specify when each field was set. There
 767  829       * are two special values, UNSET and COMPUTED. Values from
 768  830       * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
 769  831       */
 770  832      transient private int   stamp[];
 771  833  
 772  834      /**
 773  835       * The currently set time for this calendar, expressed in milliseconds after
 774  836       * January 1, 1970, 0:00:00 GMT.
 775  837       * @see #isTimeSet
 776  838       * @serial
 777  839       */
      840 +    @SuppressWarnings("ProtectedField")
 778  841      protected long          time;
 779  842  
 780  843      /**
 781  844       * True if then the value of <code>time</code> is valid.
 782  845       * The time is made invalid by a change to an item of <code>field[]</code>.
 783  846       * @see #time
 784  847       * @serial
 785  848       */
      849 +    @SuppressWarnings("ProtectedField")
 786  850      protected boolean       isTimeSet;
 787  851  
 788  852      /**
 789  853       * True if <code>fields[]</code> are in sync with the currently set time.
 790  854       * If false, then the next attempt to get the value of a field will
 791  855       * force a recomputation of all fields from the current value of
 792  856       * <code>time</code>.
 793  857       * @serial
 794  858       */
      859 +    @SuppressWarnings("ProtectedField")
 795  860      protected boolean       areFieldsSet;
 796  861  
 797  862      /**
 798  863       * True if all fields have been set.
 799  864       * @serial
 800  865       */
 801  866      transient boolean       areAllFieldsSet;
 802  867  
 803  868      /**
 804  869       * <code>True</code> if this calendar allows out-of-range field values during computation
↓ open down ↓ 98 lines elided ↑ open up ↑
 903  968       * is written.
 904  969       * @serial
 905  970       * @since JDK1.1.6
 906  971       */
 907  972      private int             serialVersionOnStream = currentSerialVersion;
 908  973  
 909  974      // Proclaim serialization compatibility with JDK 1.1
 910  975      static final long       serialVersionUID = -1807547505821590642L;
 911  976  
 912  977      // Mask values for calendar fields
      978 +    @SuppressWarnings("PointlessBitwiseExpression")
 913  979      final static int ERA_MASK           = (1 << ERA);
 914  980      final static int YEAR_MASK          = (1 << YEAR);
 915  981      final static int MONTH_MASK         = (1 << MONTH);
 916  982      final static int WEEK_OF_YEAR_MASK  = (1 << WEEK_OF_YEAR);
 917  983      final static int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
 918  984      final static int DAY_OF_MONTH_MASK  = (1 << DAY_OF_MONTH);
 919  985      final static int DATE_MASK          = DAY_OF_MONTH_MASK;
 920  986      final static int DAY_OF_YEAR_MASK   = (1 << DAY_OF_YEAR);
 921  987      final static int DAY_OF_WEEK_MASK   = (1 << DAY_OF_WEEK);
 922  988      final static int DAY_OF_WEEK_IN_MONTH_MASK  = (1 << DAY_OF_WEEK_IN_MONTH);
↓ open down ↓ 88 lines elided ↑ open up ↑
1011 1077                                         Locale aLocale)
1012 1078      {
1013 1079          return createCalendar(zone, aLocale);
1014 1080      }
1015 1081  
1016 1082      private static Calendar createCalendar(TimeZone zone,
1017 1083                                             Locale aLocale)
1018 1084      {
1019 1085          Calendar cal = null;
1020 1086  
     1087 +        if (aLocale.hasExtensions()) {
1021 1088          String caltype = aLocale.getUnicodeLocaleType("ca");
1022      -        if (caltype == null) {
1023      -            // Calendar type is not specified.
1024      -            // If the specified locale is a Thai locale,
1025      -            // returns a BuddhistCalendar instance.
1026      -            if ("th".equals(aLocale.getLanguage())
1027      -                    && ("TH".equals(aLocale.getCountry()))) {
     1089 +            if (caltype != null) {
     1090 +                switch (caltype) {
     1091 +                case "buddhist":
1028 1092                  cal = new BuddhistCalendar(zone, aLocale);
     1093 +                    break;
     1094 +                case "japanese":
     1095 +                    cal = new JapaneseImperialCalendar(zone, aLocale);
     1096 +                    break;
     1097 +                case "gregory":
     1098 +                    cal = new GregorianCalendar(zone, aLocale);
     1099 +                    break;
     1100 +                }
     1101 +            }
     1102 +        }
     1103 +        if (cal == null) {
     1104 +            // If no known calendar type is explicitly specified,
     1105 +            // perform the traditional way to create a Calendar:
     1106 +            // create a BuddhistCalendar for th_TH locale,
     1107 +            // a JapaneseImperialCalendar for ja_JP_JP locale, or
     1108 +            // a GregorianCalendar for any other locales.
     1109 +            // NOTE: The language, country and variant strings are interned.
     1110 +            if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
     1111 +                cal = new BuddhistCalendar(zone, aLocale);
     1112 +            } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
     1113 +                       && aLocale.getCountry() == "JP") {
     1114 +                cal = new JapaneseImperialCalendar(zone, aLocale);
1029 1115              } else {
1030 1116                  cal = new GregorianCalendar(zone, aLocale);
1031 1117              }
1032      -        } else if (caltype.equals("japanese")) {
1033      -            cal = new JapaneseImperialCalendar(zone, aLocale);
1034      -        } else if (caltype.equals("buddhist")) {
1035      -            cal = new BuddhistCalendar(zone, aLocale);
1036      -        } else {
1037      -            // Unsupported calendar type.
1038      -            // Use Gregorian calendar as a fallback.
1039      -            cal = new GregorianCalendar(zone, aLocale);
1040 1118          }
1041      -
1042 1119          return cal;
1043 1120      }
1044 1121  
1045 1122      /**
1046 1123       * Returns an array of all locales for which the <code>getInstance</code>
1047 1124       * methods of this class can return localized instances.
1048 1125       * The array returned must contain at least a <code>Locale</code>
1049 1126       * instance equal to {@link java.util.Locale#US Locale.US}.
1050 1127       *
1051 1128       * @return An array of locales for which localized
↓ open down ↓ 334 lines elided ↑ open up ↑
1386 1463       * would return <code>null</code>.
1387 1464       *
1388 1465       * <p>The default implementation supports the calendar fields for
1389 1466       * which a {@link DateFormatSymbols} has names in the given
1390 1467       * <code>locale</code>.
1391 1468       *
1392 1469       * @param field
1393 1470       *        the calendar field for which the string representation
1394 1471       *        is returned
1395 1472       * @param style
1396      -     *        the style applied to the string representation; one of
1397      -     *        {@link #SHORT} or {@link #LONG}.
     1473 +     *        the style applied to the string representation; one of {@link
     1474 +     *        #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE},
     1475 +     *        {@link #LONG_FORMAT} ({@link #LONG}) or {@link #LONG_STANDALONE}.
1398 1476       * @param locale
1399 1477       *        the locale for the string representation
     1478 +     *        (any calendar types specified by {@code locale} are ignored)
1400 1479       * @return the string representation of the given
1401 1480       *        <code>field</code> in the given <code>style</code>, or
1402 1481       *        <code>null</code> if no string representation is
1403 1482       *        applicable.
1404 1483       * @exception IllegalArgumentException
1405 1484       *        if <code>field</code> or <code>style</code> is invalid,
1406 1485       *        or if this <code>Calendar</code> is non-lenient and any
1407 1486       *        of the calendar fields have invalid values
1408 1487       * @exception NullPointerException
1409 1488       *        if <code>locale</code> is null
1410 1489       * @since 1.6
1411 1490       */
1412 1491      public String getDisplayName(int field, int style, Locale locale) {
1413      -        if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
1414      -                                    ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
     1492 +        if (!checkDisplayNameParams(field, style, SHORT, LONG, locale,
     1493 +                            ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
1415 1494              return null;
1416 1495          }
1417 1496  
     1497 +        // the standalone styles are supported only through CalendarDataProviders.
     1498 +        if (isStandaloneStyle(style)) {
     1499 +            return CalendarDataUtility.retrieveFieldValueName(getCalendarType(),
     1500 +                                                              field, get(field),
     1501 +                                                              style, locale);
     1502 +        }
     1503 +
1418 1504          DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
1419 1505          String[] strings = getFieldStrings(field, style, symbols);
1420 1506          if (strings != null) {
1421 1507              int fieldValue = get(field);
1422 1508              if (fieldValue < strings.length) {
1423 1509                  return strings[fieldValue];
1424 1510              }
1425 1511          }
1426 1512          return null;
1427 1513      }
↓ open down ↓ 18 lines elided ↑ open up ↑
1446 1532       * <p>The default implementation supports display names contained in
1447 1533       * a {@link DateFormatSymbols}. For example, if <code>field</code>
1448 1534       * is {@link #MONTH} and <code>style</code> is {@link
1449 1535       * #ALL_STYLES}, this method returns a <code>Map</code> containing
1450 1536       * all strings returned by {@link DateFormatSymbols#getShortMonths()}
1451 1537       * and {@link DateFormatSymbols#getMonths()}.
1452 1538       *
1453 1539       * @param field
1454 1540       *        the calendar field for which the display names are returned
1455 1541       * @param style
1456      -     *        the style applied to the display names; one of {@link
1457      -     *        #SHORT}, {@link #LONG}, or {@link #ALL_STYLES}.
     1542 +     *        the style applied to the string representation; one of {@link
     1543 +     *        #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE},
     1544 +     *        {@link #LONG_FORMAT} ({@link #LONG}) or {@link #LONG_STANDALONE}.
1458 1545       * @param locale
1459 1546       *        the locale for the display names
1460 1547       * @return a <code>Map</code> containing all display names in
1461 1548       *        <code>style</code> and <code>locale</code> and their
1462 1549       *        field values, or <code>null</code> if no display names
1463 1550       *        are defined for <code>field</code>
1464 1551       * @exception IllegalArgumentException
1465 1552       *        if <code>field</code> or <code>style</code> is invalid,
1466 1553       *        or if this <code>Calendar</code> is non-lenient and any
1467 1554       *        of the calendar fields have invalid values
1468 1555       * @exception NullPointerException
1469 1556       *        if <code>locale</code> is null
1470 1557       * @since 1.6
1471 1558       */
1472 1559      public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
1473 1560          if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
1474 1561                                      ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
1475 1562              return null;
1476 1563          }
1477      -
1478      -        // ALL_STYLES
1479      -        if (style == ALL_STYLES) {
1480      -            Map<String,Integer> shortNames = getDisplayNamesImpl(field, SHORT, locale);
1481      -            if (field == ERA || field == AM_PM) {
1482      -                return shortNames;
1483      -            }
1484      -            Map<String,Integer> longNames = getDisplayNamesImpl(field, LONG, locale);
1485      -            if (shortNames == null) {
1486      -                return longNames;
1487      -            }
1488      -            if (longNames != null) {
1489      -                shortNames.putAll(longNames);
1490      -            }
1491      -            return shortNames;
     1564 +        if (style == ALL_STYLES || isStandaloneStyle(style)) {
     1565 +            return CalendarDataUtility.retrieveFieldValueNames(getCalendarType(), field, style, locale);
1492 1566          }
1493      -
1494 1567          // SHORT or LONG
1495 1568          return getDisplayNamesImpl(field, style, locale);
1496 1569      }
1497 1570  
1498 1571      private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
1499 1572          DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
1500 1573          String[] strings = getFieldStrings(field, style, symbols);
1501 1574          if (strings != null) {
1502 1575              Map<String,Integer> names = new HashMap<>();
1503 1576              for (int i = 0; i < strings.length; i++) {
↓ open down ↓ 2 lines elided ↑ open up ↑
1506 1579                  }
1507 1580                  names.put(strings[i], i);
1508 1581              }
1509 1582              return names;
1510 1583          }
1511 1584          return null;
1512 1585      }
1513 1586  
1514 1587      boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle,
1515 1588                                     Locale locale, int fieldMask) {
     1589 +        int baseStyle = getBaseStyle(style); // Ignore the standalone mask
1516 1590          if (field < 0 || field >= fields.length ||
1517      -            style < minStyle || style > maxStyle) {
     1591 +            baseStyle < minStyle || baseStyle > maxStyle) {
1518 1592              throw new IllegalArgumentException();
1519 1593          }
1520 1594          if (locale == null) {
1521 1595              throw new NullPointerException();
1522 1596          }
1523 1597          return isFieldSet(fieldMask, field);
1524 1598      }
1525 1599  
1526 1600      private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
     1601 +        int baseStyle = getBaseStyle(style); // ignore the standalone mask
1527 1602          String[] strings = null;
1528 1603          switch (field) {
1529 1604          case ERA:
1530 1605              strings = symbols.getEras();
1531 1606              break;
1532 1607  
1533 1608          case MONTH:
1534      -            strings = (style == LONG) ? symbols.getMonths() : symbols.getShortMonths();
     1609 +            strings = (baseStyle == LONG) ? symbols.getMonths() : symbols.getShortMonths();
1535 1610              break;
1536 1611  
1537 1612          case DAY_OF_WEEK:
1538      -            strings = (style == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
     1613 +            strings = (baseStyle == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
1539 1614              break;
1540 1615  
1541 1616          case AM_PM:
1542 1617              strings = symbols.getAmPmStrings();
1543 1618              break;
1544 1619          }
1545 1620          return strings;
1546 1621      }
1547 1622  
1548 1623      /**
1549 1624       * Fills in any unset fields in the calendar fields. First, the {@link
1550 1625       * #computeTime()} method is called if the time value (millisecond offset
1551 1626       * from the <a href="#Epoch">Epoch</a>) has not been calculated from
1552 1627       * calendar field values. Then, the {@link #computeFields()} method is
1553 1628       * called to calculate all calendar field values.
1554 1629       */
1555 1630      protected void complete()
1556 1631      {
1557      -        if (!isTimeSet)
     1632 +        if (!isTimeSet) {
1558 1633              updateTime();
     1634 +        }
1559 1635          if (!areFieldsSet || !areAllFieldsSet) {
1560 1636              computeFields(); // fills in unset fields
1561 1637              areAllFieldsSet = areFieldsSet = true;
1562 1638          }
1563 1639      }
1564 1640  
1565 1641      /**
1566 1642       * Returns whether the value of the specified calendar field has been set
1567 1643       * externally by calling one of the setter methods rather than by the
1568 1644       * internal time calculation.
↓ open down ↓ 113 lines elided ↑ open up ↑
1682 1758       * Marks this Calendar as not sync'd.
1683 1759       */
1684 1760      final void setUnnormalized() {
1685 1761          areFieldsSet = areAllFieldsSet = false;
1686 1762      }
1687 1763  
1688 1764      /**
1689 1765       * Returns whether the specified <code>field</code> is on in the
1690 1766       * <code>fieldMask</code>.
1691 1767       */
1692      -    static final boolean isFieldSet(int fieldMask, int field) {
     1768 +    static boolean isFieldSet(int fieldMask, int field) {
1693 1769          return (fieldMask & (1 << field)) != 0;
1694 1770      }
1695 1771  
1696 1772      /**
1697 1773       * Returns a field mask indicating which calendar field values
1698 1774       * to be used to calculate the time value. The calendar fields are
1699 1775       * returned as a bit mask, each bit of which corresponds to a field, i.e.,
1700 1776       * the mask value of <code>field</code> is <code>(1 &lt;&lt;
1701 1777       * field)</code>. For example, 0x26 represents the <code>YEAR</code>,
1702 1778       * <code>MONTH</code>, and <code>DAY_OF_MONTH</code> fields (i.e., 0x26 is
↓ open down ↓ 155 lines elided ↑ open up ↑
1858 1934          if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP) {
1859 1935                  fieldMask |= ZONE_OFFSET_MASK;
1860 1936          }
1861 1937          if (stamp[DST_OFFSET] >= MINIMUM_USER_STAMP) {
1862 1938              fieldMask |= DST_OFFSET_MASK;
1863 1939          }
1864 1940  
1865 1941          return fieldMask;
1866 1942      }
1867 1943  
     1944 +    int getBaseStyle(int style) {
     1945 +        return style & ~STANDALONE_MASK;
     1946 +    }
     1947 +
     1948 +    boolean isStandaloneStyle(int style) {
     1949 +        return (style & STANDALONE_MASK) != 0;
     1950 +    }
     1951 +
1868 1952      /**
1869 1953       * Returns the pseudo-time-stamp for two fields, given their
1870 1954       * individual pseudo-time-stamps.  If either of the fields
1871 1955       * is unset, then the aggregate is unset.  Otherwise, the
1872 1956       * aggregate is the later of the two stamps.
1873 1957       */
1874      -    private static final int aggregateStamp(int stamp_a, int stamp_b) {
     1958 +    private static int aggregateStamp(int stamp_a, int stamp_b) {
1875 1959          if (stamp_a == UNSET || stamp_b == UNSET) {
1876 1960              return UNSET;
1877 1961          }
1878 1962          return (stamp_a > stamp_b) ? stamp_a : stamp_b;
1879 1963      }
1880 1964  
1881 1965      /**
     1966 +     * Returns the calendar type of this {@code Calendar}. Calendar types are
     1967 +     * defined by the <em>Unicode Locale Data Markup Language (LDML)</em>
     1968 +     * specification.
     1969 +     *
     1970 +     * <p>The default implementation of this method returns the class name of
     1971 +     * this {@code Calendar} instance. Any subclasses that implement
     1972 +     * LDML-defined calendar systems should override this method to return
     1973 +     * appropriate calendar types.
     1974 +     *
     1975 +     * @return the LDML-defined calendar type or the class name of this
     1976 +     *         {@code Calendar} instance
     1977 +     * @since 1.8
     1978 +     * @see <a href="Locale.html#def_extensions">Locale extensions</a>
     1979 +     * @see Locale.Builder#setLocale(Locale)
     1980 +     * @see Locale.Builder#setUnicodeLocaleKeyword(String, String)
     1981 +     */
     1982 +    public String getCalendarType() {
     1983 +        return this.getClass().getName();
     1984 +    }
     1985 +
     1986 +    /**
1882 1987       * Compares this <code>Calendar</code> to the specified
1883 1988       * <code>Object</code>.  The result is <code>true</code> if and only if
1884 1989       * the argument is a <code>Calendar</code> object of the same calendar
1885 1990       * system that represents the same time value (millisecond offset from the
1886 1991       * <a href="#Epoch">Epoch</a>) under the same
1887 1992       * <code>Calendar</code> parameters as this object.
1888 1993       *
1889 1994       * <p>The <code>Calendar</code> parameters are the values represented
1890 1995       * by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
1891 1996       * <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
↓ open down ↓ 1 lines elided ↑ open up ↑
1893 1998       * between the two <code>Calendar</code>s, this method returns
1894 1999       * <code>false</code>.
1895 2000       *
1896 2001       * <p>Use the {@link #compareTo(Calendar) compareTo} method to
1897 2002       * compare only the time values.
1898 2003       *
1899 2004       * @param obj the object to compare with.
1900 2005       * @return <code>true</code> if this object is equal to <code>obj</code>;
1901 2006       * <code>false</code> otherwise.
1902 2007       */
     2008 +    @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
     2009 +    @Override
1903 2010      public boolean equals(Object obj) {
1904      -        if (this == obj)
     2011 +        if (this == obj) {
1905 2012              return true;
     2013 +        }
1906 2014          try {
1907 2015              Calendar that = (Calendar)obj;
1908 2016              return compareTo(getMillisOf(that)) == 0 &&
1909 2017                  lenient == that.lenient &&
1910 2018                  firstDayOfWeek == that.firstDayOfWeek &&
1911 2019                  minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
1912 2020                  zone.equals(that.zone);
1913 2021          } catch (Exception e) {
1914 2022              // Note: GregorianCalendar.computeTime throws
1915 2023              // IllegalArgumentException if the ERA value is invalid
↓ open down ↓ 1 lines elided ↑ open up ↑
1917 2025          }
1918 2026          return false;
1919 2027      }
1920 2028  
1921 2029      /**
1922 2030       * Returns a hash code for this calendar.
1923 2031       *
1924 2032       * @return a hash code value for this object.
1925 2033       * @since 1.2
1926 2034       */
     2035 +    @Override
1927 2036      public int hashCode() {
1928 2037          // 'otheritems' represents the hash code for the previous versions.
1929 2038          int otheritems = (lenient ? 1 : 0)
1930 2039              | (firstDayOfWeek << 1)
1931 2040              | (minimalDaysInFirstWeek << 4)
1932 2041              | (zone.hashCode() << 7);
1933 2042          long t = getMillisOf(this);
1934 2043          return (int) t ^ (int)(t >> 32) ^ otheritems;
1935 2044      }
1936 2045  
↓ open down ↓ 51 lines elided ↑ open up ↑
1988 2097       * before the time represented by the argument; and a value greater than
1989 2098       * <code>0</code> if the time of this <code>Calendar</code> is after the
1990 2099       * time represented by the argument.
1991 2100       * @exception NullPointerException if the specified <code>Calendar</code> is
1992 2101       *            <code>null</code>.
1993 2102       * @exception IllegalArgumentException if the time value of the
1994 2103       * specified <code>Calendar</code> object can't be obtained due to
1995 2104       * any invalid calendar values.
1996 2105       * @since   1.5
1997 2106       */
     2107 +    @Override
1998 2108      public int compareTo(Calendar anotherCalendar) {
1999 2109          return compareTo(getMillisOf(anotherCalendar));
2000 2110      }
2001 2111  
2002 2112      /**
2003 2113       * Adds or subtracts the specified amount of time to the given calendar field,
2004 2114       * based on the calendar's rules. For example, to subtract 5 days from
2005 2115       * the current time of the calendar, you can achieve it by calling:
2006 2116       * <p><code>add(Calendar.DAY_OF_MONTH, -5)</code>.
2007 2117       *
↓ open down ↓ 453 lines elided ↑ open up ↑
2461 2571              return fieldValue;
2462 2572          }
2463 2573  
2464 2574          // clone the calendar so we don't mess with the real one, and set it to
2465 2575          // accept anything for the field values.
2466 2576          Calendar work = (Calendar)this.clone();
2467 2577          work.setLenient(true);
2468 2578  
2469 2579          // if we're counting weeks, set the day of the week to Sunday.  We know the
2470 2580          // last week of a month or year will contain the first day of the week.
2471      -        if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH)
     2581 +        if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH) {
2472 2582              work.set(DAY_OF_WEEK, firstDayOfWeek);
     2583 +        }
2473 2584  
2474 2585          // now try each value from getLeastMaximum() to getMaximum() one by one until
2475 2586          // we get a value that normalizes to another value.  The last value that
2476 2587          // normalizes to itself is the actual maximum for the current date
2477 2588          int result = fieldValue;
2478 2589  
2479 2590          do {
2480 2591              work.set(field, fieldValue);
2481 2592              if (work.get(field) != fieldValue) {
2482 2593                  break;
↓ open down ↓ 4 lines elided ↑ open up ↑
2487 2598          } while (fieldValue <= endValue);
2488 2599  
2489 2600          return result;
2490 2601      }
2491 2602  
2492 2603      /**
2493 2604       * Creates and returns a copy of this object.
2494 2605       *
2495 2606       * @return a copy of this object.
2496 2607       */
     2608 +    @Override
2497 2609      public Object clone()
2498 2610      {
2499 2611          try {
2500 2612              Calendar other = (Calendar) super.clone();
2501 2613  
2502 2614              other.fields = new int[FIELD_COUNT];
2503 2615              other.isSet = new boolean[FIELD_COUNT];
2504 2616              other.stamp = new int[FIELD_COUNT];
2505 2617              for (int i = 0; i < FIELD_COUNT; i++) {
2506 2618                  other.fields[i] = fields[i];
↓ open down ↓ 17 lines elided ↑ open up ↑
2524 2636      };
2525 2637  
2526 2638      /**
2527 2639       * Returns the name of the specified calendar field.
2528 2640       *
2529 2641       * @param field the calendar field
2530 2642       * @return the calendar field name
2531 2643       * @exception IndexOutOfBoundsException if <code>field</code> is negative,
2532 2644       * equal to or greater then <code>FIELD_COUNT</code>.
2533 2645       */
2534      -    static final String getFieldName(int field) {
     2646 +    static String getFieldName(int field) {
2535 2647          return FIELD_NAME[field];
2536 2648      }
2537 2649  
2538 2650      /**
2539 2651       * Return a string representation of this calendar. This method
2540 2652       * is intended to be used only for debugging purposes, and the
2541 2653       * format of the returned string may vary between implementations.
2542 2654       * The returned string may be empty but may not be <code>null</code>.
2543 2655       *
2544 2656       * @return  a string representation of this calendar.
2545 2657       */
     2658 +    @Override
2546 2659      public String toString() {
2547 2660          // NOTE: BuddhistCalendar.toString() interprets the string
2548 2661          // produced by this method so that the Gregorian year number
2549 2662          // is substituted by its B.E. year value. It relies on
2550 2663          // "...,YEAR=<year>,..." or "...,YEAR=?,...".
2551 2664          StringBuilder buffer = new StringBuilder(800);
2552 2665          buffer.append(getClass().getName()).append('[');
2553 2666          appendValue(buffer, "time", isTimeSet, time);
2554 2667          buffer.append(",areFieldsSet=").append(areFieldsSet);
2555 2668          buffer.append(",areAllFieldsSet=").append(areAllFieldsSet);
↓ open down ↓ 4 lines elided ↑ open up ↑
2560 2673          for (int i = 0; i < FIELD_COUNT; ++i) {
2561 2674              buffer.append(',');
2562 2675              appendValue(buffer, FIELD_NAME[i], isSet(i), (long) fields[i]);
2563 2676          }
2564 2677          buffer.append(']');
2565 2678          return buffer.toString();
2566 2679      }
2567 2680  
2568 2681      // =======================privates===============================
2569 2682  
2570      -    private static final void appendValue(StringBuilder sb, String item, boolean valid, long value) {
     2683 +    private static void appendValue(StringBuilder sb, String item, boolean valid, long value) {
2571 2684          sb.append(item).append('=');
2572 2685          if (valid) {
2573 2686              sb.append(value);
2574 2687          } else {
2575 2688              sb.append('?');
2576 2689          }
2577 2690      }
2578 2691  
2579 2692      /**
2580 2693       * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.
2581 2694       * They are used to figure out the week count for a specific date for
2582 2695       * a given locale. These must be set when a Calendar is constructed.
2583 2696       * @param desiredLocale the given locale.
2584 2697       */
2585 2698      private void setWeekCountData(Locale desiredLocale)
2586 2699      {
2587 2700          /* try to get the Locale data from the cache */
2588 2701          int[] data = cachedLocaleData.get(desiredLocale);
2589 2702          if (data == null) {  /* cache miss */
2590      -            ResourceBundle bundle = LocaleData.getCalendarData(desiredLocale);
     2703 +            LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(CalendarDataProvider.class, desiredLocale);
     2704 +            CalendarDataProvider provider = adapter.getCalendarDataProvider();
2591 2705              data = new int[2];
2592      -            data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek"));
2593      -            data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek"));
     2706 +            data[0] = provider.getFirstDayOfWeek(desiredLocale);
     2707 +            data[1] = provider.getMinimalDaysInFirstWeek(desiredLocale);
     2708 +            assert data[0] != 0 && data[1] != 0;
2594 2709              cachedLocaleData.putIfAbsent(desiredLocale, data);
2595 2710          }
2596 2711          firstDayOfWeek = data[0];
2597 2712          minimalDaysInFirstWeek = data[1];
2598 2713      }
2599 2714  
2600 2715      /**
2601 2716       * Recomputes the time and updates the status fields isTimeSet
2602 2717       * and areFieldsSet.  Callers should check isTimeSet and only
2603 2718       * call this method if isTimeSet is false.
↓ open down ↓ 3 lines elided ↑ open up ↑
2607 2722          // The areFieldsSet and areAllFieldsSet values are no longer
2608 2723          // controlled here (as of 1.5).
2609 2724          isTimeSet = true;
2610 2725      }
2611 2726  
2612 2727      private int compareTo(long t) {
2613 2728          long thisTime = getMillisOf(this);
2614 2729          return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
2615 2730      }
2616 2731  
2617      -    private static final long getMillisOf(Calendar calendar) {
     2732 +    private static long getMillisOf(Calendar calendar) {
2618 2733          if (calendar.isTimeSet) {
2619 2734              return calendar.time;
2620 2735          }
2621 2736          Calendar cal = (Calendar) calendar.clone();
2622 2737          cal.setLenient(true);
2623 2738          return cal.getTimeInMillis();
2624 2739      }
2625 2740  
2626 2741      /**
2627 2742       * Adjusts the stamp[] values before nextStamp overflow. nextStamp
2628 2743       * is set to the next stamp value upon the return.
2629 2744       */
2630      -    private final void adjustStamp() {
     2745 +    private void adjustStamp() {
2631 2746          int max = MINIMUM_USER_STAMP;
2632 2747          int newStamp = MINIMUM_USER_STAMP;
2633 2748  
2634 2749          for (;;) {
2635 2750              int min = Integer.MAX_VALUE;
2636 2751              for (int i = 0; i < stamp.length; i++) {
2637 2752                  int v = stamp[i];
2638 2753                  if (v >= newStamp && min > v) {
2639 2754                      min = v;
2640 2755                  }
↓ open down ↓ 104 lines elided ↑ open up ↑
2745 2860      private static class CalendarAccessControlContext {
2746 2861          private static final AccessControlContext INSTANCE;
2747 2862          static {
2748 2863              RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
2749 2864              PermissionCollection perms = perm.newPermissionCollection();
2750 2865              perms.add(perm);
2751 2866              INSTANCE = new AccessControlContext(new ProtectionDomain[] {
2752 2867                                                      new ProtectionDomain(null, perms)
2753 2868                                                  });
2754 2869          }
     2870 +        private CalendarAccessControlContext() {
     2871 +        }
2755 2872      }
2756 2873  
2757 2874      /**
2758 2875       * Reconstitutes this object from a stream (i.e., deserialize it).
2759 2876       */
2760 2877      private void readObject(ObjectInputStream stream)
2761 2878           throws IOException, ClassNotFoundException
2762 2879      {
2763 2880          final ObjectInputStream input = stream;
2764 2881          input.defaultReadObject();
2765 2882  
2766 2883          stamp = new int[FIELD_COUNT];
2767 2884  
2768 2885          // Starting with version 2 (not implemented yet), we expect that
2769 2886          // fields[], isSet[], isTimeSet, and areFieldsSet may not be
2770 2887          // streamed out anymore.  We expect 'time' to be correct.
2771 2888          if (serialVersionOnStream >= 2)
2772 2889          {
2773 2890              isTimeSet = true;
2774      -            if (fields == null) fields = new int[FIELD_COUNT];
2775      -            if (isSet == null) isSet = new boolean[FIELD_COUNT];
     2891 +            if (fields == null) {
     2892 +                fields = new int[FIELD_COUNT];
     2893 +            }
     2894 +            if (isSet == null) {
     2895 +                isSet = new boolean[FIELD_COUNT];
     2896 +            }
2776 2897          }
2777 2898          else if (serialVersionOnStream >= 0)
2778 2899          {
2779      -            for (int i=0; i<FIELD_COUNT; ++i)
     2900 +            for (int i=0; i<FIELD_COUNT; ++i) {
2780 2901                  stamp[i] = isSet[i] ? COMPUTED : UNSET;
     2902 +            }
2781 2903          }
2782 2904  
2783 2905          serialVersionOnStream = currentSerialVersion;
2784 2906  
2785 2907          // If there's a ZoneInfo object, use it for zone.
2786 2908          ZoneInfo zi = null;
2787 2909          try {
2788 2910              zi = AccessController.doPrivileged(
2789 2911                      new PrivilegedExceptionAction<ZoneInfo>() {
     2912 +                        @Override
2790 2913                          public ZoneInfo run() throws Exception {
2791 2914                              return (ZoneInfo) input.readObject();
2792 2915                          }
2793 2916                      },
2794 2917                      CalendarAccessControlContext.INSTANCE);
2795 2918          } catch (PrivilegedActionException pae) {
2796 2919              Exception e = pae.getException();
2797 2920              if (!(e instanceof OptionalDataException)) {
2798 2921                  if (e instanceof RuntimeException) {
2799 2922                      throw (RuntimeException) e;
↓ open down ↓ 25 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX