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 { |
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. |