< prev index next >

src/java.base/share/classes/java/text/SimpleDateFormat.java

Print this page
rev 53363 : [mq]: 8216969
   1 /*
   2  * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 516      * The symbols used by this formatter for week names, month names,
 517      * etc.  May not be null.
 518      * @serial
 519      * @see java.text.DateFormatSymbols
 520      */
 521     private DateFormatSymbols formatData;
 522 
 523     /**
 524      * We map dates with two-digit years into the century starting at
 525      * <code>defaultCenturyStart</code>, which may be any date.  May
 526      * not be null.
 527      * @serial
 528      * @since 1.1.4
 529      */
 530     private Date defaultCenturyStart;
 531 
 532     private transient int defaultCenturyStartYear;
 533 
 534     private static final int MILLIS_PER_MINUTE = 60 * 1000;
 535 


 536     // For time zones that have no names, use strings GMT+minutes and
 537     // GMT-minutes. For instance, in France the time zone is GMT+60.
 538     private static final String GMT = "GMT";
 539 
 540     /**
 541      * Cache NumberFormat instances with Locale key.
 542      */
 543     private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
 544         = new ConcurrentHashMap<>(3);
 545 
 546     /**
 547      * The Locale used to instantiate this
 548      * <code>SimpleDateFormat</code>. The value may be null if this object
 549      * has been created by an older <code>SimpleDateFormat</code> and
 550      * deserialized.
 551      *
 552      * @serial
 553      * @since 1.6
 554      */
 555     private Locale locale;


1172                 current = "";
1173             }
1174             break;
1175 
1176         case PATTERN_WEEK_YEAR: // 'Y'
1177         case PATTERN_YEAR:      // 'y'
1178             if (calendar instanceof GregorianCalendar) {
1179                 if (count != 2) {
1180                     zeroPaddingNumber(value, count, maxIntCount, buffer);
1181                 } else {
1182                     zeroPaddingNumber(value, 2, 2, buffer);
1183                 } // clip 1996 to 96
1184             } else {
1185                 if (current == null) {
1186                     zeroPaddingNumber(value, style == Calendar.LONG ? 1 : count,
1187                                       maxIntCount, buffer);
1188                 }
1189             }
1190             break;
1191 
1192         case PATTERN_MONTH:            // 'M' (context seinsive)
1193             if (useDateFormatSymbols) {
1194                 String[] months;
1195                 if (count >= 4) {
1196                     months = formatData.getMonths();
1197                     current = months[value];
1198                 } else if (count == 3) {
1199                     months = formatData.getShortMonths();
1200                     current = months[value];
1201                 }
1202             } else {
1203                 if (count < 3) {
1204                     current = null;
1205                 } else if (forceStandaloneForm) {
1206                     current = calendar.getDisplayName(field, style | 0x8000, locale);
1207                     if (current == null) {
1208                         current = calendar.getDisplayName(field, style, locale);
1209                     }
1210                 }
1211             }
1212             if (current == null) {
1213                 zeroPaddingNumber(value+1, count, maxIntCount, buffer);
1214             }
1215             break;
1216 
1217         case PATTERN_MONTH_STANDALONE: // 'L'
1218             assert current == null;
1219             if (locale == null) {
1220                 String[] months;
1221                 if (count >= 4) {
1222                     months = formatData.getMonths();
1223                     current = months[value];
1224                 } else if (count == 3) {
1225                     months = formatData.getShortMonths();
1226                     current = months[value];
1227                 }
1228             } else {
1229                 if (count >= 3) {
1230                     current = calendar.getDisplayName(field, style | 0x8000, locale);
1231                 }
1232             }
1233             if (current == null) {
1234                 zeroPaddingNumber(value+1, count, maxIntCount, buffer);
1235             }
1236             break;
1237 
1238         case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
1239             if (current == null) {
1240                 if (value == 0) {
1241                     zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1,
1242                                       count, maxIntCount, buffer);
1243                 } else {
1244                     zeroPaddingNumber(value, count, maxIntCount, buffer);
1245                 }
1246             }
1247             break;
1248 
1249         case PATTERN_DAY_OF_WEEK: // 'E'
1250             if (useDateFormatSymbols) {


2016                     // [We computed 'value' above.]
2017                     calb.set(Calendar.MONTH, value - 1);
2018                     return pos.index;
2019                 }
2020 
2021                 if (useDateFormatSymbols) {
2022                     // count >= 3 // i.e., MMM or MMMM
2023                     // Want to be able to parse both short and long forms.
2024                     // Try count == 4 first:
2025                     int newStart;
2026                     if ((newStart = matchString(text, start, Calendar.MONTH,
2027                                                 formatData.getMonths(), calb)) > 0) {
2028                         return newStart;
2029                     }
2030                     // count == 4 failed, now try count == 3
2031                     if ((index = matchString(text, start, Calendar.MONTH,
2032                                              formatData.getShortMonths(), calb)) > 0) {
2033                         return index;
2034                     }
2035                 } else {
2036                     Map<String, Integer> map = getDisplayNamesMap(field, locale);
2037                     if ((index = matchString(text, start, field, map, calb)) > 0) {
2038                         return index;
2039                     }
2040                 }
2041                 break parsing;
2042 
2043             case PATTERN_MONTH_STANDALONE: // 'L'
2044                 if (count <= 2) {
2045                     // Don't want to parse the month if it is a string
2046                     // while pattern uses numeric style: L or LL
2047                     //[we computed 'value' above.]
2048                     calb.set(Calendar.MONTH, value - 1);
2049                     return pos.index;
2050                 }
2051                 Map<String, Integer> maps = getDisplayNamesMap(field, locale);
2052                 if ((index = matchString(text, start, field, maps, calb)) > 0) {
2053                     return index;
2054                 }
2055                 break parsing;
2056 


2432         SimpleDateFormat that = (SimpleDateFormat) obj;
2433         return (pattern.equals(that.pattern)
2434                 && formatData.equals(that.formatData));
2435     }
2436 
2437     private static final int[] REST_OF_STYLES = {
2438         Calendar.SHORT_STANDALONE, Calendar.LONG_FORMAT, Calendar.LONG_STANDALONE,
2439     };
2440     private Map<String, Integer> getDisplayNamesMap(int field, Locale locale) {
2441         Map<String, Integer> map = calendar.getDisplayNames(field, Calendar.SHORT_FORMAT, locale);
2442         // Get all SHORT and LONG styles (avoid NARROW styles).
2443         for (int style : REST_OF_STYLES) {
2444             Map<String, Integer> m = calendar.getDisplayNames(field, style, locale);
2445             if (m != null) {
2446                 map.putAll(m);
2447             }
2448         }
2449         return map;
2450     }
2451 













2452     /**
2453      * After reading an object from the input stream, the format
2454      * pattern in the object is verified.
2455      *
2456      * @exception InvalidObjectException if the pattern is invalid
2457      */
2458     private void readObject(ObjectInputStream stream)
2459                          throws IOException, ClassNotFoundException {
2460         stream.defaultReadObject();
2461 
2462         try {
2463             compiledPattern = compile(pattern);
2464         } catch (Exception e) {
2465             throw new InvalidObjectException("invalid pattern");
2466         }
2467 
2468         if (serialVersionOnStream < 1) {
2469             // didn't have defaultCenturyStart field
2470             initializeDefaultCentury();
2471         }


   1 /*
   2  * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 516      * The symbols used by this formatter for week names, month names,
 517      * etc.  May not be null.
 518      * @serial
 519      * @see java.text.DateFormatSymbols
 520      */
 521     private DateFormatSymbols formatData;
 522 
 523     /**
 524      * We map dates with two-digit years into the century starting at
 525      * <code>defaultCenturyStart</code>, which may be any date.  May
 526      * not be null.
 527      * @serial
 528      * @since 1.1.4
 529      */
 530     private Date defaultCenturyStart;
 531 
 532     private transient int defaultCenturyStartYear;
 533 
 534     private static final int MILLIS_PER_MINUTE = 60 * 1000;
 535 
 536     private static final int STANDALONE_MASK = 0x8000; // Calendar.STANDALONE_MASK
 537 
 538     // For time zones that have no names, use strings GMT+minutes and
 539     // GMT-minutes. For instance, in France the time zone is GMT+60.
 540     private static final String GMT = "GMT";
 541 
 542     /**
 543      * Cache NumberFormat instances with Locale key.
 544      */
 545     private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
 546         = new ConcurrentHashMap<>(3);
 547 
 548     /**
 549      * The Locale used to instantiate this
 550      * <code>SimpleDateFormat</code>. The value may be null if this object
 551      * has been created by an older <code>SimpleDateFormat</code> and
 552      * deserialized.
 553      *
 554      * @serial
 555      * @since 1.6
 556      */
 557     private Locale locale;


1174                 current = "";
1175             }
1176             break;
1177 
1178         case PATTERN_WEEK_YEAR: // 'Y'
1179         case PATTERN_YEAR:      // 'y'
1180             if (calendar instanceof GregorianCalendar) {
1181                 if (count != 2) {
1182                     zeroPaddingNumber(value, count, maxIntCount, buffer);
1183                 } else {
1184                     zeroPaddingNumber(value, 2, 2, buffer);
1185                 } // clip 1996 to 96
1186             } else {
1187                 if (current == null) {
1188                     zeroPaddingNumber(value, style == Calendar.LONG ? 1 : count,
1189                                       maxIntCount, buffer);
1190                 }
1191             }
1192             break;
1193 
1194         case PATTERN_MONTH:            // 'M' (context sensitive)
1195             if (useDateFormatSymbols) {
1196                 String[] months;
1197                 if (count >= 4) {
1198                     months = formatData.getMonths();
1199                     current = months[value];
1200                 } else if (count == 3) {
1201                     months = formatData.getShortMonths();
1202                     current = months[value];
1203                 }
1204             } else {
1205                 if (count < 3) {
1206                     current = null;
1207                 } else if (forceStandaloneForm) {
1208                     current = calendar.getDisplayName(field, style | STANDALONE_MASK, locale);
1209                     if (current == null) {
1210                         current = calendar.getDisplayName(field, style, locale);
1211                     }
1212                 }
1213             }
1214             if (current == null) {
1215                 zeroPaddingNumber(value+1, count, maxIntCount, buffer);
1216             }
1217             break;
1218 
1219         case PATTERN_MONTH_STANDALONE: // 'L'
1220             assert current == null;
1221             if (locale == null) {
1222                 String[] months;
1223                 if (count >= 4) {
1224                     months = formatData.getMonths();
1225                     current = months[value];
1226                 } else if (count == 3) {
1227                     months = formatData.getShortMonths();
1228                     current = months[value];
1229                 }
1230             } else {
1231                 if (count >= 3) {
1232                     current = calendar.getDisplayName(field, style | STANDALONE_MASK, locale);
1233                 }
1234             }
1235             if (current == null) {
1236                 zeroPaddingNumber(value+1, count, maxIntCount, buffer);
1237             }
1238             break;
1239 
1240         case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
1241             if (current == null) {
1242                 if (value == 0) {
1243                     zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1,
1244                                       count, maxIntCount, buffer);
1245                 } else {
1246                     zeroPaddingNumber(value, count, maxIntCount, buffer);
1247                 }
1248             }
1249             break;
1250 
1251         case PATTERN_DAY_OF_WEEK: // 'E'
1252             if (useDateFormatSymbols) {


2018                     // [We computed 'value' above.]
2019                     calb.set(Calendar.MONTH, value - 1);
2020                     return pos.index;
2021                 }
2022 
2023                 if (useDateFormatSymbols) {
2024                     // count >= 3 // i.e., MMM or MMMM
2025                     // Want to be able to parse both short and long forms.
2026                     // Try count == 4 first:
2027                     int newStart;
2028                     if ((newStart = matchString(text, start, Calendar.MONTH,
2029                                                 formatData.getMonths(), calb)) > 0) {
2030                         return newStart;
2031                     }
2032                     // count == 4 failed, now try count == 3
2033                     if ((index = matchString(text, start, Calendar.MONTH,
2034                                              formatData.getShortMonths(), calb)) > 0) {
2035                         return index;
2036                     }
2037                 } else {
2038                     Map<String, Integer> map = getDisplayContextNamesMap(field, locale);
2039                     if ((index = matchString(text, start, field, map, calb)) > 0) {
2040                         return index;
2041                     }
2042                 }
2043                 break parsing;
2044 
2045             case PATTERN_MONTH_STANDALONE: // 'L'
2046                 if (count <= 2) {
2047                     // Don't want to parse the month if it is a string
2048                     // while pattern uses numeric style: L or LL
2049                     //[we computed 'value' above.]
2050                     calb.set(Calendar.MONTH, value - 1);
2051                     return pos.index;
2052                 }
2053                 Map<String, Integer> maps = getDisplayNamesMap(field, locale);
2054                 if ((index = matchString(text, start, field, maps, calb)) > 0) {
2055                     return index;
2056                 }
2057                 break parsing;
2058 


2434         SimpleDateFormat that = (SimpleDateFormat) obj;
2435         return (pattern.equals(that.pattern)
2436                 && formatData.equals(that.formatData));
2437     }
2438 
2439     private static final int[] REST_OF_STYLES = {
2440         Calendar.SHORT_STANDALONE, Calendar.LONG_FORMAT, Calendar.LONG_STANDALONE,
2441     };
2442     private Map<String, Integer> getDisplayNamesMap(int field, Locale locale) {
2443         Map<String, Integer> map = calendar.getDisplayNames(field, Calendar.SHORT_FORMAT, locale);
2444         // Get all SHORT and LONG styles (avoid NARROW styles).
2445         for (int style : REST_OF_STYLES) {
2446             Map<String, Integer> m = calendar.getDisplayNames(field, style, locale);
2447             if (m != null) {
2448                 map.putAll(m);
2449             }
2450         }
2451         return map;
2452     }
2453 
2454     // for 'M' pattern only
2455     private Map<String, Integer> getDisplayContextNamesMap(int field, Locale locale) {
2456         Map<String, Integer> map = calendar.getDisplayNames(field,
2457             Calendar.SHORT_FORMAT | (forceStandaloneForm ? STANDALONE_MASK : 0), locale);
2458         // Get LONG styles
2459         Map<String, Integer> m = calendar.getDisplayNames(field,
2460             Calendar.LONG_FORMAT | (forceStandaloneForm ? STANDALONE_MASK : 0), locale);
2461         if (m != null) {
2462             map.putAll(m);
2463         }
2464         return map;
2465     }
2466 
2467     /**
2468      * After reading an object from the input stream, the format
2469      * pattern in the object is verified.
2470      *
2471      * @exception InvalidObjectException if the pattern is invalid
2472      */
2473     private void readObject(ObjectInputStream stream)
2474                          throws IOException, ClassNotFoundException {
2475         stream.defaultReadObject();
2476 
2477         try {
2478             compiledPattern = compile(pattern);
2479         } catch (Exception e) {
2480             throw new InvalidObjectException("invalid pattern");
2481         }
2482 
2483         if (serialVersionOnStream < 1) {
2484             // didn't have defaultCenturyStart field
2485             initializeDefaultCentury();
2486         }


< prev index next >