jdk/src/share/classes/java/time/format/DateTimeFormatter.java
changeset 17474 8c100beabcc0
parent 16852 60207b2b4b42
child 18591 8202ea23bca7
equal deleted inserted replaced
17473:35cd9b3a98ff 17474:8c100beabcc0
    75 import java.text.FieldPosition;
    75 import java.text.FieldPosition;
    76 import java.text.Format;
    76 import java.text.Format;
    77 import java.text.ParseException;
    77 import java.text.ParseException;
    78 import java.text.ParsePosition;
    78 import java.text.ParsePosition;
    79 import java.time.DateTimeException;
    79 import java.time.DateTimeException;
       
    80 import java.time.Period;
    80 import java.time.ZoneId;
    81 import java.time.ZoneId;
    81 import java.time.ZoneOffset;
    82 import java.time.ZoneOffset;
    82 import java.time.chrono.Chronology;
    83 import java.time.chrono.Chronology;
    83 import java.time.chrono.IsoChronology;
    84 import java.time.chrono.IsoChronology;
    84 import java.time.format.DateTimeFormatterBuilder.CompositePrinterParser;
    85 import java.time.format.DateTimeFormatterBuilder.CompositePrinterParser;
   119  *  String text = date.toString(formatter);
   120  *  String text = date.toString(formatter);
   120  *  LocalDate date = LocalDate.parse(text, formatter);
   121  *  LocalDate date = LocalDate.parse(text, formatter);
   121  * </pre></blockquote>
   122  * </pre></blockquote>
   122  * <p>
   123  * <p>
   123  * In addition to the format, formatters can be created with desired Locale,
   124  * In addition to the format, formatters can be created with desired Locale,
   124  * Chronology, ZoneId, and formatting symbols.
   125  * Chronology, ZoneId, and DecimalStyle.
   125  * <p>
   126  * <p>
   126  * The {@link #withLocale withLocale} method returns a new formatter that
   127  * The {@link #withLocale withLocale} method returns a new formatter that
   127  * overrides the locale. The locale affects some aspects of formatting and
   128  * overrides the locale. The locale affects some aspects of formatting and
   128  * parsing. For example, the {@link #ofLocalizedDate ofLocalizedDate} provides a
   129  * parsing. For example, the {@link #ofLocalizedDate ofLocalizedDate} provides a
   129  * formatter that uses the locale specific date format.
   130  * formatter that uses the locale specific date format.
   136  * The {@link #withZone withZone} method returns a new formatter that overrides
   137  * The {@link #withZone withZone} method returns a new formatter that overrides
   137  * the zone. If overridden, the date-time value is converted to a ZonedDateTime
   138  * the zone. If overridden, the date-time value is converted to a ZonedDateTime
   138  * with the requested ZoneId before formatting. During parsing the ZoneId is
   139  * with the requested ZoneId before formatting. During parsing the ZoneId is
   139  * applied before the value is returned.
   140  * applied before the value is returned.
   140  * <p>
   141  * <p>
   141  * The {@link #withSymbols withSymbols} method returns a new formatter that
   142  * The {@link #withDecimalStyle withDecimalStyle} method returns a new formatter that
   142  * overrides the {@link DateTimeFormatSymbols}. The symbols are used for
   143  * overrides the {@link DecimalStyle}. The DecimalStyle symbols are used for
   143  * formatting and parsing.
   144  * formatting and parsing.
   144  * <p>
   145  * <p>
   145  * Some applications may need to use the older {@link Format java.text.Format}
   146  * Some applications may need to use the older {@link Format java.text.Format}
   146  * class for formatting. The {@link #toFormat()} method returns an
   147  * class for formatting. The {@link #toFormat()} method returns an
   147  * implementation of {@code java.text.Format}.
   148  * implementation of {@code java.text.Format}.
   415  * '[', ']', '{', '}', '#' and the single quote will be output directly.
   416  * '[', ']', '{', '}', '#' and the single quote will be output directly.
   416  * Despite this, it is recommended to use single quotes around all characters
   417  * Despite this, it is recommended to use single quotes around all characters
   417  * that you want to output directly to ensure that future changes do not break
   418  * that you want to output directly to ensure that future changes do not break
   418  * your application.
   419  * your application.
   419  *
   420  *
   420  * <h3>Specification for implementors</h3>
   421  * <h3 id="resolving">Resolving</h3>
       
   422  * Parsing is implemented as a two-phase operation.
       
   423  * First, the text is parsed using the layout defined by the formatter, producing
       
   424  * a {@code Map} of field to value, a {@code ZoneId} and a {@code Chronology}.
       
   425  * Second, the parsed data is <em>resolved</em>, by validating, combining and
       
   426  * simplifying the various fields into more useful ones.
       
   427  * <p>
       
   428  * Five parsing methods are supplied by this class.
       
   429  * Four of these perform both the parse and resolve phases.
       
   430  * The fifth method, {@link #parseUnresolved(CharSequence, ParsePosition)},
       
   431  * only performs the first phase, leaving the result unresolved.
       
   432  * As such, it is essentially a low-level operation.
       
   433  * <p>
       
   434  * The resolve phase is controlled by two parameters, set on this class.
       
   435  * <p>
       
   436  * The {@link ResolverStyle} is an enum that offers three different approaches,
       
   437  * strict, smart and lenient. The smart option is the default.
       
   438  * It can be set using {@link #withResolverStyle(ResolverStyle)}.
       
   439  * <p>
       
   440  * The {@link #withResolverFields(TemporalField...)} parameter allows the
       
   441  * set of fields that will be resolved to be filtered before resolving starts.
       
   442  * For example, if the formatter has parsed a year, month, day-of-month
       
   443  * and day-of-year, then there are two approaches to resolve a date:
       
   444  * (year + month + day-of-month) and (year + day-of-year).
       
   445  * The resolver fields allows one of the two approaches to be selected.
       
   446  * If no resolver fields are set then both approaches must result in the same date.
       
   447  * <p>
       
   448  * Resolving separate fields to form a complete date and time is a complex
       
   449  * process with behaviour distributed across a number of classes.
       
   450  * It follows these steps:
       
   451  * <ol>
       
   452  * <li>The chronology is determined.
       
   453  * The chronology of the result is either the chronology that was parsed,
       
   454  * or if no chronology was parsed, it is the chronology set on this class,
       
   455  * or if that is null, it is {@code IsoChronology}.
       
   456  * <li>The {@code ChronoField} date fields are resolved.
       
   457  * This is achieved using {@link Chronology#resolveDate(Map, ResolverStyle)}.
       
   458  * Documentation about field resolution is located in the implementation
       
   459  * of {@code Chronology}.
       
   460  * <li>The {@code ChronoField} time fields are resolved.
       
   461  * This is documented on {@link ChronoField} and is the same for all chronologies.
       
   462  * <li>Any fields that are not {@code ChronoField} are processed.
       
   463  * This is achieved using {@link TemporalField#resolve(TemporalAccessor, long, ResolverStyle)}.
       
   464  * Documentation about field resolution is located in the implementation
       
   465  * of {@code TemporalField}.
       
   466  * <li>The {@code ChronoField} date and time fields are re-resolved.
       
   467  * This allows fields in step four to produce {@code ChronoField} values
       
   468  * and have them be processed into dates and times.
       
   469  * <li>A {@code LocalTime} is formed if there is at least an hour-of-day available.
       
   470  * This involves providing default values for minute, second and fraction of second.
       
   471  * <li>Any remaining unresolved fields are cross-checked against any
       
   472  * date and/or time that was resolved. Thus, an earlier stage would resolve
       
   473  * (year + month + day-of-month) to a date, and this stage would check that
       
   474  * day-of-week was valid for the date.
       
   475  * <li>If an {@linkplain #parsedExcessDays() excess number of days}
       
   476  * was parsed then it is added to the date if a date is available.
       
   477  * </ol>
       
   478  *
       
   479  * @implSpec
   421  * This class is immutable and thread-safe.
   480  * This class is immutable and thread-safe.
   422  *
   481  *
   423  * @since 1.8
   482  * @since 1.8
   424  */
   483  */
   425 public final class DateTimeFormatter {
   484 public final class DateTimeFormatter {
   433      */
   492      */
   434     private final Locale locale;
   493     private final Locale locale;
   435     /**
   494     /**
   436      * The symbols to use for formatting, not null.
   495      * The symbols to use for formatting, not null.
   437      */
   496      */
   438     private final DateTimeFormatSymbols symbols;
   497     private final DecimalStyle decimalStyle;
   439     /**
   498     /**
   440      * The resolver style to use, not null.
   499      * The resolver style to use, not null.
   441      */
   500      */
   442     private final ResolverStyle resolverStyle;
   501     private final ResolverStyle resolverStyle;
   443     /**
   502     /**
  1038      * The ISO instant formatter that formats or parses an instant in UTC,
  1097      * The ISO instant formatter that formats or parses an instant in UTC,
  1039      * such as '2011-12-03T10:15:30Z'.
  1098      * such as '2011-12-03T10:15:30Z'.
  1040      * <p>
  1099      * <p>
  1041      * This returns an immutable formatter capable of formatting and parsing
  1100      * This returns an immutable formatter capable of formatting and parsing
  1042      * the ISO-8601 instant format.
  1101      * the ISO-8601 instant format.
       
  1102      * When formatting, the second-of-minute is always output.
       
  1103      * The nano-of-second outputs zero, three, six or nine digits digits as necessary.
       
  1104      * When parsing, time to at least the seconds field is required.
       
  1105      * Fractional seconds from zero to nine are parsed.
       
  1106      * The localized decimal style is not used.
  1043      * <p>
  1107      * <p>
  1044      * This is a special case formatter intended to allow a human readable form
  1108      * This is a special case formatter intended to allow a human readable form
  1045      * of an {@link java.time.Instant}. The {@code Instant} class is designed to
  1109      * of an {@link java.time.Instant}. The {@code Instant} class is designed to
  1046      * only represent a point in time and internally stores a value in nanoseconds
  1110      * only represent a point in time and internally stores a value in nanoseconds
  1047      * from a fixed epoch of 1970-01-01Z. As such, an {@code Instant} cannot be
  1111      * from a fixed epoch of 1970-01-01Z. As such, an {@code Instant} cannot be
  1199                 .appendLiteral(' ')
  1263                 .appendLiteral(' ')
  1200                 .appendOffset("+HHMM", "GMT")  // should handle UT/Z/EST/EDT/CST/CDT/MST/MDT/PST/MDT
  1264                 .appendOffset("+HHMM", "GMT")  // should handle UT/Z/EST/EDT/CST/CDT/MST/MDT/PST/MDT
  1201                 .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE);
  1265                 .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE);
  1202     }
  1266     }
  1203 
  1267 
       
  1268     //-----------------------------------------------------------------------
       
  1269     /**
       
  1270      * A query that provides access to the excess days that were parsed.
       
  1271      * <p>
       
  1272      * This returns a singleton {@linkplain TemporalQuery query} that provides
       
  1273      * access to additional information from the parse. The query always returns
       
  1274      * a non-null period, with a zero period returned instead of null.
       
  1275      * <p>
       
  1276      * There are two situations where this query may return a non-zero period.
       
  1277      * <p><ul>
       
  1278      * <li>If the {@code ResolverStyle} is {@code LENIENT} and a time is parsed
       
  1279      *  without a date, then the complete result of the parse consists of a
       
  1280      *  {@code LocalTime} and an excess {@code Period} in days.
       
  1281      * <p>
       
  1282      * <li>If the {@code ResolverStyle} is {@code SMART} and a time is parsed
       
  1283      *  without a date where the time is 24:00:00, then the complete result of
       
  1284      *  the parse consists of a {@code LocalTime} of 00:00:00 and an excess
       
  1285      *  {@code Period} of one day.
       
  1286      * </ul>
       
  1287      * <p>
       
  1288      * In both cases, if a complete {@code ChronoLocalDateTime} or {@code Instant}
       
  1289      * is parsed, then the excess days are added to the date part.
       
  1290      * As a result, this query will return a zero period.
       
  1291      * <p>
       
  1292      * The {@code SMART} behaviour handles the common "end of day" 24:00 value.
       
  1293      * Processing in {@code LENIENT} mode also produces the same result:
       
  1294      * <pre>
       
  1295      *  Text to parse        Parsed object                         Excess days
       
  1296      *  "2012-12-03T00:00"   LocalDateTime.of(2012, 12, 3, 0, 0)   ZERO
       
  1297      *  "2012-12-03T24:00"   LocalDateTime.of(2012, 12, 4, 0, 0)   ZERO
       
  1298      *  "00:00"              LocalTime.of(0, 0)                    ZERO
       
  1299      *  "24:00"              LocalTime.of(0, 0)                    Period.ofDays(1)
       
  1300      * </pre>
       
  1301      * The query can be used as follows:
       
  1302      * <pre>
       
  1303      *  TemporalAccessor parsed = formatter.parse(str);
       
  1304      *  LocalTime time = parsed.query(LocalTime::from);
       
  1305      *  Period extraDays = parsed.query(DateTimeFormatter.parsedExcessDays());
       
  1306      * </pre>
       
  1307      */
       
  1308     public static final TemporalQuery<Period> parsedExcessDays() {
       
  1309         return PARSED_EXCESS_DAYS;
       
  1310     }
       
  1311     private static final TemporalQuery<Period> PARSED_EXCESS_DAYS = t -> {
       
  1312         if (t instanceof Parsed) {
       
  1313             return ((Parsed) t).excessDays;
       
  1314         } else {
       
  1315             return Period.ZERO;
       
  1316         }
       
  1317     };
       
  1318 
       
  1319     /**
       
  1320      * A query that provides access to whether a leap-second was parsed.
       
  1321      * <p>
       
  1322      * This returns a singleton {@linkplain TemporalQuery query} that provides
       
  1323      * access to additional information from the parse. The query always returns
       
  1324      * a non-null boolean, true if parsing saw a leap-second, false if not.
       
  1325      * <p>
       
  1326      * Instant parsing handles the special "leap second" time of '23:59:60'.
       
  1327      * Leap seconds occur at '23:59:60' in the UTC time-zone, but at other
       
  1328      * local times in different time-zones. To avoid this potential ambiguity,
       
  1329      * the handling of leap-seconds is limited to
       
  1330      * {@link DateTimeFormatterBuilder#appendInstant()}, as that method
       
  1331      * always parses the instant with the UTC zone offset.
       
  1332      * <p>
       
  1333      * If the time '23:59:60' is received, then a simple conversion is applied,
       
  1334      * replacing the second-of-minute of 60 with 59. This query can be used
       
  1335      * on the parse result to determine if the leap-second adjustment was made.
       
  1336      * The query will return one second of excess if it did adjust to remove
       
  1337      * the leap-second, and zero if not. Note that applying a leap-second
       
  1338      * smoothing mechanism, such as UTC-SLS, is the responsibility of the
       
  1339      * application, as follows:
       
  1340      * <pre>
       
  1341      *  TemporalAccessor parsed = formatter.parse(str);
       
  1342      *  Instant instant = parsed.query(Instant::from);
       
  1343      *  if (parsed.query(DateTimeFormatter.parsedLeapSecond())) {
       
  1344      *    // validate leap-second is correct and apply correct smoothing
       
  1345      *  }
       
  1346      * </pre>
       
  1347      */
       
  1348     public static final TemporalQuery<Boolean> parsedLeapSecond() {
       
  1349         return PARSED_LEAP_SECOND;
       
  1350     }
       
  1351     private static final TemporalQuery<Boolean> PARSED_LEAP_SECOND = t -> {
       
  1352         if (t instanceof Parsed) {
       
  1353             return ((Parsed) t).leapSecond;
       
  1354         } else {
       
  1355             return Boolean.FALSE;
       
  1356         }
       
  1357     };
       
  1358 
       
  1359     //-----------------------------------------------------------------------
  1204     /**
  1360     /**
  1205      * Constructor.
  1361      * Constructor.
  1206      *
  1362      *
  1207      * @param printerParser  the printer/parser to use, not null
  1363      * @param printerParser  the printer/parser to use, not null
  1208      * @param locale  the locale to use, not null
  1364      * @param locale  the locale to use, not null
  1209      * @param symbols  the symbols to use, not null
  1365      * @param decimalStyle  the DecimalStyle to use, not null
  1210      * @param resolverStyle  the resolver style to use, not null
  1366      * @param resolverStyle  the resolver style to use, not null
  1211      * @param resolverFields  the fields to use during resolving, null for all fields
  1367      * @param resolverFields  the fields to use during resolving, null for all fields
  1212      * @param chrono  the chronology to use, null for no override
  1368      * @param chrono  the chronology to use, null for no override
  1213      * @param zone  the zone to use, null for no override
  1369      * @param zone  the zone to use, null for no override
  1214      */
  1370      */
  1215     DateTimeFormatter(CompositePrinterParser printerParser,
  1371     DateTimeFormatter(CompositePrinterParser printerParser,
  1216             Locale locale, DateTimeFormatSymbols symbols,
  1372             Locale locale, DecimalStyle decimalStyle,
  1217             ResolverStyle resolverStyle, Set<TemporalField> resolverFields,
  1373             ResolverStyle resolverStyle, Set<TemporalField> resolverFields,
  1218             Chronology chrono, ZoneId zone) {
  1374             Chronology chrono, ZoneId zone) {
  1219         this.printerParser = Objects.requireNonNull(printerParser, "printerParser");
  1375         this.printerParser = Objects.requireNonNull(printerParser, "printerParser");
  1220         this.resolverFields = resolverFields;
  1376         this.resolverFields = resolverFields;
  1221         this.locale = Objects.requireNonNull(locale, "locale");
  1377         this.locale = Objects.requireNonNull(locale, "locale");
  1222         this.symbols = Objects.requireNonNull(symbols, "symbols");
  1378         this.decimalStyle = Objects.requireNonNull(decimalStyle, "decimalStyle");
  1223         this.resolverStyle = Objects.requireNonNull(resolverStyle, "resolverStyle");
  1379         this.resolverStyle = Objects.requireNonNull(resolverStyle, "resolverStyle");
  1224         this.chrono = chrono;
  1380         this.chrono = chrono;
  1225         this.zone = zone;
  1381         this.zone = zone;
  1226     }
  1382     }
  1227 
  1383 
  1251      */
  1407      */
  1252     public DateTimeFormatter withLocale(Locale locale) {
  1408     public DateTimeFormatter withLocale(Locale locale) {
  1253         if (this.locale.equals(locale)) {
  1409         if (this.locale.equals(locale)) {
  1254             return this;
  1410             return this;
  1255         }
  1411         }
  1256         return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
  1412         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
  1257     }
  1413     }
  1258 
  1414 
  1259     //-----------------------------------------------------------------------
  1415     //-----------------------------------------------------------------------
  1260     /**
  1416     /**
  1261      * Gets the set of symbols to be used during formatting.
  1417      * Gets the DecimalStyle to be used during formatting.
  1262      *
  1418      *
  1263      * @return the locale of this formatter, not null
  1419      * @return the locale of this formatter, not null
  1264      */
  1420      */
  1265     public DateTimeFormatSymbols getSymbols() {
  1421     public DecimalStyle getDecimalStyle() {
  1266         return symbols;
  1422         return decimalStyle;
  1267     }
  1423     }
  1268 
  1424 
  1269     /**
  1425     /**
  1270      * Returns a copy of this formatter with a new set of symbols.
  1426      * Returns a copy of this formatter with a new DecimalStyle.
  1271      * <p>
  1427      * <p>
  1272      * This instance is immutable and unaffected by this method call.
  1428      * This instance is immutable and unaffected by this method call.
  1273      *
  1429      *
  1274      * @param symbols  the new symbols, not null
  1430      * @param decimalStyle  the new DecimalStyle, not null
  1275      * @return a formatter based on this formatter with the requested symbols, not null
  1431      * @return a formatter based on this formatter with the requested DecimalStyle, not null
  1276      */
  1432      */
  1277     public DateTimeFormatter withSymbols(DateTimeFormatSymbols symbols) {
  1433     public DateTimeFormatter withDecimalStyle(DecimalStyle decimalStyle) {
  1278         if (this.symbols.equals(symbols)) {
  1434         if (this.decimalStyle.equals(decimalStyle)) {
  1279             return this;
  1435             return this;
  1280         }
  1436         }
  1281         return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
  1437         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
  1282     }
  1438     }
  1283 
  1439 
  1284     //-----------------------------------------------------------------------
  1440     //-----------------------------------------------------------------------
  1285     /**
  1441     /**
  1286      * Gets the overriding chronology to be used during formatting.
  1442      * Gets the overriding chronology to be used during formatting.
  1330      */
  1486      */
  1331     public DateTimeFormatter withChronology(Chronology chrono) {
  1487     public DateTimeFormatter withChronology(Chronology chrono) {
  1332         if (Objects.equals(this.chrono, chrono)) {
  1488         if (Objects.equals(this.chrono, chrono)) {
  1333             return this;
  1489             return this;
  1334         }
  1490         }
  1335         return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
  1491         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
  1336     }
  1492     }
  1337 
  1493 
  1338     //-----------------------------------------------------------------------
  1494     //-----------------------------------------------------------------------
  1339     /**
  1495     /**
  1340      * Gets the overriding zone to be used during formatting.
  1496      * Gets the overriding zone to be used during formatting.
  1387      */
  1543      */
  1388     public DateTimeFormatter withZone(ZoneId zone) {
  1544     public DateTimeFormatter withZone(ZoneId zone) {
  1389         if (Objects.equals(this.zone, zone)) {
  1545         if (Objects.equals(this.zone, zone)) {
  1390             return this;
  1546             return this;
  1391         }
  1547         }
  1392         return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
  1548         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
  1393     }
  1549     }
  1394 
  1550 
  1395     //-----------------------------------------------------------------------
  1551     //-----------------------------------------------------------------------
  1396     /**
  1552     /**
  1397      * Gets the resolver style to use during parsing.
  1553      * Gets the resolver style to use during parsing.
  1429     public DateTimeFormatter withResolverStyle(ResolverStyle resolverStyle) {
  1585     public DateTimeFormatter withResolverStyle(ResolverStyle resolverStyle) {
  1430         Objects.requireNonNull(resolverStyle, "resolverStyle");
  1586         Objects.requireNonNull(resolverStyle, "resolverStyle");
  1431         if (Objects.equals(this.resolverStyle, resolverStyle)) {
  1587         if (Objects.equals(this.resolverStyle, resolverStyle)) {
  1432             return this;
  1588             return this;
  1433         }
  1589         }
  1434         return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
  1590         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
  1435     }
  1591     }
  1436 
  1592 
  1437     //-----------------------------------------------------------------------
  1593     //-----------------------------------------------------------------------
  1438     /**
  1594     /**
  1439      * Gets the resolver fields to use during parsing.
  1595      * Gets the resolver fields to use during parsing.
  1493         Set<TemporalField> fields = new HashSet<>(Arrays.asList(resolverFields));
  1649         Set<TemporalField> fields = new HashSet<>(Arrays.asList(resolverFields));
  1494         if (Objects.equals(this.resolverFields, fields)) {
  1650         if (Objects.equals(this.resolverFields, fields)) {
  1495             return this;
  1651             return this;
  1496         }
  1652         }
  1497         fields = Collections.unmodifiableSet(fields);
  1653         fields = Collections.unmodifiableSet(fields);
  1498         return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, fields, chrono, zone);
  1654         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, fields, chrono, zone);
  1499     }
  1655     }
  1500 
  1656 
  1501     /**
  1657     /**
  1502      * Returns a copy of this formatter with a new set of resolver fields.
  1658      * Returns a copy of this formatter with a new set of resolver fields.
  1503      * <p>
  1659      * <p>
  1541         Objects.requireNonNull(resolverFields, "resolverFields");
  1697         Objects.requireNonNull(resolverFields, "resolverFields");
  1542         if (Objects.equals(this.resolverFields, resolverFields)) {
  1698         if (Objects.equals(this.resolverFields, resolverFields)) {
  1543             return this;
  1699             return this;
  1544         }
  1700         }
  1545         resolverFields = Collections.unmodifiableSet(new HashSet<>(resolverFields));
  1701         resolverFields = Collections.unmodifiableSet(new HashSet<>(resolverFields));
  1546         return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone);
  1702         return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
  1547     }
  1703     }
  1548 
  1704 
  1549     //-----------------------------------------------------------------------
  1705     //-----------------------------------------------------------------------
  1550     /**
  1706     /**
  1551      * Formats a date-time object using this formatter.
  1707      * Formats a date-time object using this formatter.