src/share/classes/java/util/Calendar.java

Print this page
rev 5615 : 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 Jigsaw. by Naoto Sato and Masayoshi Okutsu)

*** 51,63 **** import java.security.ProtectionDomain; import java.text.DateFormat; import java.text.DateFormatSymbols; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import sun.util.BuddhistCalendar; import sun.util.calendar.ZoneInfo; ! import sun.util.resources.LocaleData; /** * The <code>Calendar</code> class is an abstract class that provides methods * for converting between a specific instant in time and a set of {@link * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>, --- 51,65 ---- import java.security.ProtectionDomain; import java.text.DateFormat; import java.text.DateFormatSymbols; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; + import java.util.spi.CalendarDataProvider; import sun.util.BuddhistCalendar; + import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.calendar.ZoneInfo; ! import sun.util.locale.provider.CalendarDataUtility; /** * The <code>Calendar</code> class is an abstract class that provides methods * for converting between a specific instant in time and a set of {@link * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
*** 705,740 **** /** * A style specifier for {@link #getDisplayNames(int, int, Locale) * getDisplayNames} indicating names in all styles, such as * "January" and "Jan". * * @see #SHORT * @see #LONG * @since 1.6 */ public static final int ALL_STYLES = 0; /** * A style specifier for {@link #getDisplayName(int, int, Locale) * getDisplayName} and {@link #getDisplayNames(int, int, Locale) ! * getDisplayNames} indicating a short name, such as "Jan". * * @see #LONG * @since 1.6 */ public static final int SHORT = 1; /** * A style specifier for {@link #getDisplayName(int, int, Locale) * getDisplayName} and {@link #getDisplayNames(int, int, Locale) ! * getDisplayNames} indicating a long name, such as "January". * * @see #SHORT * @since 1.6 */ public static final int LONG = 2; // Internal notes: // Calendar contains two kinds of time representations: current "time" in // milliseconds, and a set of calendar "fields" representing the current time. // The two representations are usually in sync, but can get out of sync // as follows. --- 707,800 ---- /** * A style specifier for {@link #getDisplayNames(int, int, Locale) * getDisplayNames} indicating names in all styles, such as * "January" and "Jan". * + * @see #SHORT_FORMAT + * @see #LONG_FORMAT + * @see #SHORT_STANDALONE + * @see #LONG_STANDALONE * @see #SHORT * @see #LONG * @since 1.6 */ public static final int ALL_STYLES = 0; + static final int STANDALONE_MASK = 0x8000; + /** * A style specifier for {@link #getDisplayName(int, int, Locale) * getDisplayName} and {@link #getDisplayNames(int, int, Locale) ! * getDisplayNames} equivalent to {@link #SHORT_FORMAT}. * + * @see #SHORT_STANDALONE * @see #LONG * @since 1.6 */ public static final int SHORT = 1; /** * A style specifier for {@link #getDisplayName(int, int, Locale) * getDisplayName} and {@link #getDisplayNames(int, int, Locale) ! * getDisplayNames} equivalent to {@link #LONG_FORMAT}. * + * @see #LONG_STANDALONE * @see #SHORT * @since 1.6 */ public static final int LONG = 2; + /** + * A style specifier for {@link #getDisplayName(int, int, Locale) + * getDisplayName} and {@link #getDisplayNames(int, int, Locale) + * getDisplayNames} indicating a short name used for format. + * + * @see #SHORT_STANDALONE + * @see #LONG_FORMAT + * @see #LONG_STANDALONE + * @since 1.8 + */ + public static final int SHORT_FORMAT = 1; + + /** + * A style specifier for {@link #getDisplayName(int, int, Locale) + * getDisplayName} and {@link #getDisplayNames(int, int, Locale) + * getDisplayNames} indicating a long name used for format. + * + * @see #LONG_STANDALONE + * @see #SHORT_FORMAT + * @see #SHORT_STANDALONE + * @since 1.8 + */ + public static final int LONG_FORMAT = 2; + + /** + * A style specifier for {@link #getDisplayName(int, int, Locale) + * getDisplayName} and {@link #getDisplayNames(int, int, Locale) + * getDisplayNames} indicating a short name used independently, + * such as a month abbreviation as calendar headers. + * + * @see #SHORT_FORMAT + * @see #LONG_FORMAT + * @see #LONG_STANDALONE + * @since 1.8 + */ + public static final int SHORT_STANDALONE = SHORT | STANDALONE_MASK; + + /** + * A style specifier for {@link #getDisplayName(int, int, Locale) + * getDisplayName} and {@link #getDisplayNames(int, int, Locale) + * getDisplayNames} indicating a long name used independently, + * such as a month name as calendar headers. + * + * @see #LONG_FORMAT + * @see #SHORT_FORMAT + * @see #SHORT_STANDALONE + * @since 1.8 + */ + public static final int LONG_STANDALONE = LONG | STANDALONE_MASK; + // Internal notes: // Calendar contains two kinds of time representations: current "time" in // milliseconds, and a set of calendar "fields" representing the current time. // The two representations are usually in sync, but can get out of sync // as follows.
*** 748,757 **** --- 808,818 ---- * The calendar field values for the currently set time for this calendar. * This is an array of <code>FIELD_COUNT</code> integers, with index values * <code>ERA</code> through <code>DST_OFFSET</code>. * @serial */ + @SuppressWarnings("ProtectedField") protected int fields[]; /** * The flags which tell if a specified calendar field for the calendar is set. * A new object has no fields set. After the first call to a method
*** 758,767 **** --- 819,829 ---- * which generates the fields, they all remain set after that. * This is an array of <code>FIELD_COUNT</code> booleans, with index values * <code>ERA</code> through <code>DST_OFFSET</code>. * @serial */ + @SuppressWarnings("ProtectedField") protected boolean isSet[]; /** * Pseudo-time-stamps which specify when each field was set. There * are two special values, UNSET and COMPUTED. Values from
*** 773,799 **** --- 835,864 ---- * The currently set time for this calendar, expressed in milliseconds after * January 1, 1970, 0:00:00 GMT. * @see #isTimeSet * @serial */ + @SuppressWarnings("ProtectedField") protected long time; /** * True if then the value of <code>time</code> is valid. * The time is made invalid by a change to an item of <code>field[]</code>. * @see #time * @serial */ + @SuppressWarnings("ProtectedField") protected boolean isTimeSet; /** * True if <code>fields[]</code> are in sync with the currently set time. * If false, then the next attempt to get the value of a field will * force a recomputation of all fields from the current value of * <code>time</code>. * @serial */ + @SuppressWarnings("ProtectedField") protected boolean areFieldsSet; /** * True if all fields have been set. * @serial
*** 908,917 **** --- 973,983 ---- // Proclaim serialization compatibility with JDK 1.1 static final long serialVersionUID = -1807547505821590642L; // Mask values for calendar fields + @SuppressWarnings("PointlessBitwiseExpression") final static int ERA_MASK = (1 << ERA); final static int YEAR_MASK = (1 << YEAR); final static int MONTH_MASK = (1 << MONTH); final static int WEEK_OF_YEAR_MASK = (1 << WEEK_OF_YEAR); final static int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
*** 1016,1046 **** private static Calendar createCalendar(TimeZone zone, Locale aLocale) { Calendar cal = null; String caltype = aLocale.getUnicodeLocaleType("ca"); ! if (caltype == null) { ! // Calendar type is not specified. ! // If the specified locale is a Thai locale, ! // returns a BuddhistCalendar instance. ! if ("th".equals(aLocale.getLanguage()) ! && ("TH".equals(aLocale.getCountry()))) { cal = new BuddhistCalendar(zone, aLocale); ! } else { cal = new GregorianCalendar(zone, aLocale); } ! } else if (caltype.equals("japanese")) { ! cal = new JapaneseImperialCalendar(zone, aLocale); ! } else if (caltype.equals("buddhist")) { cal = new BuddhistCalendar(zone, aLocale); } else { - // Unsupported calendar type. - // Use Gregorian calendar as a fallback. cal = new GregorianCalendar(zone, aLocale); } ! return cal; } /** * Returns an array of all locales for which the <code>getInstance</code> --- 1082,1123 ---- private static Calendar createCalendar(TimeZone zone, Locale aLocale) { Calendar cal = null; + if (aLocale.hasExtensions()) { String caltype = aLocale.getUnicodeLocaleType("ca"); ! if (caltype != null) { ! switch (caltype) { ! case "buddhist": cal = new BuddhistCalendar(zone, aLocale); ! break; ! case "japanese": ! cal = new JapaneseImperialCalendar(zone, aLocale); ! break; ! case "gregory": cal = new GregorianCalendar(zone, aLocale); + break; } ! } ! } ! if (cal == null) { ! // If no known calendar type is explicitly specified, ! // perform the traditional way to create a Calendar: ! // create a BuddhistCalendar for th_TH locale, ! // a JapaneseImperialCalendar for ja_JP_JP locale, or ! // a GregorianCalendar for any other locales. ! // NOTE: The language, country and variant strings are interned. ! if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") { cal = new BuddhistCalendar(zone, aLocale); + } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja" + && aLocale.getCountry() == "JP") { + cal = new JapaneseImperialCalendar(zone, aLocale); } else { cal = new GregorianCalendar(zone, aLocale); } ! } return cal; } /** * Returns an array of all locales for which the <code>getInstance</code>
*** 1391,1404 **** * * @param field * the calendar field for which the string representation * is returned * @param style ! * the style applied to the string representation; one of ! * {@link #SHORT} or {@link #LONG}. * @param locale * the locale for the string representation * @return the string representation of the given * <code>field</code> in the given <code>style</code>, or * <code>null</code> if no string representation is * applicable. * @exception IllegalArgumentException --- 1468,1483 ---- * * @param field * the calendar field for which the string representation * is returned * @param style ! * the style applied to the string representation; one of {@link ! * #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE}, ! * {@link #LONG_FORMAT} ({@link #LONG}) or {@link #LONG_STANDALONE}. * @param locale * the locale for the string representation + * (any calendar types specified by {@code locale} are ignored) * @return the string representation of the given * <code>field</code> in the given <code>style</code>, or * <code>null</code> if no string representation is * applicable. * @exception IllegalArgumentException
*** 1408,1422 **** * @exception NullPointerException * if <code>locale</code> is null * @since 1.6 */ public String getDisplayName(int field, int style, Locale locale) { ! if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale, ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { return null; } DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale); String[] strings = getFieldStrings(field, style, symbols); if (strings != null) { int fieldValue = get(field); if (fieldValue < strings.length) { --- 1487,1508 ---- * @exception NullPointerException * if <code>locale</code> is null * @since 1.6 */ public String getDisplayName(int field, int style, Locale locale) { ! if (!checkDisplayNameParams(field, style, SHORT, LONG, locale, ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { return null; } + // the standalone styles are supported only through CalendarDataProviders. + if (isStandaloneStyle(style)) { + return CalendarDataUtility.retrieveFieldValueName(getCalendarType(), + field, get(field), + style, locale); + } + DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale); String[] strings = getFieldStrings(field, style, symbols); if (strings != null) { int fieldValue = get(field); if (fieldValue < strings.length) {
*** 1451,1462 **** * and {@link DateFormatSymbols#getMonths()}. * * @param field * the calendar field for which the display names are returned * @param style ! * the style applied to the display names; one of {@link ! * #SHORT}, {@link #LONG}, or {@link #ALL_STYLES}. * @param locale * the locale for the display names * @return a <code>Map</code> containing all display names in * <code>style</code> and <code>locale</code> and their * field values, or <code>null</code> if no display names --- 1537,1549 ---- * and {@link DateFormatSymbols#getMonths()}. * * @param field * the calendar field for which the display names are returned * @param style ! * the style applied to the string representation; one of {@link ! * #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE}, ! * {@link #LONG_FORMAT} ({@link #LONG}) or {@link #LONG_STANDALONE}. * @param locale * the locale for the display names * @return a <code>Map</code> containing all display names in * <code>style</code> and <code>locale</code> and their * field values, or <code>null</code> if no display names
*** 1472,1498 **** public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) { if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale, ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { return null; } ! ! // ALL_STYLES ! if (style == ALL_STYLES) { ! Map<String,Integer> shortNames = getDisplayNamesImpl(field, SHORT, locale); ! if (field == ERA || field == AM_PM) { ! return shortNames; } - Map<String,Integer> longNames = getDisplayNamesImpl(field, LONG, locale); - if (shortNames == null) { - return longNames; - } - if (longNames != null) { - shortNames.putAll(longNames); - } - return shortNames; - } - // SHORT or LONG return getDisplayNamesImpl(field, style, locale); } private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) { --- 1559,1571 ---- public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) { if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale, ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { return null; } ! if (style == ALL_STYLES || isStandaloneStyle(style)) { ! return CalendarDataUtility.retrieveFieldValueNames(getCalendarType(), field, style, locale); } // SHORT or LONG return getDisplayNamesImpl(field, style, locale); } private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
*** 1511,1543 **** return null; } boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle, Locale locale, int fieldMask) { if (field < 0 || field >= fields.length || ! style < minStyle || style > maxStyle) { throw new IllegalArgumentException(); } if (locale == null) { throw new NullPointerException(); } return isFieldSet(fieldMask, field); } private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) { String[] strings = null; switch (field) { case ERA: strings = symbols.getEras(); break; case MONTH: ! strings = (style == LONG) ? symbols.getMonths() : symbols.getShortMonths(); break; case DAY_OF_WEEK: ! strings = (style == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays(); break; case AM_PM: strings = symbols.getAmPmStrings(); break; --- 1584,1618 ---- return null; } boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle, Locale locale, int fieldMask) { + int baseStyle = getBaseStyle(style); // Ignore the standalone mask if (field < 0 || field >= fields.length || ! baseStyle < minStyle || baseStyle > maxStyle) { throw new IllegalArgumentException(); } if (locale == null) { throw new NullPointerException(); } return isFieldSet(fieldMask, field); } private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) { + int baseStyle = getBaseStyle(style); // ignore the standalone mask String[] strings = null; switch (field) { case ERA: strings = symbols.getEras(); break; case MONTH: ! strings = (baseStyle == LONG) ? symbols.getMonths() : symbols.getShortMonths(); break; case DAY_OF_WEEK: ! strings = (baseStyle == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays(); break; case AM_PM: strings = symbols.getAmPmStrings(); break;
*** 1552,1563 **** * calendar field values. Then, the {@link #computeFields()} method is * called to calculate all calendar field values. */ protected void complete() { ! if (!isTimeSet) updateTime(); if (!areFieldsSet || !areAllFieldsSet) { computeFields(); // fills in unset fields areAllFieldsSet = areFieldsSet = true; } } --- 1627,1639 ---- * calendar field values. Then, the {@link #computeFields()} method is * called to calculate all calendar field values. */ protected void complete() { ! if (!isTimeSet) { updateTime(); + } if (!areFieldsSet || !areAllFieldsSet) { computeFields(); // fills in unset fields areAllFieldsSet = areFieldsSet = true; } }
*** 1687,1697 **** /** * Returns whether the specified <code>field</code> is on in the * <code>fieldMask</code>. */ ! static final boolean isFieldSet(int fieldMask, int field) { return (fieldMask & (1 << field)) != 0; } /** * Returns a field mask indicating which calendar field values --- 1763,1773 ---- /** * Returns whether the specified <code>field</code> is on in the * <code>fieldMask</code>. */ ! static boolean isFieldSet(int fieldMask, int field) { return (fieldMask & (1 << field)) != 0; } /** * Returns a field mask indicating which calendar field values
*** 1863,1886 **** } return fieldMask; } /** * Returns the pseudo-time-stamp for two fields, given their * individual pseudo-time-stamps. If either of the fields * is unset, then the aggregate is unset. Otherwise, the * aggregate is the later of the two stamps. */ ! private static final int aggregateStamp(int stamp_a, int stamp_b) { if (stamp_a == UNSET || stamp_b == UNSET) { return UNSET; } return (stamp_a > stamp_b) ? stamp_a : stamp_b; } /** * Compares this <code>Calendar</code> to the specified * <code>Object</code>. The result is <code>true</code> if and only if * the argument is a <code>Calendar</code> object of the same calendar * system that represents the same time value (millisecond offset from the * <a href="#Epoch">Epoch</a>) under the same --- 1939,1991 ---- } return fieldMask; } + int getBaseStyle(int style) { + return style & ~STANDALONE_MASK; + } + + boolean isStandaloneStyle(int style) { + return (style & STANDALONE_MASK) != 0; + } + /** * Returns the pseudo-time-stamp for two fields, given their * individual pseudo-time-stamps. If either of the fields * is unset, then the aggregate is unset. Otherwise, the * aggregate is the later of the two stamps. */ ! private static int aggregateStamp(int stamp_a, int stamp_b) { if (stamp_a == UNSET || stamp_b == UNSET) { return UNSET; } return (stamp_a > stamp_b) ? stamp_a : stamp_b; } /** + * Returns the calendar type of this {@code Calendar}. Calendar types are + * defined by the <em>Unicode Locale Data Markup Language (LDML)</em> + * specification. + * + * <p>The default implementation of this method returns the class name of + * this {@code Calendar} instance. Any subclasses that implement + * LDML-defined calendar systems should override this method to return + * appropriate calendar types. + * + * @return the LDML-defined calendar type or the class name of this + * {@code Calendar} instance + * @since 1.8 + * @see <a href="Locale.html#def_extensions">Locale extensions</a> + * @see Locale.Builder#setLocale(Locale) + * @see Locale.Builder#setUnicodeLocaleKeyword(String, String) + */ + public String getCalendarType() { + return this.getClass().getName(); + } + + /** * Compares this <code>Calendar</code> to the specified * <code>Object</code>. The result is <code>true</code> if and only if * the argument is a <code>Calendar</code> object of the same calendar * system that represents the same time value (millisecond offset from the * <a href="#Epoch">Epoch</a>) under the same
*** 1898,1910 **** * * @param obj the object to compare with. * @return <code>true</code> if this object is equal to <code>obj</code>; * <code>false</code> otherwise. */ public boolean equals(Object obj) { ! if (this == obj) return true; try { Calendar that = (Calendar)obj; return compareTo(getMillisOf(that)) == 0 && lenient == that.lenient && firstDayOfWeek == that.firstDayOfWeek && --- 2003,2018 ---- * * @param obj the object to compare with. * @return <code>true</code> if this object is equal to <code>obj</code>; * <code>false</code> otherwise. */ + @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") + @Override public boolean equals(Object obj) { ! if (this == obj) { return true; + } try { Calendar that = (Calendar)obj; return compareTo(getMillisOf(that)) == 0 && lenient == that.lenient && firstDayOfWeek == that.firstDayOfWeek &&
*** 1922,1931 **** --- 2030,2040 ---- * Returns a hash code for this calendar. * * @return a hash code value for this object. * @since 1.2 */ + @Override public int hashCode() { // 'otheritems' represents the hash code for the previous versions. int otheritems = (lenient ? 1 : 0) | (firstDayOfWeek << 1) | (minimalDaysInFirstWeek << 4)
*** 1993,2002 **** --- 2102,2112 ---- * @exception IllegalArgumentException if the time value of the * specified <code>Calendar</code> object can't be obtained due to * any invalid calendar values. * @since 1.5 */ + @Override public int compareTo(Calendar anotherCalendar) { return compareTo(getMillisOf(anotherCalendar)); } /**
*** 2466,2477 **** Calendar work = (Calendar)this.clone(); work.setLenient(true); // if we're counting weeks, set the day of the week to Sunday. We know the // last week of a month or year will contain the first day of the week. ! if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH) work.set(DAY_OF_WEEK, firstDayOfWeek); // now try each value from getLeastMaximum() to getMaximum() one by one until // we get a value that normalizes to another value. The last value that // normalizes to itself is the actual maximum for the current date int result = fieldValue; --- 2576,2588 ---- Calendar work = (Calendar)this.clone(); work.setLenient(true); // if we're counting weeks, set the day of the week to Sunday. We know the // last week of a month or year will contain the first day of the week. ! if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH) { work.set(DAY_OF_WEEK, firstDayOfWeek); + } // now try each value from getLeastMaximum() to getMaximum() one by one until // we get a value that normalizes to another value. The last value that // normalizes to itself is the actual maximum for the current date int result = fieldValue;
*** 2492,2501 **** --- 2603,2613 ---- /** * Creates and returns a copy of this object. * * @return a copy of this object. */ + @Override public Object clone() { try { Calendar other = (Calendar) super.clone();
*** 2529,2539 **** * @param field the calendar field * @return the calendar field name * @exception IndexOutOfBoundsException if <code>field</code> is negative, * equal to or greater then <code>FIELD_COUNT</code>. */ ! static final String getFieldName(int field) { return FIELD_NAME[field]; } /** * Return a string representation of this calendar. This method --- 2641,2651 ---- * @param field the calendar field * @return the calendar field name * @exception IndexOutOfBoundsException if <code>field</code> is negative, * equal to or greater then <code>FIELD_COUNT</code>. */ ! static String getFieldName(int field) { return FIELD_NAME[field]; } /** * Return a string representation of this calendar. This method
*** 2541,2550 **** --- 2653,2663 ---- * format of the returned string may vary between implementations. * The returned string may be empty but may not be <code>null</code>. * * @return a string representation of this calendar. */ + @Override public String toString() { // NOTE: BuddhistCalendar.toString() interprets the string // produced by this method so that the Gregorian year number // is substituted by its B.E. year value. It relies on // "...,YEAR=<year>,..." or "...,YEAR=?,...".
*** 2565,2575 **** return buffer.toString(); } // =======================privates=============================== ! private static final void appendValue(StringBuilder sb, String item, boolean valid, long value) { sb.append(item).append('='); if (valid) { sb.append(value); } else { sb.append('?'); --- 2678,2688 ---- return buffer.toString(); } // =======================privates=============================== ! private static void appendValue(StringBuilder sb, String item, boolean valid, long value) { sb.append(item).append('='); if (valid) { sb.append(value); } else { sb.append('?');
*** 2585,2598 **** private void setWeekCountData(Locale desiredLocale) { /* try to get the Locale data from the cache */ int[] data = cachedLocaleData.get(desiredLocale); if (data == null) { /* cache miss */ ! ResourceBundle bundle = LocaleData.getCalendarData(desiredLocale); data = new int[2]; ! data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek")); ! data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek")); cachedLocaleData.putIfAbsent(desiredLocale, data); } firstDayOfWeek = data[0]; minimalDaysInFirstWeek = data[1]; } --- 2698,2713 ---- private void setWeekCountData(Locale desiredLocale) { /* try to get the Locale data from the cache */ int[] data = cachedLocaleData.get(desiredLocale); if (data == null) { /* cache miss */ ! LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(CalendarDataProvider.class, desiredLocale); ! CalendarDataProvider provider = adapter.getCalendarDataProvider(); data = new int[2]; ! data[0] = provider.getFirstDayOfWeek(desiredLocale); ! data[1] = provider.getMinimalDaysInFirstWeek(desiredLocale); ! assert data[0] != 0 && data[1] != 0; cachedLocaleData.putIfAbsent(desiredLocale, data); } firstDayOfWeek = data[0]; minimalDaysInFirstWeek = data[1]; }
*** 2612,2622 **** private int compareTo(long t) { long thisTime = getMillisOf(this); return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1; } ! private static final long getMillisOf(Calendar calendar) { if (calendar.isTimeSet) { return calendar.time; } Calendar cal = (Calendar) calendar.clone(); cal.setLenient(true); --- 2727,2737 ---- private int compareTo(long t) { long thisTime = getMillisOf(this); return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1; } ! private static long getMillisOf(Calendar calendar) { if (calendar.isTimeSet) { return calendar.time; } Calendar cal = (Calendar) calendar.clone(); cal.setLenient(true);
*** 2625,2635 **** /** * Adjusts the stamp[] values before nextStamp overflow. nextStamp * is set to the next stamp value upon the return. */ ! private final void adjustStamp() { int max = MINIMUM_USER_STAMP; int newStamp = MINIMUM_USER_STAMP; for (;;) { int min = Integer.MAX_VALUE; --- 2740,2750 ---- /** * Adjusts the stamp[] values before nextStamp overflow. nextStamp * is set to the next stamp value upon the return. */ ! private void adjustStamp() { int max = MINIMUM_USER_STAMP; int newStamp = MINIMUM_USER_STAMP; for (;;) { int min = Integer.MAX_VALUE;
*** 2750,2760 **** --- 2865,2877 ---- perms.add(perm); INSTANCE = new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); } + private CalendarAccessControlContext() { } + } /** * Reconstitutes this object from a stream (i.e., deserialize it). */ private void readObject(ObjectInputStream stream)
*** 2769,2794 **** // fields[], isSet[], isTimeSet, and areFieldsSet may not be // streamed out anymore. We expect 'time' to be correct. if (serialVersionOnStream >= 2) { isTimeSet = true; ! if (fields == null) fields = new int[FIELD_COUNT]; ! if (isSet == null) isSet = new boolean[FIELD_COUNT]; } else if (serialVersionOnStream >= 0) { ! for (int i=0; i<FIELD_COUNT; ++i) stamp[i] = isSet[i] ? COMPUTED : UNSET; } serialVersionOnStream = currentSerialVersion; // If there's a ZoneInfo object, use it for zone. ZoneInfo zi = null; try { zi = AccessController.doPrivileged( new PrivilegedExceptionAction<ZoneInfo>() { public ZoneInfo run() throws Exception { return (ZoneInfo) input.readObject(); } }, CalendarAccessControlContext.INSTANCE); --- 2886,2917 ---- // fields[], isSet[], isTimeSet, and areFieldsSet may not be // streamed out anymore. We expect 'time' to be correct. if (serialVersionOnStream >= 2) { isTimeSet = true; ! if (fields == null) { ! fields = new int[FIELD_COUNT]; } + if (isSet == null) { + isSet = new boolean[FIELD_COUNT]; + } + } else if (serialVersionOnStream >= 0) { ! for (int i=0; i<FIELD_COUNT; ++i) { stamp[i] = isSet[i] ? COMPUTED : UNSET; } + } serialVersionOnStream = currentSerialVersion; // If there's a ZoneInfo object, use it for zone. ZoneInfo zi = null; try { zi = AccessController.doPrivileged( new PrivilegedExceptionAction<ZoneInfo>() { + @Override public ZoneInfo run() throws Exception { return (ZoneInfo) input.readObject(); } }, CalendarAccessControlContext.INSTANCE);