< prev index next >

src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java

Print this page
rev 47480 : [mq]: 8176841
   1 /*
   2  * Copyright (c) 2012, 2016, 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


 103 import java.util.AbstractMap.SimpleImmutableEntry;
 104 import java.util.ArrayList;
 105 import java.util.Arrays;
 106 import java.util.Collections;
 107 import java.util.Comparator;
 108 import java.util.HashMap;
 109 import java.util.HashSet;
 110 import java.util.Iterator;
 111 import java.util.LinkedHashMap;
 112 import java.util.List;
 113 import java.util.Locale;
 114 import java.util.Map;
 115 import java.util.Map.Entry;
 116 import java.util.Objects;
 117 import java.util.Set;
 118 import java.util.TimeZone;
 119 import java.util.concurrent.ConcurrentHashMap;
 120 import java.util.concurrent.ConcurrentMap;
 121 
 122 import sun.text.spi.JavaTimeDateTimePatternProvider;

 123 import sun.util.locale.provider.LocaleProviderAdapter;
 124 import sun.util.locale.provider.LocaleResources;
 125 import sun.util.locale.provider.TimeZoneNameUtility;
 126 
 127 /**
 128  * Builder to create date-time formatters.
 129  * <p>
 130  * This allows a {@code DateTimeFormatter} to be created.
 131  * All date-time formatters are created ultimately using this builder.
 132  * <p>
 133  * The basic elements of date-time can all be added:
 134  * <ul>
 135  * <li>Value - a numeric value</li>
 136  * <li>Fraction - a fractional value including the decimal place. Always use this when
 137  * outputting fractions to ensure that the fraction is parsed correctly</li>
 138  * <li>Text - the textual equivalent for the value</li>
 139  * <li>OffsetId/Offset - the {@linkplain ZoneOffset zone offset}</li>
 140  * <li>ZoneId - the {@linkplain ZoneId time-zone} id</li>
 141  * <li>ZoneText - the name of the time-zone</li>
 142  * <li>ChronologyId - the {@linkplain Chronology chronology} id</li>


 199      * The locale and chronology are used to lookup the locale specific format
 200      * for the requested dateStyle and/or timeStyle.
 201      *
 202      * @param dateStyle  the FormatStyle for the date, null for time-only pattern
 203      * @param timeStyle  the FormatStyle for the time, null for date-only pattern
 204      * @param chrono  the Chronology, non-null
 205      * @param locale  the locale, non-null
 206      * @return the locale and Chronology specific formatting pattern
 207      * @throws IllegalArgumentException if both dateStyle and timeStyle are null
 208      */
 209     public static String getLocalizedDateTimePattern(FormatStyle dateStyle, FormatStyle timeStyle,
 210             Chronology chrono, Locale locale) {
 211         Objects.requireNonNull(locale, "locale");
 212         Objects.requireNonNull(chrono, "chrono");
 213         if (dateStyle == null && timeStyle == null) {
 214             throw new IllegalArgumentException("Either dateStyle or timeStyle must be non-null");
 215         }
 216         LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(JavaTimeDateTimePatternProvider.class, locale);
 217         JavaTimeDateTimePatternProvider provider = adapter.getJavaTimeDateTimePatternProvider();
 218         String pattern = provider.getJavaTimeDateTimePattern(convertStyle(timeStyle),
 219                          convertStyle(dateStyle), chrono.getCalendarType(), locale);

 220         return pattern;
 221     }
 222 
 223     /**
 224      * Converts the given FormatStyle to the java.text.DateFormat style.
 225      *
 226      * @param style  the FormatStyle style
 227      * @return the int style, or -1 if style is null, indicating un-required
 228      */
 229     private static int convertStyle(FormatStyle style) {
 230         if (style == null) {
 231             return -1;
 232         }
 233         return style.ordinal();  // indices happen to align
 234     }
 235 
 236     /**
 237      * Constructs a new instance of the builder.
 238      */
 239     public DateTimeFormatterBuilder() {


2143         if (active.padNextWidth > 0) {
2144             if (pp != null) {
2145                 pp = new PadPrinterParserDecorator(pp, active.padNextWidth, active.padNextChar);
2146             }
2147             active.padNextWidth = 0;
2148             active.padNextChar = 0;
2149         }
2150         active.printerParsers.add(pp);
2151         active.valueParserIndex = -1;
2152         return active.printerParsers.size() - 1;
2153     }
2154 
2155     //-----------------------------------------------------------------------
2156     /**
2157      * Completes this builder by creating the {@code DateTimeFormatter}
2158      * using the default locale.
2159      * <p>
2160      * This will create a formatter with the {@linkplain Locale#getDefault(Locale.Category) default FORMAT locale}.
2161      * Numbers will be printed and parsed using the standard DecimalStyle.
2162      * The resolver style will be {@link ResolverStyle#SMART SMART}.






2163      * <p>
2164      * Calling this method will end any open optional sections by repeatedly
2165      * calling {@link #optionalEnd()} before creating the formatter.
2166      * <p>
2167      * This builder can still be used after creating the formatter if desired,
2168      * although the state may have been changed by calls to {@code optionalEnd}.
2169      *
2170      * @return the created formatter, not null
2171      */
2172     public DateTimeFormatter toFormatter() {
2173         return toFormatter(Locale.getDefault(Locale.Category.FORMAT));
2174     }
2175 
2176     /**
2177      * Completes this builder by creating the {@code DateTimeFormatter}
2178      * using the specified locale.
2179      * <p>
2180      * This will create a formatter with the specified locale.
2181      * Numbers will be printed and parsed using the standard DecimalStyle.
2182      * The resolver style will be {@link ResolverStyle#SMART SMART}.






2183      * <p>
2184      * Calling this method will end any open optional sections by repeatedly
2185      * calling {@link #optionalEnd()} before creating the formatter.
2186      * <p>
2187      * This builder can still be used after creating the formatter if desired,
2188      * although the state may have been changed by calls to {@code optionalEnd}.
2189      *
2190      * @param locale  the locale to use for formatting, not null
2191      * @return the created formatter, not null
2192      */
2193     public DateTimeFormatter toFormatter(Locale locale) {
2194         return toFormatter(locale, ResolverStyle.SMART, null);
2195     }
2196 
2197     /**
2198      * Completes this builder by creating the formatter.
2199      * This uses the default locale.
2200      *
2201      * @param resolverStyle  the resolver style to use, not null
2202      * @return the created formatter, not null
2203      */
2204     DateTimeFormatter toFormatter(ResolverStyle resolverStyle, Chronology chrono) {
2205         return toFormatter(Locale.getDefault(Locale.Category.FORMAT), resolverStyle, chrono);
2206     }
2207 
2208     /**
2209      * Completes this builder by creating the formatter.
2210      *
2211      * @param locale  the locale to use for formatting, not null
2212      * @param chrono  the chronology to use, may be null
2213      * @return the created formatter, not null
2214      */
2215     private DateTimeFormatter toFormatter(Locale locale, ResolverStyle resolverStyle, Chronology chrono) {
2216         Objects.requireNonNull(locale, "locale");
2217         while (active.parent != null) {
2218             optionalEnd();
2219         }
2220         CompositePrinterParser pp = new CompositePrinterParser(printerParsers, false);










2221         return new DateTimeFormatter(pp, locale, DecimalStyle.STANDARD,
2222                 resolverStyle, null, chrono, null);
2223     }
2224 
2225     //-----------------------------------------------------------------------
2226     /**
2227      * Strategy for formatting/parsing date-time information.
2228      * <p>
2229      * The printer may format any part, or the whole, of the input date-time object.
2230      * Typically, a complete format is constructed from a number of smaller
2231      * units, each outputting a single field.
2232      * <p>
2233      * The parser may parse any piece of text from the input, storing the result
2234      * in the context. Typically, each individual parser will just parse one
2235      * field, such as the day-of-month, storing the value in the context.
2236      * Once the parse is complete, the caller will then resolve the parsed values
2237      * to create the desired object, such as a {@code LocalDate}.
2238      * <p>
2239      * The parse position will be updated during the parse. Parsing will start at
2240      * the specified index and the return value specifies the new parse position
2241      * for the next parser. If an error occurs, the returned index will be negative
2242      * and will have the error position encoded using the complement operator.


   1 /*
   2  * Copyright (c) 2012, 2017, 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


 103 import java.util.AbstractMap.SimpleImmutableEntry;
 104 import java.util.ArrayList;
 105 import java.util.Arrays;
 106 import java.util.Collections;
 107 import java.util.Comparator;
 108 import java.util.HashMap;
 109 import java.util.HashSet;
 110 import java.util.Iterator;
 111 import java.util.LinkedHashMap;
 112 import java.util.List;
 113 import java.util.Locale;
 114 import java.util.Map;
 115 import java.util.Map.Entry;
 116 import java.util.Objects;
 117 import java.util.Set;
 118 import java.util.TimeZone;
 119 import java.util.concurrent.ConcurrentHashMap;
 120 import java.util.concurrent.ConcurrentMap;
 121 
 122 import sun.text.spi.JavaTimeDateTimePatternProvider;
 123 import sun.util.locale.provider.CalendarDataUtility;
 124 import sun.util.locale.provider.LocaleProviderAdapter;
 125 import sun.util.locale.provider.LocaleResources;
 126 import sun.util.locale.provider.TimeZoneNameUtility;
 127 
 128 /**
 129  * Builder to create date-time formatters.
 130  * <p>
 131  * This allows a {@code DateTimeFormatter} to be created.
 132  * All date-time formatters are created ultimately using this builder.
 133  * <p>
 134  * The basic elements of date-time can all be added:
 135  * <ul>
 136  * <li>Value - a numeric value</li>
 137  * <li>Fraction - a fractional value including the decimal place. Always use this when
 138  * outputting fractions to ensure that the fraction is parsed correctly</li>
 139  * <li>Text - the textual equivalent for the value</li>
 140  * <li>OffsetId/Offset - the {@linkplain ZoneOffset zone offset}</li>
 141  * <li>ZoneId - the {@linkplain ZoneId time-zone} id</li>
 142  * <li>ZoneText - the name of the time-zone</li>
 143  * <li>ChronologyId - the {@linkplain Chronology chronology} id</li>


 200      * The locale and chronology are used to lookup the locale specific format
 201      * for the requested dateStyle and/or timeStyle.
 202      *
 203      * @param dateStyle  the FormatStyle for the date, null for time-only pattern
 204      * @param timeStyle  the FormatStyle for the time, null for date-only pattern
 205      * @param chrono  the Chronology, non-null
 206      * @param locale  the locale, non-null
 207      * @return the locale and Chronology specific formatting pattern
 208      * @throws IllegalArgumentException if both dateStyle and timeStyle are null
 209      */
 210     public static String getLocalizedDateTimePattern(FormatStyle dateStyle, FormatStyle timeStyle,
 211             Chronology chrono, Locale locale) {
 212         Objects.requireNonNull(locale, "locale");
 213         Objects.requireNonNull(chrono, "chrono");
 214         if (dateStyle == null && timeStyle == null) {
 215             throw new IllegalArgumentException("Either dateStyle or timeStyle must be non-null");
 216         }
 217         LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(JavaTimeDateTimePatternProvider.class, locale);
 218         JavaTimeDateTimePatternProvider provider = adapter.getJavaTimeDateTimePatternProvider();
 219         String pattern = provider.getJavaTimeDateTimePattern(convertStyle(timeStyle),
 220                          convertStyle(dateStyle), chrono.getCalendarType(),
 221                          CalendarDataUtility.findRegionOverride(locale).orElse(locale));
 222         return pattern;
 223     }
 224 
 225     /**
 226      * Converts the given FormatStyle to the java.text.DateFormat style.
 227      *
 228      * @param style  the FormatStyle style
 229      * @return the int style, or -1 if style is null, indicating un-required
 230      */
 231     private static int convertStyle(FormatStyle style) {
 232         if (style == null) {
 233             return -1;
 234         }
 235         return style.ordinal();  // indices happen to align
 236     }
 237 
 238     /**
 239      * Constructs a new instance of the builder.
 240      */
 241     public DateTimeFormatterBuilder() {


2145         if (active.padNextWidth > 0) {
2146             if (pp != null) {
2147                 pp = new PadPrinterParserDecorator(pp, active.padNextWidth, active.padNextChar);
2148             }
2149             active.padNextWidth = 0;
2150             active.padNextChar = 0;
2151         }
2152         active.printerParsers.add(pp);
2153         active.valueParserIndex = -1;
2154         return active.printerParsers.size() - 1;
2155     }
2156 
2157     //-----------------------------------------------------------------------
2158     /**
2159      * Completes this builder by creating the {@code DateTimeFormatter}
2160      * using the default locale.
2161      * <p>
2162      * This will create a formatter with the {@linkplain Locale#getDefault(Locale.Category) default FORMAT locale}.
2163      * Numbers will be printed and parsed using the standard DecimalStyle.
2164      * The resolver style will be {@link ResolverStyle#SMART SMART}.
2165      * If the default locale contains "ca" (calendar), "rg" (region override)
2166      * and/or "tz" (timezone)
2167      * <a href="../../util/Locale.html#def_locale_extension">Unicode extensions</a>,
2168      * the chronology and/or the zone are overriden. If both "ca" and "rg" are
2169      * specified, the chronology from "ca" extension supersedes the implicit one
2170      * from "rg" extension.
2171      * <p>
2172      * Calling this method will end any open optional sections by repeatedly
2173      * calling {@link #optionalEnd()} before creating the formatter.
2174      * <p>
2175      * This builder can still be used after creating the formatter if desired,
2176      * although the state may have been changed by calls to {@code optionalEnd}.
2177      *
2178      * @return the created formatter, not null
2179      */
2180     public DateTimeFormatter toFormatter() {
2181         return toFormatter(Locale.getDefault(Locale.Category.FORMAT));
2182     }
2183 
2184     /**
2185      * Completes this builder by creating the {@code DateTimeFormatter}
2186      * using the specified locale.
2187      * <p>
2188      * This will create a formatter with the specified locale.
2189      * Numbers will be printed and parsed using the standard DecimalStyle.
2190      * The resolver style will be {@link ResolverStyle#SMART SMART}.
2191      * If the specified locale contains "ca" (calendar), "rg" (region override)
2192      * and/or "tz" (timezone)
2193      * <a href="../../util/Locale.html#def_locale_extension">Unicode extensions</a>,
2194      * the chronology and/or the zone are overriden. If both "ca" and "rg" are
2195      * specified, the chronology from "ca" extension supersedes the implicit one
2196      * from "rg" extension.
2197      * <p>
2198      * Calling this method will end any open optional sections by repeatedly
2199      * calling {@link #optionalEnd()} before creating the formatter.
2200      * <p>
2201      * This builder can still be used after creating the formatter if desired,
2202      * although the state may have been changed by calls to {@code optionalEnd}.
2203      *
2204      * @param locale  the locale to use for formatting, not null
2205      * @return the created formatter, not null
2206      */
2207     public DateTimeFormatter toFormatter(Locale locale) {
2208         return toFormatter(locale, ResolverStyle.SMART, null);
2209     }
2210 
2211     /**
2212      * Completes this builder by creating the formatter.
2213      * This uses the default locale.
2214      *
2215      * @param resolverStyle  the resolver style to use, not null
2216      * @return the created formatter, not null
2217      */
2218     DateTimeFormatter toFormatter(ResolverStyle resolverStyle, Chronology chrono) {
2219         return toFormatter(Locale.getDefault(Locale.Category.FORMAT), resolverStyle, chrono);
2220     }
2221 
2222     /**
2223      * Completes this builder by creating the formatter.
2224      *
2225      * @param locale  the locale to use for formatting, not null
2226      * @param chrono  the chronology to use, may be null
2227      * @return the created formatter, not null
2228      */
2229     private DateTimeFormatter toFormatter(Locale locale, ResolverStyle resolverStyle, Chronology chrono) {
2230         Objects.requireNonNull(locale, "locale");
2231         while (active.parent != null) {
2232             optionalEnd();
2233         }
2234         CompositePrinterParser pp = new CompositePrinterParser(printerParsers, false);
2235 
2236         // Check for chronology/timezone in locale object
2237         Chronology c = locale.getUnicodeLocaleType("ca") != null ?
2238                        Chronology.ofLocale(locale) : chrono;
2239         String tzType = locale.getUnicodeLocaleType("tz");
2240         ZoneId z  = tzType != null ?
2241                     TimeZoneNameUtility.convertLDMLShortID(tzType)
2242                         .map(ZoneId::of)
2243                         .orElse(null) :
2244                     null;
2245         return new DateTimeFormatter(pp, locale, DecimalStyle.STANDARD,
2246                 resolverStyle, null, c, z);
2247     }
2248 
2249     //-----------------------------------------------------------------------
2250     /**
2251      * Strategy for formatting/parsing date-time information.
2252      * <p>
2253      * The printer may format any part, or the whole, of the input date-time object.
2254      * Typically, a complete format is constructed from a number of smaller
2255      * units, each outputting a single field.
2256      * <p>
2257      * The parser may parse any piece of text from the input, storing the result
2258      * in the context. Typically, each individual parser will just parse one
2259      * field, such as the day-of-month, storing the value in the context.
2260      * Once the parse is complete, the caller will then resolve the parsed values
2261      * to create the desired object, such as a {@code LocalDate}.
2262      * <p>
2263      * The parse position will be updated during the parse. Parsing will start at
2264      * the specified index and the return value specifies the new parse position
2265      * for the next parser. If an error occurs, the returned index will be negative
2266      * and will have the error position encoded using the complement operator.


< prev index next >