1 /* 2 * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * * Neither the name of JSR-310 nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package org.threeten.bp.format; 33 34 import static org.threeten.bp.temporal.ChronoField.DAY_OF_MONTH; 35 import static org.threeten.bp.temporal.ChronoField.DAY_OF_WEEK; 36 import static org.threeten.bp.temporal.ChronoField.DAY_OF_YEAR; 37 import static org.threeten.bp.temporal.ChronoField.HOUR_OF_DAY; 38 import static org.threeten.bp.temporal.ChronoField.MINUTE_OF_HOUR; 39 import static org.threeten.bp.temporal.ChronoField.MONTH_OF_YEAR; 40 import static org.threeten.bp.temporal.ChronoField.NANO_OF_SECOND; 41 import static org.threeten.bp.temporal.ChronoField.SECOND_OF_MINUTE; 42 import static org.threeten.bp.temporal.ChronoField.YEAR; 43 44 import java.io.IOException; 45 import java.text.FieldPosition; 46 import java.text.Format; 47 import java.text.ParseException; 48 import java.text.ParsePosition; 49 import java.util.Arrays; 50 import java.util.Collections; 51 import java.util.HashMap; 52 import java.util.HashSet; 53 import java.util.Locale; 54 import java.util.Map; 55 import java.util.Set; 56 57 import org.threeten.bp.DateTimeException; 58 import org.threeten.bp.Period; 59 import org.threeten.bp.ZoneId; 60 import org.threeten.bp.ZoneOffset; 61 import org.threeten.bp.chrono.Chronology; 62 import org.threeten.bp.chrono.IsoChronology; 63 import org.threeten.bp.format.DateTimeFormatterBuilder.CompositePrinterParser; 64 import org.threeten.bp.format.DateTimeParseContext.Parsed; 65 import org.threeten.bp.jdk8.Jdk8Methods; 66 import org.threeten.bp.temporal.ChronoField; 67 import org.threeten.bp.temporal.IsoFields; 68 import org.threeten.bp.temporal.TemporalAccessor; 69 import org.threeten.bp.temporal.TemporalField; 70 import org.threeten.bp.temporal.TemporalQuery; 71 72 /** 73 * Formatter for printing and parsing date-time objects. 74 * <p> 75 * This class provides the main application entry point for printing and parsing. 76 * Common instances of {@code DateTimeFormatter} are provided: 77 * <p><ul> 78 * <li>Using pattern letters, such as {@code yyyy-MMM-dd} 79 * <li>Using localized styles, such as {@code long} or {@code medium} 80 * <li>Using predefined constants, such as {@link #ISO_LOCAL_DATE} 81 * </ul><p> 82 * <p> 83 * For more complex formatters, a {@link DateTimeFormatterBuilder builder} is provided. 84 * <p> 85 * In most cases, it is not necessary to use this class directly when formatting. 86 * The main date-time classes provide two methods - one for formatting, 87 * {@code format(DateTimeFormatter formatter)}, and one for parsing, 88 * For example: 89 * <pre> 90 * String text = date.format(formatter); 91 * LocalDate date = LocalDate.parse(text, formatter); 92 * </pre> 93 * Some aspects of printing and parsing are dependent on the locale. 94 * The locale can be changed using the {@link #withLocale(Locale)} method 95 * which returns a new formatter in the requested locale. 96 * <p> 97 * Some applications may need to use the older {@link Format} class for formatting. 98 * The {@link #toFormat()} method returns an implementation of the old API. 99 * 100 * <h3>Specification for implementors</h3> 101 * This class is immutable and thread-safe. 102 */ 103 public final class DateTimeFormatter { 104 105 //----------------------------------------------------------------------- 106 /** 107 * Returns the ISO date formatter that prints/parses a date without an offset, 108 * such as '2011-12-03'. 109 * <p> 110 * This returns an immutable formatter capable of printing and parsing 111 * the ISO-8601 extended local date format. 112 * The format consists of: 113 * <p><ul> 114 * <li>Four digits or more for the {@link ChronoField#YEAR year}. 115 * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. 116 * Years outside that range will have a prefixed positive or negative symbol. 117 * <li>A dash 118 * <li>Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}. 119 * This is pre-padded by zero to ensure two digits. 120 * <li>A dash 121 * <li>Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. 122 * This is pre-padded by zero to ensure two digits. 123 * </ul><p> 124 */ 125 public static final DateTimeFormatter ISO_LOCAL_DATE; 126 static { 127 ISO_LOCAL_DATE = new DateTimeFormatterBuilder() 128 .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) 129 .appendLiteral('-') 130 .appendValue(MONTH_OF_YEAR, 2) 131 .appendLiteral('-') 132 .appendValue(DAY_OF_MONTH, 2) 133 .toFormatter(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 134 } 135 136 //----------------------------------------------------------------------- 137 /** 138 * Returns the ISO date formatter that prints/parses a date with an offset, 139 * such as '2011-12-03+01:00'. 140 * <p> 141 * This returns an immutable formatter capable of printing and parsing 142 * the ISO-8601 extended offset date format. 143 * The format consists of: 144 * <p><ul> 145 * <li>The {@link #ISO_LOCAL_DATE} 146 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then 147 * they will be handled even though this is not part of the ISO-8601 standard. 148 * Parsing is case insensitive. 149 * </ul><p> 150 */ 151 public static final DateTimeFormatter ISO_OFFSET_DATE; 152 static { 153 ISO_OFFSET_DATE = new DateTimeFormatterBuilder() 154 .parseCaseInsensitive() 155 .append(ISO_LOCAL_DATE) 156 .appendOffsetId() 157 .toFormatter(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 158 } 159 160 //----------------------------------------------------------------------- 161 /** 162 * Returns the ISO date formatter that prints/parses a date with the 163 * offset if available, such as '2011-12-03' or '2011-12-03+01:00'. 164 * <p> 165 * This returns an immutable formatter capable of printing and parsing 166 * the ISO-8601 extended date format. 167 * The format consists of: 168 * <p><ul> 169 * <li>The {@link #ISO_LOCAL_DATE} 170 * <li>If the offset is not available to print/parse then the format is complete. 171 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then 172 * they will be handled even though this is not part of the ISO-8601 standard. 173 * Parsing is case insensitive. 174 * </ul><p> 175 * As this formatter has an optional element, it may be necessary to parse using 176 * {@link DateTimeFormatter#parseBest}. 177 */ 178 public static final DateTimeFormatter ISO_DATE; 179 static { 180 ISO_DATE = new DateTimeFormatterBuilder() 181 .parseCaseInsensitive() 182 .append(ISO_LOCAL_DATE) 183 .optionalStart() 184 .appendOffsetId() 185 .toFormatter(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 186 } 187 188 //----------------------------------------------------------------------- 189 /** 190 * Returns the ISO time formatter that prints/parses a time without an offset, 191 * such as '10:15' or '10:15:30'. 192 * <p> 193 * This returns an immutable formatter capable of printing and parsing 194 * the ISO-8601 extended local time format. 195 * The format consists of: 196 * <p><ul> 197 * <li>Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}. 198 * This is pre-padded by zero to ensure two digits. 199 * <li>A colon 200 * <li>Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}. 201 * This is pre-padded by zero to ensure two digits. 202 * <li>If the second-of-minute is not available to print/parse then the format is complete. 203 * <li>A colon 204 * <li>Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}. 205 * This is pre-padded by zero to ensure two digits. 206 * <li>If the nano-of-second is zero or not available to print/parse then the format is complete. 207 * <li>A decimal point 208 * <li>One to nine digits for the {@link ChronoField#NANO_OF_SECOND nano-of-second}. 209 * As many digits will be printed as required. 210 * </ul><p> 211 */ 212 public static final DateTimeFormatter ISO_LOCAL_TIME; 213 static { 214 ISO_LOCAL_TIME = new DateTimeFormatterBuilder() 215 .appendValue(HOUR_OF_DAY, 2) 216 .appendLiteral(':') 217 .appendValue(MINUTE_OF_HOUR, 2) 218 .optionalStart() 219 .appendLiteral(':') 220 .appendValue(SECOND_OF_MINUTE, 2) 221 .optionalStart() 222 .appendFraction(NANO_OF_SECOND, 0, 9, true) 223 .toFormatter(ResolverStyle.STRICT); 224 } 225 226 //----------------------------------------------------------------------- 227 /** 228 * Returns the ISO time formatter that prints/parses a time with an offset, 229 * such as '10:15+01:00' or '10:15:30+01:00'. 230 * <p> 231 * This returns an immutable formatter capable of printing and parsing 232 * the ISO-8601 extended offset time format. 233 * The format consists of: 234 * <p><ul> 235 * <li>The {@link #ISO_LOCAL_TIME} 236 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then 237 * they will be handled even though this is not part of the ISO-8601 standard. 238 * Parsing is case insensitive. 239 * </ul><p> 240 */ 241 public static final DateTimeFormatter ISO_OFFSET_TIME; 242 static { 243 ISO_OFFSET_TIME = new DateTimeFormatterBuilder() 244 .parseCaseInsensitive() 245 .append(ISO_LOCAL_TIME) 246 .appendOffsetId() 247 .toFormatter(ResolverStyle.STRICT); 248 } 249 250 //----------------------------------------------------------------------- 251 /** 252 * Returns the ISO time formatter that prints/parses a time, with the 253 * offset if available, such as '10:15', '10:15:30' or '10:15:30+01:00'. 254 * <p> 255 * This returns an immutable formatter capable of printing and parsing 256 * the ISO-8601 extended offset time format. 257 * The format consists of: 258 * <p><ul> 259 * <li>The {@link #ISO_LOCAL_TIME} 260 * <li>If the offset is not available to print/parse then the format is complete. 261 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then 262 * they will be handled even though this is not part of the ISO-8601 standard. 263 * Parsing is case insensitive. 264 * </ul><p> 265 * As this formatter has an optional element, it may be necessary to parse using 266 * {@link DateTimeFormatter#parseBest}. 267 */ 268 public static final DateTimeFormatter ISO_TIME; 269 static { 270 ISO_TIME = new DateTimeFormatterBuilder() 271 .parseCaseInsensitive() 272 .append(ISO_LOCAL_TIME) 273 .optionalStart() 274 .appendOffsetId() 275 .toFormatter(ResolverStyle.STRICT); 276 } 277 278 //----------------------------------------------------------------------- 279 /** 280 * Returns the ISO date formatter that prints/parses a date-time 281 * without an offset, such as '2011-12-03T10:15:30'. 282 * <p> 283 * This returns an immutable formatter capable of printing and parsing 284 * the ISO-8601 extended offset date-time format. 285 * The format consists of: 286 * <p><ul> 287 * <li>The {@link #ISO_LOCAL_DATE} 288 * <li>The letter 'T'. Parsing is case insensitive. 289 * <li>The {@link #ISO_LOCAL_TIME} 290 * </ul><p> 291 */ 292 public static final DateTimeFormatter ISO_LOCAL_DATE_TIME; 293 static { 294 ISO_LOCAL_DATE_TIME = new DateTimeFormatterBuilder() 295 .parseCaseInsensitive() 296 .append(ISO_LOCAL_DATE) 297 .appendLiteral('T') 298 .append(ISO_LOCAL_TIME) 299 .toFormatter(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 300 } 301 302 //----------------------------------------------------------------------- 303 /** 304 * Returns the ISO date formatter that prints/parses a date-time 305 * with an offset, such as '2011-12-03T10:15:30+01:00'. 306 * <p> 307 * This returns an immutable formatter capable of printing and parsing 308 * the ISO-8601 extended offset date-time format. 309 * The format consists of: 310 * <p><ul> 311 * <li>The {@link #ISO_LOCAL_DATE_TIME} 312 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then 313 * they will be handled even though this is not part of the ISO-8601 standard. 314 * Parsing is case insensitive. 315 * </ul><p> 316 */ 317 public static final DateTimeFormatter ISO_OFFSET_DATE_TIME; 318 static { 319 ISO_OFFSET_DATE_TIME = new DateTimeFormatterBuilder() 320 .parseCaseInsensitive() 321 .append(ISO_LOCAL_DATE_TIME) 322 .appendOffsetId() 323 .toFormatter(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 324 } 325 326 //----------------------------------------------------------------------- 327 /** 328 * Returns the ISO date formatter that prints/parses a date-time with 329 * offset and zone, such as '2011-12-03T10:15:30+01:00[Europe/Paris]'. 330 * <p> 331 * This returns an immutable formatter capable of printing and parsing 332 * a format that extends the ISO-8601 extended offset date-time format 333 * to add the time-zone. 334 * The format consists of: 335 * <p><ul> 336 * <li>The {@link #ISO_OFFSET_DATE_TIME} 337 * <li>If the zone ID is not available or is a {@code ZoneOffset} then the format is complete. 338 * <li>An open square bracket '['. 339 * <li>The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard. 340 * Parsing is case sensitive. 341 * <li>A close square bracket ']'. 342 * </ul><p> 343 */ 344 public static final DateTimeFormatter ISO_ZONED_DATE_TIME; 345 static { 346 ISO_ZONED_DATE_TIME = new DateTimeFormatterBuilder() 347 .append(ISO_OFFSET_DATE_TIME) 348 .optionalStart() 349 .appendLiteral('[') 350 .parseCaseSensitive() 351 .appendZoneRegionId() 352 .appendLiteral(']') 353 .toFormatter(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 354 } 355 356 //----------------------------------------------------------------------- 357 /** 358 * Returns the ISO date formatter that prints/parses a date-time 359 * with the offset and zone if available, such as '2011-12-03T10:15:30', 360 * '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]'. 361 * <p> 362 * This returns an immutable formatter capable of printing and parsing 363 * the ISO-8601 extended offset date-time format. 364 * The format consists of: 365 * <p><ul> 366 * <li>The {@link #ISO_LOCAL_DATE_TIME} 367 * <li>If the offset is not available to print/parse then the format is complete. 368 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then 369 * they will be handled even though this is not part of the ISO-8601 standard. 370 * <li>If the zone ID is not available or is a {@code ZoneOffset} then the format is complete. 371 * <li>An open square bracket '['. 372 * <li>The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard. 373 * Parsing is case sensitive. 374 * <li>A close square bracket ']'. 375 * </ul><p> 376 * As this formatter has an optional element, it may be necessary to parse using 377 * {@link DateTimeFormatter#parseBest}. 378 */ 379 public static final DateTimeFormatter ISO_DATE_TIME; 380 static { 381 ISO_DATE_TIME = new DateTimeFormatterBuilder() 382 .append(ISO_LOCAL_DATE_TIME) 383 .optionalStart() 384 .appendOffsetId() 385 .optionalStart() 386 .appendLiteral('[') 387 .parseCaseSensitive() 388 .appendZoneRegionId() 389 .appendLiteral(']') 390 .toFormatter(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 391 } 392 393 //----------------------------------------------------------------------- 394 /** 395 * Returns the ISO date formatter that prints/parses the ordinal date 396 * without an offset, such as '2012-337'. 397 * <p> 398 * This returns an immutable formatter capable of printing and parsing 399 * the ISO-8601 extended ordinal date format. 400 * The format consists of: 401 * <p><ul> 402 * <li>Four digits or more for the {@link ChronoField#YEAR year}. 403 * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. 404 * Years outside that range will have a prefixed positive or negative symbol. 405 * <li>A dash 406 * <li>Three digits for the {@link ChronoField#DAY_OF_YEAR day-of-year}. 407 * This is pre-padded by zero to ensure three digits. 408 * <li>If the offset is not available to print/parse then the format is complete. 409 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then 410 * they will be handled even though this is not part of the ISO-8601 standard. 411 * Parsing is case insensitive. 412 * </ul><p> 413 * As this formatter has an optional element, it may be necessary to parse using 414 * {@link DateTimeFormatter#parseBest}. 415 */ 416 public static final DateTimeFormatter ISO_ORDINAL_DATE; 417 static { 418 ISO_ORDINAL_DATE = new DateTimeFormatterBuilder() 419 .parseCaseInsensitive() 420 .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) 421 .appendLiteral('-') 422 .appendValue(DAY_OF_YEAR, 3) 423 .optionalStart() 424 .appendOffsetId() 425 .toFormatter(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 426 } 427 428 //----------------------------------------------------------------------- 429 /** 430 * Returns the ISO date formatter that prints/parses the week-based date 431 * without an offset, such as '2012-W48-6'. 432 * <p> 433 * This returns an immutable formatter capable of printing and parsing 434 * the ISO-8601 extended week-based date format. 435 * The format consists of: 436 * <p><ul> 437 * <li>Four digits or more for the {@link IsoFields#WEEK_BASED_YEAR week-based-year}. 438 * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits. 439 * Years outside that range will have a prefixed positive or negative symbol. 440 * <li>A dash 441 * <li>The letter 'W'. Parsing is case insensitive. 442 * <li>Two digits for the {@link IsoFields#WEEK_OF_WEEK_BASED_YEAR week-of-week-based-year}. 443 * This is pre-padded by zero to ensure three digits. 444 * <li>A dash 445 * <li>One digit for the {@link ChronoField#DAY_OF_WEEK day-of-week}. 446 * The value run from Monday (1) to Sunday (7). 447 * <li>If the offset is not available to print/parse then the format is complete. 448 * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then 449 * they will be handled even though this is not part of the ISO-8601 standard. 450 * Parsing is case insensitive. 451 * </ul><p> 452 * As this formatter has an optional element, it may be necessary to parse using 453 * {@link DateTimeFormatter#parseBest}. 454 */ 455 public static final DateTimeFormatter ISO_WEEK_DATE; 456 static { 457 ISO_WEEK_DATE = new DateTimeFormatterBuilder() 458 .parseCaseInsensitive() 459 .appendValue(IsoFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD) 460 .appendLiteral("-W") 461 .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2) 462 .appendLiteral('-') 463 .appendValue(DAY_OF_WEEK, 1) 464 .optionalStart() 465 .appendOffsetId() 466 .toFormatter(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 467 } 468 469 //----------------------------------------------------------------------- 470 /** 471 * The ISO instant formatter that formats or parses an instant in UTC, 472 * such as '2011-12-03T10:15:30Z'. 473 * <p> 474 * This returns an immutable formatter capable of formatting and parsing 475 * the ISO-8601 instant format. 476 * When formatting, the second-of-minute is always output. 477 * The nano-of-second outputs zero, three, six or nine digits as necessary. 478 * When parsing, time to at least the seconds field is required. 479 * Fractional seconds from zero to nine are parsed. 480 * The localized decimal style is not used. 481 * <p> 482 * This is a special case formatter intended to allow a human readable form 483 * of an {@link org.threeten.bp.Instant Instant}. 484 * The {@code Instant} class is designed to 485 * only represent a point in time and internally stores a value in nanoseconds 486 * from a fixed epoch of 1970-01-01Z. As such, an {@code Instant} cannot be 487 * formatted as a date or time without providing some form of time-zone. 488 * This formatter allows the {@code Instant} to be formatted, by providing 489 * a suitable conversion using {@code ZoneOffset.UTC}. 490 * <p> 491 * The format consists of: 492 * <ul> 493 * <li>The {@link #ISO_OFFSET_DATE_TIME} where the instant is converted from 494 * {@link ChronoField#INSTANT_SECONDS} and {@link ChronoField#NANO_OF_SECOND} 495 * using the {@code UTC} offset. Parsing is case insensitive. 496 * </ul> 497 * <p> 498 * The returned formatter has no override chronology or zone. 499 * It uses the {@link ResolverStyle#STRICT STRICT} resolver style. 500 */ 501 public static final DateTimeFormatter ISO_INSTANT; 502 static { 503 ISO_INSTANT = new DateTimeFormatterBuilder() 504 .parseCaseInsensitive() 505 .appendInstant() 506 .toFormatter(ResolverStyle.STRICT); 507 } 508 509 //----------------------------------------------------------------------- 510 /** 511 * Returns the ISO date formatter that prints/parses a date without an offset, 512 * such as '20111203'. 513 * <p> 514 * This returns an immutable formatter capable of printing and parsing 515 * the ISO-8601 basic local date format. 516 * The format consists of: 517 * <p><ul> 518 * <li>Four digits for the {@link ChronoField#YEAR year}. 519 * Only years in the range 0000 to 9999 are supported. 520 * <li>Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}. 521 * This is pre-padded by zero to ensure two digits. 522 * <li>Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. 523 * This is pre-padded by zero to ensure two digits. 524 * <li>If the offset is not available to print/parse then the format is complete. 525 * <li>The {@link ZoneOffset#getId() offset ID} without colons. If the offset has 526 * seconds then they will be handled even though this is not part of the ISO-8601 standard. 527 * Parsing is case insensitive. 528 * </ul><p> 529 * As this formatter has an optional element, it may be necessary to parse using 530 * {@link DateTimeFormatter#parseBest}. 531 */ 532 public static final DateTimeFormatter BASIC_ISO_DATE; 533 static { 534 BASIC_ISO_DATE = new DateTimeFormatterBuilder() 535 .parseCaseInsensitive() 536 .appendValue(YEAR, 4) 537 .appendValue(MONTH_OF_YEAR, 2) 538 .appendValue(DAY_OF_MONTH, 2) 539 .optionalStart() 540 .appendOffset("+HHMMss", "Z") 541 .toFormatter(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 542 } 543 544 //----------------------------------------------------------------------- 545 /** 546 * Returns the RFC-1123 date-time formatter, such as 'Tue, 3 Jun 2008 11:05:30 GMT'. 547 * <p> 548 * This returns an immutable formatter capable of printing and parsing 549 * most of the RFC-1123 format. 550 * RFC-1123 updates RFC-822 changing the year from two digits to four. 551 * This implementation requires a four digit year. 552 * This implementation also does not handle North American or military zone 553 * names, only 'GMT' and offset amounts. 554 * <p> 555 * The format consists of: 556 * <p><ul> 557 * <li>If the day-of-week is not available to print/parse then jump to day-of-month. 558 * <li>Three letter {@link ChronoField#DAY_OF_WEEK day-of-week} in English. 559 * <li>A comma 560 * <li>A space 561 * <li>One or two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}. 562 * <li>A space 563 * <li>Three letter {@link ChronoField#MONTH_OF_YEAR month-of-year} in English. 564 * <li>A space 565 * <li>Four digits for the {@link ChronoField#YEAR year}. 566 * Only years in the range 0000 to 9999 are supported. 567 * <li>A space 568 * <li>Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}. 569 * This is pre-padded by zero to ensure two digits. 570 * <li>A colon 571 * <li>Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}. 572 * This is pre-padded by zero to ensure two digits. 573 * <li>If the second-of-minute is not available to print/parse then jump to the next space. 574 * <li>A colon 575 * <li>Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}. 576 * This is pre-padded by zero to ensure two digits. 577 * <li>A space 578 * <li>The {@link ZoneOffset#getId() offset ID} without colons or seconds. 579 * An offset of zero uses "GMT". North American zone names and military zone names are not handled. 580 * </ul><p> 581 * Parsing is case insensitive. 582 */ 583 public static final DateTimeFormatter RFC_1123_DATE_TIME; 584 static { 585 // manually code maps to ensure correct data always used 586 // (locale data can be changed by application code) 587 Map<Long, String> dow = new HashMap<Long, String>(); 588 dow.put(1L, "Mon"); 589 dow.put(2L, "Tue"); 590 dow.put(3L, "Wed"); 591 dow.put(4L, "Thu"); 592 dow.put(5L, "Fri"); 593 dow.put(6L, "Sat"); 594 dow.put(7L, "Sun"); 595 Map<Long, String> moy = new HashMap<Long, String>(); 596 moy.put(1L, "Jan"); 597 moy.put(2L, "Feb"); 598 moy.put(3L, "Mar"); 599 moy.put(4L, "Apr"); 600 moy.put(5L, "May"); 601 moy.put(6L, "Jun"); 602 moy.put(7L, "Jul"); 603 moy.put(8L, "Aug"); 604 moy.put(9L, "Sep"); 605 moy.put(10L, "Oct"); 606 moy.put(11L, "Nov"); 607 moy.put(12L, "Dec"); 608 RFC_1123_DATE_TIME = new DateTimeFormatterBuilder() 609 .parseCaseInsensitive() 610 .parseLenient() 611 .optionalStart() 612 .appendText(DAY_OF_WEEK, dow) 613 .appendLiteral(", ") 614 .optionalEnd() 615 .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE) 616 .appendLiteral(' ') 617 .appendText(MONTH_OF_YEAR, moy) 618 .appendLiteral(' ') 619 .appendValue(YEAR, 4) // 2 digit year not handled 620 .appendLiteral(' ') 621 .appendValue(HOUR_OF_DAY, 2) 622 .appendLiteral(':') 623 .appendValue(MINUTE_OF_HOUR, 2) 624 .optionalStart() 625 .appendLiteral(':') 626 .appendValue(SECOND_OF_MINUTE, 2) 627 .optionalEnd() 628 .appendLiteral(' ') 629 .appendOffset("+HHMM", "GMT") // should handle UT/Z/EST/EDT/CST/CDT/MST/MDT/PST/MDT 630 .toFormatter(ResolverStyle.SMART).withChronology(IsoChronology.INSTANCE); 631 } 632 633 //----------------------------------------------------------------------- 634 /** 635 * Creates a formatter using the specified pattern. 636 * <p> 637 * This method will create a formatter based on a simple pattern of letters and symbols. 638 * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'. 639 * <p> 640 * The returned formatter will use the default locale, but this can be changed 641 * using {@link DateTimeFormatter#withLocale(Locale)}. 642 * <p> 643 * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. 644 * The following pattern letters are defined: 645 * <pre> 646 * Symbol Meaning Presentation Examples 647 * ------ ------- ------------ ------- 648 * G era number/text 1; 01; AD; Anno Domini 649 * y year year 2004; 04 650 * D day-of-year number 189 651 * M month-of-year number/text 7; 07; Jul; July; J 652 * d day-of-month number 10 653 * 654 * Q quarter-of-year number/text 3; 03; Q3 655 * Y week-based-year year 1996; 96 656 * w week-of-year number 27 657 * W week-of-month number 27 658 * e localized day-of-week number 2; Tue; Tuesday; T 659 * E day-of-week number/text 2; Tue; Tuesday; T 660 * F week-of-month number 3 661 * 662 * a am-pm-of-day text PM 663 * h clock-hour-of-am-pm (1-12) number 12 664 * K hour-of-am-pm (0-11) number 0 665 * k clock-hour-of-am-pm (1-24) number 0 666 * 667 * H hour-of-day (0-23) number 0 668 * m minute-of-hour number 30 669 * s second-of-minute number 55 670 * S fraction-of-second fraction 978 671 * A milli-of-day number 1234 672 * n nano-of-second number 987654321 673 * N nano-of-day number 1234000000 674 * 675 * V time-zone ID zone-id America/Los_Angeles; Z; -08:30 676 * z time-zone name zone-name Pacific Standard Time; PST 677 * X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15; 678 * x zone-offset offset-x +0000; -08; -0830; -08:30; -083015; -08:30:15; 679 * Z zone-offset offset-Z +0000; -0800; -08:00; 680 * 681 * p pad next pad modifier 1 682 * 683 * ' escape for text delimiter 684 * '' single quote literal ' 685 * [ optional section start 686 * ] optional section end 687 * {} reserved for future use 688 * </pre> 689 * <p> 690 * The count of pattern letters determine the format. 691 * <p> 692 * <b>Text</b>: The text style is determined based on the number of pattern letters used. 693 * Less than 4 pattern letters will use the {@link TextStyle#SHORT short form}. 694 * Exactly 4 pattern letters will use the {@link TextStyle#FULL full form}. 695 * Exactly 5 pattern letters will use the {@link TextStyle#NARROW narrow form}. 696 * <p> 697 * <b>Number</b>: If the count of letters is one, then the value is printed using the minimum number 698 * of digits and without padding as per {@link DateTimeFormatterBuilder#appendValue(TemporalField)}. 699 * Otherwise, the count of digits is used as the width of the output field as per 700 * {@link DateTimeFormatterBuilder#appendValue(TemporalField, int)}. 701 * <p> 702 * <b>Number/Text</b>: If the count of pattern letters is 3 or greater, use the Text rules above. 703 * Otherwise use the Number rules above. 704 * <p> 705 * <b>Fraction</b>: Outputs the nano-of-second field as a fraction-of-second. 706 * The nano-of-second value has nine digits, thus the count of pattern letters is from 1 to 9. 707 * If it is less than 9, then the nano-of-second value is truncated, with only the most 708 * significant digits being output. 709 * When parsing in strict mode, the number of parsed digits must match the count of pattern letters. 710 * When parsing in lenient mode, the number of parsed digits must be at least the count of pattern 711 * letters, up to 9 digits. 712 * <p> 713 * <b>Year</b>: The count of letters determines the minimum field width below which padding is used. 714 * If the count of letters is two, then a {@link DateTimeFormatterBuilder#appendValueReduced reduced} 715 * two digit form is used. 716 * For printing, this outputs the rightmost two digits. For parsing, this will parse using the 717 * base value of 2000, resulting in a year within the range 2000 to 2099 inclusive. 718 * If the count of letters is less than four (but not two), then the sign is only output for negative 719 * years as per {@link SignStyle#NORMAL}. 720 * Otherwise, the sign is output if the pad width is exceeded, as per {@link SignStyle#EXCEEDS_PAD} 721 * <p> 722 * <b>ZoneId</b>: This outputs the time-zone ID, such as 'Europe/Paris'. 723 * If the count of letters is two, then the time-zone ID is output. 724 * Any other count of letters throws {@code IllegalArgumentException}. 725 * <p> 726 * <b>Zone names</b>: This outputs the display name of the time-zone ID. 727 * If the count of letters is one, two or three, then the short name is output. 728 * If the count of letters is four, then the full name is output. 729 * Five or more letters throws {@code IllegalArgumentException}. 730 * <p> 731 * <b>Offset X and x</b>: This formats the offset based on the number of pattern letters. 732 * One letter outputs just the hour', such as '+01', unless the minute is non-zero 733 * in which case the minute is also output, such as '+0130'. 734 * Two letters outputs the hour and minute, without a colon, such as '+0130'. 735 * Three letters outputs the hour and minute, with a colon, such as '+01:30'. 736 * Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'. 737 * Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'. 738 * Six or more letters throws {@code IllegalArgumentException}. 739 * Pattern letter 'X' (upper case) will output 'Z' when the offset to be output would be zero, 740 * whereas pattern letter 'x' (lower case) will output '+00', '+0000', or '+00:00'. 741 * <p> 742 * <b>Offset Z</b>: This formats the offset based on the number of pattern letters. 743 * One, two or three letters outputs the hour and minute, without a colon, such as '+0130'. 744 * Four or more letters throws {@code IllegalArgumentException}. 745 * The output will be '+0000' when the offset is zero. 746 * <p> 747 * <b>Optional section</b>: The optional section markers work exactly like calling 748 * {@link DateTimeFormatterBuilder#optionalStart()} and {@link DateTimeFormatterBuilder#optionalEnd()}. 749 * <p> 750 * <b>Pad modifier</b>: Modifies the pattern that immediately follows to be padded with spaces. 751 * The pad width is determined by the number of pattern letters. 752 * This is the same as calling {@link DateTimeFormatterBuilder#padNext(int)}. 753 * <p> 754 * For example, 'ppH' outputs the hour-of-day padded on the left with spaces to a width of 2. 755 * <p> 756 * Any unrecognized letter is an error. 757 * Any non-letter character, other than '[', ']', '{', '}' and the single quote will be output directly. 758 * Despite this, it is recommended to use single quotes around all characters that you want to 759 * output directly to ensure that future changes do not break your application. 760 * 761 * @param pattern the pattern to use, not null 762 * @return the formatter based on the pattern, not null 763 * @throws IllegalArgumentException if the pattern is invalid 764 * @see DateTimeFormatterBuilder#appendPattern(String) 765 */ ofPattern(String pattern)766 public static DateTimeFormatter ofPattern(String pattern) { 767 return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(); 768 } 769 770 /** 771 * Creates a formatter using the specified pattern. 772 * <p> 773 * This method will create a formatter based on a simple pattern of letters and symbols. 774 * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'. 775 * <p> 776 * See {@link #ofPattern(String)} for details of the pattern. 777 * <p> 778 * The returned formatter will use the specified locale, but this can be changed 779 * using {@link DateTimeFormatter#withLocale(Locale)}. 780 * 781 * @param pattern the pattern to use, not null 782 * @param locale the locale to use, not null 783 * @return the formatter based on the pattern, not null 784 * @throws IllegalArgumentException if the pattern is invalid 785 * @see DateTimeFormatterBuilder#appendPattern(String) 786 */ ofPattern(String pattern, Locale locale)787 public static DateTimeFormatter ofPattern(String pattern, Locale locale) { 788 return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale); 789 } 790 791 //----------------------------------------------------------------------- 792 /** 793 * Returns a locale specific date format. 794 * <p> 795 * This returns a formatter that will print/parse a date. 796 * The exact format pattern used varies by locale. 797 * <p> 798 * The locale is determined from the formatter. The formatter returned directly by 799 * this method will use the {@link Locale#getDefault() default locale}. 800 * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} 801 * on the result of this method. 802 * <p> 803 * Note that the localized pattern is looked up lazily. 804 * This {@code DateTimeFormatter} holds the style required and the locale, 805 * looking up the pattern required on demand. 806 * 807 * @param dateStyle the formatter style to obtain, not null 808 * @return the date formatter, not null 809 */ ofLocalizedDate(FormatStyle dateStyle)810 public static DateTimeFormatter ofLocalizedDate(FormatStyle dateStyle) { 811 Jdk8Methods.requireNonNull(dateStyle, "dateStyle"); 812 return new DateTimeFormatterBuilder().appendLocalized(dateStyle, null) 813 .toFormatter().withChronology(IsoChronology.INSTANCE); 814 } 815 816 /** 817 * Returns a locale specific time format. 818 * <p> 819 * This returns a formatter that will print/parse a time. 820 * The exact format pattern used varies by locale. 821 * <p> 822 * The locale is determined from the formatter. The formatter returned directly by 823 * this method will use the {@link Locale#getDefault() default locale}. 824 * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} 825 * on the result of this method. 826 * <p> 827 * Note that the localized pattern is looked up lazily. 828 * This {@code DateTimeFormatter} holds the style required and the locale, 829 * looking up the pattern required on demand. 830 * 831 * @param timeStyle the formatter style to obtain, not null 832 * @return the time formatter, not null 833 */ ofLocalizedTime(FormatStyle timeStyle)834 public static DateTimeFormatter ofLocalizedTime(FormatStyle timeStyle) { 835 Jdk8Methods.requireNonNull(timeStyle, "timeStyle"); 836 return new DateTimeFormatterBuilder().appendLocalized(null, timeStyle) 837 .toFormatter().withChronology(IsoChronology.INSTANCE); 838 } 839 840 /** 841 * Returns a locale specific date-time format, which is typically of short length. 842 * <p> 843 * This returns a formatter that will print/parse a date-time. 844 * The exact format pattern used varies by locale. 845 * <p> 846 * The locale is determined from the formatter. The formatter returned directly by 847 * this method will use the {@link Locale#getDefault() default locale}. 848 * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} 849 * on the result of this method. 850 * <p> 851 * Note that the localized pattern is looked up lazily. 852 * This {@code DateTimeFormatter} holds the style required and the locale, 853 * looking up the pattern required on demand. 854 * 855 * @param dateTimeStyle the formatter style to obtain, not null 856 * @return the date-time formatter, not null 857 */ ofLocalizedDateTime(FormatStyle dateTimeStyle)858 public static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateTimeStyle) { 859 Jdk8Methods.requireNonNull(dateTimeStyle, "dateTimeStyle"); 860 return new DateTimeFormatterBuilder().appendLocalized(dateTimeStyle, dateTimeStyle) 861 .toFormatter().withChronology(IsoChronology.INSTANCE); 862 } 863 864 /** 865 * Returns a locale specific date and time format. 866 * <p> 867 * This returns a formatter that will print/parse a date-time. 868 * The exact format pattern used varies by locale. 869 * <p> 870 * The locale is determined from the formatter. The formatter returned directly by 871 * this method will use the {@link Locale#getDefault() default locale}. 872 * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)} 873 * on the result of this method. 874 * <p> 875 * Note that the localized pattern is looked up lazily. 876 * This {@code DateTimeFormatter} holds the style required and the locale, 877 * looking up the pattern required on demand. 878 * 879 * @param dateStyle the date formatter style to obtain, not null 880 * @param timeStyle the time formatter style to obtain, not null 881 * @return the date, time or date-time formatter, not null 882 */ ofLocalizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle)883 public static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle) { 884 Jdk8Methods.requireNonNull(dateStyle, "dateStyle"); 885 Jdk8Methods.requireNonNull(timeStyle, "timeStyle"); 886 return new DateTimeFormatterBuilder().appendLocalized(dateStyle, timeStyle) 887 .toFormatter().withChronology(IsoChronology.INSTANCE); 888 } 889 890 //----------------------------------------------------------------------- 891 /** 892 * A query that provides access to the excess days that were parsed. 893 * <p> 894 * This returns a singleton {@linkplain TemporalQuery query} that provides 895 * access to additional information from the parse. The query always returns 896 * a non-null period, with a zero period returned instead of null. 897 * <p> 898 * There are two situations where this query may return a non-zero period. 899 * <ul> 900 * <li>If the {@code ResolverStyle} is {@code LENIENT} and a time is parsed 901 * without a date, then the complete result of the parse consists of a 902 * {@code LocalTime} and an excess {@code Period} in days. 903 * 904 * <li>If the {@code ResolverStyle} is {@code SMART} and a time is parsed 905 * without a date where the time is 24:00:00, then the complete result of 906 * the parse consists of a {@code LocalTime} of 00:00:00 and an excess 907 * {@code Period} of one day. 908 * </ul> 909 * <p> 910 * In both cases, if a complete {@code ChronoLocalDateTime} or {@code Instant} 911 * is parsed, then the excess days are added to the date part. 912 * As a result, this query will return a zero period. 913 * <p> 914 * The {@code SMART} behaviour handles the common "end of day" 24:00 value. 915 * Processing in {@code LENIENT} mode also produces the same result: 916 * <pre> 917 * Text to parse Parsed object Excess days 918 * "2012-12-03T00:00" LocalDateTime.of(2012, 12, 3, 0, 0) ZERO 919 * "2012-12-03T24:00" LocalDateTime.of(2012, 12, 4, 0, 0) ZERO 920 * "00:00" LocalTime.of(0, 0) ZERO 921 * "24:00" LocalTime.of(0, 0) Period.ofDays(1) 922 * </pre> 923 * The query can be used as follows: 924 * <pre> 925 * TemporalAccessor parsed = formatter.parse(str); 926 * LocalTime time = parsed.query(LocalTime.FROM); 927 * Period extraDays = parsed.query(DateTimeFormatter.parsedExcessDays()); 928 * </pre> 929 * @return a query that provides access to the excess days that were parsed 930 */ parsedExcessDays()931 public static final TemporalQuery<Period> parsedExcessDays() { 932 return PARSED_EXCESS_DAYS; 933 } 934 private static final TemporalQuery<Period> PARSED_EXCESS_DAYS = new TemporalQuery<Period>() { 935 public Period queryFrom(TemporalAccessor temporal) { 936 if (temporal instanceof DateTimeBuilder) { 937 return ((DateTimeBuilder) temporal).excessDays; 938 } else { 939 return Period.ZERO; 940 } 941 } 942 }; 943 944 /** 945 * A query that provides access to whether a leap-second was parsed. 946 * <p> 947 * This returns a singleton {@linkplain TemporalQuery query} that provides 948 * access to additional information from the parse. The query always returns 949 * a non-null boolean, true if parsing saw a leap-second, false if not. 950 * <p> 951 * Instant parsing handles the special "leap second" time of '23:59:60'. 952 * Leap seconds occur at '23:59:60' in the UTC time-zone, but at other 953 * local times in different time-zones. To avoid this potential ambiguity, 954 * the handling of leap-seconds is limited to 955 * {@link DateTimeFormatterBuilder#appendInstant()}, as that method 956 * always parses the instant with the UTC zone offset. 957 * <p> 958 * If the time '23:59:60' is received, then a simple conversion is applied, 959 * replacing the second-of-minute of 60 with 59. This query can be used 960 * on the parse result to determine if the leap-second adjustment was made. 961 * The query will return one second of excess if it did adjust to remove 962 * the leap-second, and zero if not. Note that applying a leap-second 963 * smoothing mechanism, such as UTC-SLS, is the responsibility of the 964 * application, as follows: 965 * <pre> 966 * TemporalAccessor parsed = formatter.parse(str); 967 * Instant instant = parsed.query(Instant::from); 968 * if (parsed.query(DateTimeFormatter.parsedLeapSecond())) { 969 * // validate leap-second is correct and apply correct smoothing 970 * } 971 * </pre> 972 * @return a query that provides access to whether a leap-second was parsed 973 */ parsedLeapSecond()974 public static final TemporalQuery<Boolean> parsedLeapSecond() { 975 return PARSED_LEAP_SECOND; 976 } 977 private static final TemporalQuery<Boolean> PARSED_LEAP_SECOND = new TemporalQuery<Boolean>() { 978 public Boolean queryFrom(TemporalAccessor temporal) { 979 if (temporal instanceof DateTimeBuilder) { 980 return ((DateTimeBuilder) temporal).leapSecond; 981 } else { 982 return Boolean.FALSE; 983 } 984 } 985 }; 986 987 //----------------------------------------------------------------------- 988 /** 989 * The printer and/or parser to use, not null. 990 */ 991 private final CompositePrinterParser printerParser; 992 /** 993 * The locale to use for formatting, not null. 994 */ 995 private final Locale locale; 996 /** 997 * The symbols to use for formatting, not null. 998 */ 999 private final DecimalStyle decimalStyle; 1000 /** 1001 * The resolver style to use, not null. 1002 */ 1003 private final ResolverStyle resolverStyle; 1004 /** 1005 * The fields to use in resolving, null for all fields. 1006 */ 1007 private final Set<TemporalField> resolverFields; 1008 /** 1009 * The chronology to use for formatting, null for no override. 1010 */ 1011 private final Chronology chrono; 1012 /** 1013 * The zone to use for formatting, null for no override. 1014 */ 1015 private final ZoneId zone; 1016 1017 //----------------------------------------------------------------------- 1018 /** 1019 * Constructor. 1020 * 1021 * @param printerParser the printer/parser to use, not null 1022 * @param locale the locale to use, not null 1023 * @param decimalStyle the decimal style to use, not null 1024 * @param resolverStyle the resolver style to use, not null 1025 * @param resolverFields the fields to use during resolving, null for all fields 1026 * @param chrono the chronology to use, null for no override 1027 * @param zone the zone to use, null for no override 1028 */ DateTimeFormatter(CompositePrinterParser printerParser, Locale locale, DecimalStyle decimalStyle, ResolverStyle resolverStyle, Set<TemporalField> resolverFields, Chronology chrono, ZoneId zone)1029 DateTimeFormatter(CompositePrinterParser printerParser, Locale locale, 1030 DecimalStyle decimalStyle, ResolverStyle resolverStyle, 1031 Set<TemporalField> resolverFields, Chronology chrono, ZoneId zone) { 1032 this.printerParser = Jdk8Methods.requireNonNull(printerParser, "printerParser"); 1033 this.locale = Jdk8Methods.requireNonNull(locale, "locale"); 1034 this.decimalStyle = Jdk8Methods.requireNonNull(decimalStyle, "decimalStyle"); 1035 this.resolverStyle = Jdk8Methods.requireNonNull(resolverStyle, "resolverStyle"); 1036 this.resolverFields = resolverFields; 1037 this.chrono = chrono; 1038 this.zone = zone; 1039 } 1040 1041 //----------------------------------------------------------------------- 1042 /** 1043 * Gets the locale to be used during formatting. 1044 * <p> 1045 * This is used to lookup any part of the formatter needing specific 1046 * localization, such as the text or localized pattern. 1047 * 1048 * @return the locale of this formatter, not null 1049 */ getLocale()1050 public Locale getLocale() { 1051 return locale; 1052 } 1053 1054 /** 1055 * Returns a copy of this formatter with a new locale. 1056 * <p> 1057 * This is used to lookup any part of the formatter needing specific 1058 * localization, such as the text or localized pattern. 1059 * <p> 1060 * This instance is immutable and unaffected by this method call. 1061 * 1062 * @param locale the new locale, not null 1063 * @return a formatter based on this formatter with the requested locale, not null 1064 */ withLocale(Locale locale)1065 public DateTimeFormatter withLocale(Locale locale) { 1066 if (this.locale.equals(locale)) { 1067 return this; 1068 } 1069 return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone); 1070 } 1071 1072 //----------------------------------------------------------------------- 1073 /** 1074 * Gets the decimal style to be used during formatting. 1075 * 1076 * @return the decimal style of this formatter, not null 1077 */ getDecimalStyle()1078 public DecimalStyle getDecimalStyle() { 1079 return decimalStyle; 1080 } 1081 1082 /** 1083 * Returns a copy of this formatter with a new decimal style. 1084 * <p> 1085 * This instance is immutable and unaffected by this method call. 1086 * 1087 * @param decimalStyle the new decimal style, not null 1088 * @return a formatter based on this formatter with the requested symbols, not null 1089 */ withDecimalStyle(DecimalStyle decimalStyle)1090 public DateTimeFormatter withDecimalStyle(DecimalStyle decimalStyle) { 1091 if (this.decimalStyle.equals(decimalStyle)) { 1092 return this; 1093 } 1094 return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone); 1095 } 1096 1097 //----------------------------------------------------------------------- 1098 /** 1099 * Gets the overriding chronology to be used during formatting. 1100 * <p> 1101 * This returns the override chronology, used to convert dates. 1102 * By default, a formatter has no override chronology, returning null. 1103 * See {@link #withChronology(Chronology)} for more details on overriding. 1104 * 1105 * @return the chronology of this formatter, null if no override 1106 */ getChronology()1107 public Chronology getChronology() { 1108 return chrono; 1109 } 1110 1111 /** 1112 * Returns a copy of this formatter with a new override chronology. 1113 * <p> 1114 * This returns a formatter with similar state to this formatter but 1115 * with the override chronology set. 1116 * By default, a formatter has no override chronology, returning null. 1117 * <p> 1118 * If an override is added, then any date that is printed or parsed will be affected. 1119 * <p> 1120 * When printing, if the {@code Temporal} object contains a date then it will 1121 * be converted to a date in the override chronology. 1122 * Any time or zone will be retained unless overridden. 1123 * The converted result will behave in a manner equivalent to an implementation 1124 * of {@code ChronoLocalDate},{@code ChronoLocalDateTime} or {@code ChronoZonedDateTime}. 1125 * <p> 1126 * When parsing, the override chronology will be used to interpret the 1127 * {@linkplain ChronoField fields} into a date unless the 1128 * formatter directly parses a valid chronology. 1129 * <p> 1130 * This instance is immutable and unaffected by this method call. 1131 * 1132 * @param chrono the new chronology, not null 1133 * @return a formatter based on this formatter with the requested override chronology, not null 1134 */ withChronology(Chronology chrono)1135 public DateTimeFormatter withChronology(Chronology chrono) { 1136 if (Jdk8Methods.equals(this.chrono, chrono)) { 1137 return this; 1138 } 1139 return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone); 1140 } 1141 1142 //----------------------------------------------------------------------- 1143 /** 1144 * Gets the overriding zone to be used during formatting. 1145 * <p> 1146 * This returns the override zone, used to convert instants. 1147 * By default, a formatter has no override zone, returning null. 1148 * See {@link #withZone(ZoneId)} for more details on overriding. 1149 * 1150 * @return the chronology of this formatter, null if no override 1151 */ getZone()1152 public ZoneId getZone() { 1153 return zone; 1154 } 1155 1156 /** 1157 * Returns a copy of this formatter with a new override zone. 1158 * <p> 1159 * This returns a formatter with similar state to this formatter but 1160 * with the override zone set. 1161 * By default, a formatter has no override zone, returning null. 1162 * <p> 1163 * If an override is added, then any instant that is printed or parsed will be affected. 1164 * <p> 1165 * When printing, if the {@code Temporal} object contains an instant then it will 1166 * be converted to a zoned date-time using the override zone. 1167 * If the input has a chronology then it will be retained unless overridden. 1168 * If the input does not have a chronology, such as {@code Instant}, then 1169 * the ISO chronology will be used. 1170 * The converted result will behave in a manner equivalent to an implementation 1171 * of {@code ChronoZonedDateTime}. 1172 * <p> 1173 * When parsing, the override zone will be used to interpret the 1174 * {@linkplain ChronoField fields} into an instant unless the 1175 * formatter directly parses a valid zone. 1176 * <p> 1177 * This instance is immutable and unaffected by this method call. 1178 * 1179 * @param zone the new override zone, not null 1180 * @return a formatter based on this formatter with the requested override zone, not null 1181 */ withZone(ZoneId zone)1182 public DateTimeFormatter withZone(ZoneId zone) { 1183 if (Jdk8Methods.equals(this.zone, zone)) { 1184 return this; 1185 } 1186 return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone); 1187 } 1188 1189 //----------------------------------------------------------------------- 1190 /** 1191 * Gets the resolver style to use during parsing. 1192 * <p> 1193 * This returns the resolver style, used during the second phase of parsing 1194 * when fields are resolved into dates and times. 1195 * By default, a formatter has the {@link ResolverStyle#SMART SMART} resolver style. 1196 * See {@link #withResolverStyle(ResolverStyle)} for more details. 1197 * 1198 * @return the resolver style of this formatter, not null 1199 */ getResolverStyle()1200 public ResolverStyle getResolverStyle() { 1201 return resolverStyle; 1202 } 1203 1204 /** 1205 * Returns a copy of this formatter with a new resolver style. 1206 * <p> 1207 * This returns a formatter with similar state to this formatter but 1208 * with the resolver style set. By default, a formatter has the 1209 * {@link ResolverStyle#SMART SMART} resolver style. 1210 * <p> 1211 * Changing the resolver style only has an effect during parsing. 1212 * Parsing a text string occurs in two phases. 1213 * Phase 1 is a basic text parse according to the fields added to the builder. 1214 * Phase 2 resolves the parsed field-value pairs into date and/or time objects. 1215 * The resolver style is used to control how phase 2, resolving, happens. 1216 * See {@code ResolverStyle} for more information on the options available. 1217 * <p> 1218 * This instance is immutable and unaffected by this method call. 1219 * 1220 * @param resolverStyle the new resolver style, not null 1221 * @return a formatter based on this formatter with the requested resolver style, not null 1222 */ withResolverStyle(ResolverStyle resolverStyle)1223 public DateTimeFormatter withResolverStyle(ResolverStyle resolverStyle) { 1224 Jdk8Methods.requireNonNull(resolverStyle, "resolverStyle"); 1225 if (Jdk8Methods.equals(this.resolverStyle, resolverStyle)) { 1226 return this; 1227 } 1228 return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone); 1229 } 1230 1231 //----------------------------------------------------------------------- 1232 /** 1233 * Gets the resolver fields to use during parsing. 1234 * <p> 1235 * This returns the resolver fields, used during the second phase of parsing 1236 * when fields are resolved into dates and times. 1237 * By default, a formatter has no resolver fields, and thus returns null. 1238 * See {@link #withResolverFields(Set)} for more details. 1239 * 1240 * @return the immutable set of resolver fields of this formatter, null if no fields 1241 */ getResolverFields()1242 public Set<TemporalField> getResolverFields() { 1243 return resolverFields; 1244 } 1245 1246 /** 1247 * Returns a copy of this formatter with a new set of resolver fields. 1248 * <p> 1249 * This returns a formatter with similar state to this formatter but with 1250 * the resolver fields set. By default, a formatter has no resolver fields. 1251 * <p> 1252 * Changing the resolver fields only has an effect during parsing. 1253 * Parsing a text string occurs in two phases. 1254 * Phase 1 is a basic text parse according to the fields added to the builder. 1255 * Phase 2 resolves the parsed field-value pairs into date and/or time objects. 1256 * The resolver fields are used to filter the field-value pairs between phase 1 and 2. 1257 * <p> 1258 * This can be used to select between two or more ways that a date or time might 1259 * be resolved. For example, if the formatter consists of year, month, day-of-month 1260 * and day-of-year, then there are two ways to resolve a date. 1261 * Calling this method with the arguments {@link ChronoField#YEAR YEAR} and 1262 * {@link ChronoField#DAY_OF_YEAR DAY_OF_YEAR} will ensure that the date is 1263 * resolved using the year and day-of-year, effectively meaning that the month 1264 * and day-of-month are ignored during the resolving phase. 1265 * <p> 1266 * In a similar manner, this method can be used to ignore secondary fields that 1267 * would otherwise be cross-checked. For example, if the formatter consists of year, 1268 * month, day-of-month and day-of-week, then there is only one way to resolve a 1269 * date, but the parsed value for day-of-week will be cross-checked against the 1270 * resolved date. Calling this method with the arguments {@link ChronoField#YEAR YEAR}, 1271 * {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and 1272 * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} will ensure that the date is 1273 * resolved correctly, but without any cross-check for the day-of-week. 1274 * <p> 1275 * In implementation terms, this method behaves as follows. The result of the 1276 * parsing phase can be considered to be a map of field to value. The behavior 1277 * of this method is to cause that map to be filtered between phase 1 and 2, 1278 * removing all fields other than those specified as arguments to this method. 1279 * <p> 1280 * This instance is immutable and unaffected by this method call. 1281 * 1282 * @param resolverFields the new set of resolver fields, null if no fields 1283 * @return a formatter based on this formatter with the requested resolver style, not null 1284 */ withResolverFields(TemporalField... resolverFields)1285 public DateTimeFormatter withResolverFields(TemporalField... resolverFields) { 1286 if (resolverFields == null) { 1287 return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, null, chrono, zone); 1288 } 1289 Set<TemporalField> fields = new HashSet<TemporalField>(Arrays.asList(resolverFields)); 1290 if (Jdk8Methods.equals(this.resolverFields, fields)) { 1291 return this; 1292 } 1293 fields = Collections.unmodifiableSet(fields); 1294 return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, fields, chrono, zone); 1295 } 1296 1297 /** 1298 * Returns a copy of this formatter with a new set of resolver fields. 1299 * <p> 1300 * This returns a formatter with similar state to this formatter but with 1301 * the resolver fields set. By default, a formatter has no resolver fields. 1302 * <p> 1303 * Changing the resolver fields only has an effect during parsing. 1304 * Parsing a text string occurs in two phases. 1305 * Phase 1 is a basic text parse according to the fields added to the builder. 1306 * Phase 2 resolves the parsed field-value pairs into date and/or time objects. 1307 * The resolver fields are used to filter the field-value pairs between phase 1 and 2. 1308 * <p> 1309 * This can be used to select between two or more ways that a date or time might 1310 * be resolved. For example, if the formatter consists of year, month, day-of-month 1311 * and day-of-year, then there are two ways to resolve a date. 1312 * Calling this method with the arguments {@link ChronoField#YEAR YEAR} and 1313 * {@link ChronoField#DAY_OF_YEAR DAY_OF_YEAR} will ensure that the date is 1314 * resolved using the year and day-of-year, effectively meaning that the month 1315 * and day-of-month are ignored during the resolving phase. 1316 * <p> 1317 * In a similar manner, this method can be used to ignore secondary fields that 1318 * would otherwise be cross-checked. For example, if the formatter consists of year, 1319 * month, day-of-month and day-of-week, then there is only one way to resolve a 1320 * date, but the parsed value for day-of-week will be cross-checked against the 1321 * resolved date. Calling this method with the arguments {@link ChronoField#YEAR YEAR}, 1322 * {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and 1323 * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} will ensure that the date is 1324 * resolved correctly, but without any cross-check for the day-of-week. 1325 * <p> 1326 * In implementation terms, this method behaves as follows. The result of the 1327 * parsing phase can be considered to be a map of field to value. The behavior 1328 * of this method is to cause that map to be filtered between phase 1 and 2, 1329 * removing all fields other than those specified as arguments to this method. 1330 * <p> 1331 * This instance is immutable and unaffected by this method call. 1332 * 1333 * @param resolverFields the new set of resolver fields, null if no fields 1334 * @return a formatter based on this formatter with the requested resolver style, not null 1335 */ withResolverFields(Set<TemporalField> resolverFields)1336 public DateTimeFormatter withResolverFields(Set<TemporalField> resolverFields) { 1337 if (resolverFields == null) { 1338 return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, null, chrono, zone); 1339 } 1340 if (Jdk8Methods.equals(this.resolverFields, resolverFields)) { 1341 return this; 1342 } 1343 resolverFields = Collections.unmodifiableSet(new HashSet<TemporalField>(resolverFields)); 1344 return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone); 1345 } 1346 1347 //----------------------------------------------------------------------- 1348 /** 1349 * Formats a date-time object using this formatter. 1350 * <p> 1351 * This formats the date-time to a String using the rules of the formatter. 1352 * 1353 * @param temporal the temporal object to print, not null 1354 * @return the printed string, not null 1355 * @throws DateTimeException if an error occurs during formatting 1356 */ format(TemporalAccessor temporal)1357 public String format(TemporalAccessor temporal) { 1358 StringBuilder buf = new StringBuilder(32); 1359 formatTo(temporal, buf); 1360 return buf.toString(); 1361 } 1362 1363 //----------------------------------------------------------------------- 1364 /** 1365 * Formats a date-time object to an {@code Appendable} using this formatter. 1366 * <p> 1367 * This formats the date-time to the specified destination. 1368 * {@link Appendable} is a general purpose interface that is implemented by all 1369 * key character output classes including {@code StringBuffer}, {@code StringBuilder}, 1370 * {@code PrintStream} and {@code Writer}. 1371 * <p> 1372 * Although {@code Appendable} methods throw an {@code IOException}, this method does not. 1373 * Instead, any {@code IOException} is wrapped in a runtime exception. 1374 * 1375 * @param temporal the temporal object to print, not null 1376 * @param appendable the appendable to print to, not null 1377 * @throws DateTimeException if an error occurs during formatting 1378 */ formatTo(TemporalAccessor temporal, Appendable appendable)1379 public void formatTo(TemporalAccessor temporal, Appendable appendable) { 1380 Jdk8Methods.requireNonNull(temporal, "temporal"); 1381 Jdk8Methods.requireNonNull(appendable, "appendable"); 1382 try { 1383 DateTimePrintContext context = new DateTimePrintContext(temporal, this); 1384 if (appendable instanceof StringBuilder) { 1385 printerParser.print(context, (StringBuilder) appendable); 1386 } else { 1387 // buffer output to avoid writing to appendable in case of error 1388 StringBuilder buf = new StringBuilder(32); 1389 printerParser.print(context, buf); 1390 appendable.append(buf); 1391 } 1392 } catch (IOException ex) { 1393 throw new DateTimeException(ex.getMessage(), ex); 1394 } 1395 } 1396 1397 //----------------------------------------------------------------------- 1398 /** 1399 * Fully parses the text producing a temporal object. 1400 * <p> 1401 * This parses the entire text producing a temporal object. 1402 * It is typically more useful to use {@link #parse(CharSequence, TemporalQuery)}. 1403 * The result of this method is {@code TemporalAccessor} which has been resolved, 1404 * applying basic validation checks to help ensure a valid date-time. 1405 * <p> 1406 * If the parse completes without reading the entire length of the text, 1407 * or a problem occurs during parsing or merging, then an exception is thrown. 1408 * 1409 * @param text the text to parse, not null 1410 * @return the parsed temporal object, not null 1411 * @throws DateTimeParseException if unable to parse the requested result 1412 */ parse(CharSequence text)1413 public TemporalAccessor parse(CharSequence text) { 1414 Jdk8Methods.requireNonNull(text, "text"); 1415 try { 1416 return parseToBuilder(text, null).resolve(resolverStyle, resolverFields); 1417 } catch (DateTimeParseException ex) { 1418 throw ex; 1419 } catch (RuntimeException ex) { 1420 throw createError(text, ex); 1421 } 1422 } 1423 1424 /** 1425 * Parses the text using this formatter, providing control over the text position. 1426 * <p> 1427 * This parses the text without requiring the parse to start from the beginning 1428 * of the string or finish at the end. 1429 * The result of this method is {@code TemporalAccessor} which has been resolved, 1430 * applying basic validation checks to help ensure a valid date-time. 1431 * <p> 1432 * The text will be parsed from the specified start {@code ParsePosition}. 1433 * The entire length of the text does not have to be parsed, the {@code ParsePosition} 1434 * will be updated with the index at the end of parsing. 1435 * <p> 1436 * The operation of this method is slightly different to similar methods using 1437 * {@code ParsePosition} on {@code java.text.Format}. That class will return 1438 * errors using the error index on the {@code ParsePosition}. By contrast, this 1439 * method will throw a {@link DateTimeParseException} if an error occurs, with 1440 * the exception containing the error index. 1441 * This change in behavior is necessary due to the increased complexity of 1442 * parsing and resolving dates/times in this API. 1443 * <p> 1444 * If the formatter parses the same field more than once with different values, 1445 * the result will be an error. 1446 * 1447 * @param text the text to parse, not null 1448 * @param position the position to parse from, updated with length parsed 1449 * and the index of any error, not null 1450 * @return the parsed temporal object, not null 1451 * @throws DateTimeParseException if unable to parse the requested result 1452 * @throws IndexOutOfBoundsException if the position is invalid 1453 */ parse(CharSequence text, ParsePosition position)1454 public TemporalAccessor parse(CharSequence text, ParsePosition position) { 1455 Jdk8Methods.requireNonNull(text, "text"); 1456 Jdk8Methods.requireNonNull(position, "position"); 1457 try { 1458 return parseToBuilder(text, position).resolve(resolverStyle, resolverFields); 1459 } catch (DateTimeParseException ex) { 1460 throw ex; 1461 } catch (IndexOutOfBoundsException ex) { 1462 throw ex; 1463 } catch (RuntimeException ex) { 1464 throw createError(text, ex); 1465 } 1466 } 1467 1468 //----------------------------------------------------------------------- 1469 /** 1470 * Fully parses the text producing an object of the specified type. 1471 * <p> 1472 * Most applications should use this method for parsing. 1473 * It parses the entire text to produce the required date-time. 1474 * For example: 1475 * <pre> 1476 * LocalDateTime dt = parser.parse(str, LocalDateTime.FROM); 1477 * </pre> 1478 * If the parse completes without reading the entire length of the text, 1479 * or a problem occurs during parsing or merging, then an exception is thrown. 1480 * 1481 * @param <T> the type to extract 1482 * @param text the text to parse, not null 1483 * @param type the type to extract, not null 1484 * @return the parsed date-time, not null 1485 * @throws DateTimeParseException if unable to parse the requested result 1486 */ parse(CharSequence text, TemporalQuery<T> type)1487 public <T> T parse(CharSequence text, TemporalQuery<T> type) { 1488 Jdk8Methods.requireNonNull(text, "text"); 1489 Jdk8Methods.requireNonNull(type, "type"); 1490 try { 1491 DateTimeBuilder builder = parseToBuilder(text, null).resolve(resolverStyle, resolverFields); 1492 return builder.build(type); 1493 } catch (DateTimeParseException ex) { 1494 throw ex; 1495 } catch (RuntimeException ex) { 1496 throw createError(text, ex); 1497 } 1498 } 1499 1500 /** 1501 * Fully parses the text producing an object of one of the specified types. 1502 * <p> 1503 * This parse method is convenient for use when the parser can handle optional elements. 1504 * For example, a pattern of 'yyyy[-MM[-dd]]' can be fully parsed to a {@code LocalDate}, 1505 * or partially parsed to a {@code YearMonth} or a {@code Year}. 1506 * The types must be specified in order, starting from the best matching full-parse option 1507 * and ending with the worst matching minimal parse option. 1508 * <p> 1509 * The result is associated with the first type that successfully parses. 1510 * Normally, applications will use {@code instanceof} to check the result. 1511 * For example: 1512 * <pre> 1513 * TemporalAccessor dt = parser.parseBest(str, LocalDate.FROM, YearMonth.FROM); 1514 * if (dt instanceof LocalDate) { 1515 * ... 1516 * } else { 1517 * ... 1518 * } 1519 * </pre> 1520 * If the parse completes without reading the entire length of the text, 1521 * or a problem occurs during parsing or merging, then an exception is thrown. 1522 * 1523 * @param text the text to parse, not null 1524 * @param types the types to attempt to parse to, which must implement {@code TemporalAccessor}, not null 1525 * @return the parsed date-time, not null 1526 * @throws IllegalArgumentException if less than 2 types are specified 1527 * @throws DateTimeParseException if unable to parse the requested result 1528 */ parseBest(CharSequence text, TemporalQuery<?>... types)1529 public TemporalAccessor parseBest(CharSequence text, TemporalQuery<?>... types) { 1530 Jdk8Methods.requireNonNull(text, "text"); 1531 Jdk8Methods.requireNonNull(types, "types"); 1532 if (types.length < 2) { 1533 throw new IllegalArgumentException("At least two types must be specified"); 1534 } 1535 try { 1536 DateTimeBuilder builder = parseToBuilder(text, null).resolve(resolverStyle, resolverFields); 1537 for (TemporalQuery<?> type : types) { 1538 try { 1539 return (TemporalAccessor) builder.build(type); 1540 } catch (RuntimeException ex) { 1541 // continue 1542 } 1543 } 1544 throw new DateTimeException("Unable to convert parsed text to any specified type: " + Arrays.toString(types)); 1545 } catch (DateTimeParseException ex) { 1546 throw ex; 1547 } catch (RuntimeException ex) { 1548 throw createError(text, ex); 1549 } 1550 } 1551 createError(CharSequence text, RuntimeException ex)1552 private DateTimeParseException createError(CharSequence text, RuntimeException ex) { 1553 String abbr = ""; 1554 if (text.length() > 64) { 1555 abbr = text.subSequence(0, 64).toString() + "..."; 1556 } else { 1557 abbr = text.toString(); 1558 } 1559 return new DateTimeParseException("Text '" + abbr + "' could not be parsed: " + ex.getMessage(), text, 0, ex); 1560 } 1561 1562 //----------------------------------------------------------------------- 1563 /** 1564 * Parses the text to a builder. 1565 * <p> 1566 * This parses to a {@code DateTimeBuilder} ensuring that the text is fully parsed. 1567 * This method throws {@link DateTimeParseException} if unable to parse, or 1568 * some other {@code DateTimeException} if another date/time problem occurs. 1569 * 1570 * @param text the text to parse, not null 1571 * @param position the position to parse from, updated with length parsed 1572 * and the index of any error, null if parsing whole string 1573 * @return the engine representing the result of the parse, not null 1574 * @throws DateTimeParseException if the parse fails 1575 */ parseToBuilder(final CharSequence text, final ParsePosition position)1576 private DateTimeBuilder parseToBuilder(final CharSequence text, final ParsePosition position) { 1577 ParsePosition pos = (position != null ? position : new ParsePosition(0)); 1578 Parsed result = parseUnresolved0(text, pos); 1579 if (result == null || pos.getErrorIndex() >= 0 || (position == null && pos.getIndex() < text.length())) { 1580 String abbr = ""; 1581 if (text.length() > 64) { 1582 abbr = text.subSequence(0, 64).toString() + "..."; 1583 } else { 1584 abbr = text.toString(); 1585 } 1586 if (pos.getErrorIndex() >= 0) { 1587 throw new DateTimeParseException("Text '" + abbr + "' could not be parsed at index " + 1588 pos.getErrorIndex(), text, pos.getErrorIndex()); 1589 } else { 1590 throw new DateTimeParseException("Text '" + abbr + "' could not be parsed, unparsed text found at index " + 1591 pos.getIndex(), text, pos.getIndex()); 1592 } 1593 } 1594 return result.toBuilder(); 1595 } 1596 1597 /** 1598 * Parses the text using this formatter, without resolving the result, intended 1599 * for advanced use cases. 1600 * <p> 1601 * Parsing is implemented as a two-phase operation. 1602 * First, the text is parsed using the layout defined by the formatter, producing 1603 * a {@code Map} of field to value, a {@code ZoneId} and a {@code Chronology}. 1604 * Second, the parsed data is <em>resolved</em>, by validating, combining and 1605 * simplifying the various fields into more useful ones. 1606 * This method performs the parsing stage but not the resolving stage. 1607 * <p> 1608 * The result of this method is {@code TemporalAccessor} which represents the 1609 * data as seen in the input. Values are not validated, thus parsing a date string 1610 * of '2012-00-65' would result in a temporal with three fields - year of '2012', 1611 * month of '0' and day-of-month of '65'. 1612 * <p> 1613 * The text will be parsed from the specified start {@code ParsePosition}. 1614 * The entire length of the text does not have to be parsed, the {@code ParsePosition} 1615 * will be updated with the index at the end of parsing. 1616 * <p> 1617 * Errors are returned using the error index field of the {@code ParsePosition} 1618 * instead of {@code DateTimeParseException}. 1619 * The returned error index will be set to an index indicative of the error. 1620 * Callers must check for errors before using the context. 1621 * <p> 1622 * If the formatter parses the same field more than once with different values, 1623 * the result will be an error. 1624 * <p> 1625 * This method is intended for advanced use cases that need access to the 1626 * internal state during parsing. Typical application code should use 1627 * {@link #parse(CharSequence, TemporalQuery)} or the parse method on the target type. 1628 * 1629 * @param text the text to parse, not null 1630 * @param position the position to parse from, updated with length parsed 1631 * and the index of any error, not null 1632 * @return the parsed text, null if the parse results in an error 1633 * @throws DateTimeException if some problem occurs during parsing 1634 * @throws IndexOutOfBoundsException if the position is invalid 1635 */ parseUnresolved(CharSequence text, ParsePosition position)1636 public TemporalAccessor parseUnresolved(CharSequence text, ParsePosition position) { 1637 return parseUnresolved0(text, position); 1638 } 1639 parseUnresolved0(CharSequence text, ParsePosition position)1640 private Parsed parseUnresolved0(CharSequence text, ParsePosition position) { 1641 Jdk8Methods.requireNonNull(text, "text"); 1642 Jdk8Methods.requireNonNull(position, "position"); 1643 DateTimeParseContext context = new DateTimeParseContext(this); 1644 int pos = position.getIndex(); 1645 pos = printerParser.parse(context, text, pos); 1646 if (pos < 0) { 1647 position.setErrorIndex(~pos); // index not updated from input 1648 return null; 1649 } 1650 position.setIndex(pos); // errorIndex not updated from input 1651 return context.toParsed(); 1652 } 1653 1654 //----------------------------------------------------------------------- 1655 /** 1656 * Returns the formatter as a composite printer parser. 1657 * 1658 * @param optional whether the printer/parser should be optional 1659 * @return the printer/parser, not null 1660 */ toPrinterParser(boolean optional)1661 CompositePrinterParser toPrinterParser(boolean optional) { 1662 return printerParser.withOptional(optional); 1663 } 1664 1665 /** 1666 * Returns this formatter as a {@code java.text.Format} instance. 1667 * <p> 1668 * The returned {@link Format} instance will print any {@link TemporalAccessor} 1669 * and parses to a resolved {@link TemporalAccessor}. 1670 * <p> 1671 * Exceptions will follow the definitions of {@code Format}, see those methods 1672 * for details about {@code IllegalArgumentException} during formatting and 1673 * {@code ParseException} or null during parsing. 1674 * The format does not support attributing of the returned format string. 1675 * 1676 * @return this formatter as a classic format instance, not null 1677 */ toFormat()1678 public Format toFormat() { 1679 return new ClassicFormat(this, null); 1680 } 1681 1682 /** 1683 * Returns this formatter as a {@code java.text.Format} instance that will 1684 * parse to the specified type. 1685 * <p> 1686 * The returned {@link Format} instance will print any {@link TemporalAccessor} 1687 * and parses to the type specified. 1688 * The type must be one that is supported by {@link #parse}. 1689 * <p> 1690 * Exceptions will follow the definitions of {@code Format}, see those methods 1691 * for details about {@code IllegalArgumentException} during formatting and 1692 * {@code ParseException} or null during parsing. 1693 * The format does not support attributing of the returned format string. 1694 * 1695 * @param query the query to parse to, not null 1696 * @return this formatter as a classic format instance, not null 1697 */ toFormat(TemporalQuery<?> query)1698 public Format toFormat(TemporalQuery<?> query) { 1699 Jdk8Methods.requireNonNull(query, "query"); 1700 return new ClassicFormat(this, query); 1701 } 1702 1703 //----------------------------------------------------------------------- 1704 /** 1705 * Returns a description of the underlying formatters. 1706 * 1707 * @return a description of this formatter, not null 1708 */ 1709 @Override toString()1710 public String toString() { 1711 String pattern = printerParser.toString(); 1712 return pattern.startsWith("[") ? pattern : pattern.substring(1, pattern.length() - 1); 1713 } 1714 1715 //----------------------------------------------------------------------- 1716 /** 1717 * Implements the classic Java Format API. 1718 * @serial exclude 1719 */ 1720 @SuppressWarnings("serial") // not actually serializable 1721 static class ClassicFormat extends Format { 1722 /** The formatter. */ 1723 private final DateTimeFormatter formatter; 1724 /** The query to be parsed. */ 1725 private final TemporalQuery<?> query; 1726 /** Constructor. */ ClassicFormat(DateTimeFormatter formatter, TemporalQuery<?> query)1727 public ClassicFormat(DateTimeFormatter formatter, TemporalQuery<?> query) { 1728 this.formatter = formatter; 1729 this.query = query; 1730 } 1731 1732 @Override format(Object obj, StringBuffer toAppendTo, FieldPosition pos)1733 public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { 1734 Jdk8Methods.requireNonNull(obj, "obj"); 1735 Jdk8Methods.requireNonNull(toAppendTo, "toAppendTo"); 1736 Jdk8Methods.requireNonNull(pos, "pos"); 1737 if (obj instanceof TemporalAccessor == false) { 1738 throw new IllegalArgumentException("Format target must implement TemporalAccessor"); 1739 } 1740 pos.setBeginIndex(0); 1741 pos.setEndIndex(0); 1742 try { 1743 formatter.formatTo((TemporalAccessor) obj, toAppendTo); 1744 } catch (RuntimeException ex) { 1745 throw new IllegalArgumentException(ex.getMessage(), ex); 1746 } 1747 return toAppendTo; 1748 } 1749 @Override parseObject(String text)1750 public Object parseObject(String text) throws ParseException { 1751 Jdk8Methods.requireNonNull(text, "text"); 1752 try { 1753 if (query == null) { 1754 return formatter.parseToBuilder(text, null) 1755 .resolve(formatter.getResolverStyle(), formatter.getResolverFields()); 1756 } 1757 return formatter.parse(text, query); 1758 } catch (DateTimeParseException ex) { 1759 throw new ParseException(ex.getMessage(), ex.getErrorIndex()); 1760 } catch (RuntimeException ex) { 1761 throw (ParseException) new ParseException(ex.getMessage(), 0).initCause(ex); 1762 } 1763 } 1764 @Override parseObject(String text, ParsePosition pos)1765 public Object parseObject(String text, ParsePosition pos) { 1766 Jdk8Methods.requireNonNull(text, "text"); 1767 Parsed unresolved; 1768 try { 1769 unresolved = formatter.parseUnresolved0(text, pos); 1770 } catch (IndexOutOfBoundsException ex) { 1771 if (pos.getErrorIndex() < 0) { 1772 pos.setErrorIndex(0); 1773 } 1774 return null; 1775 } 1776 if (unresolved == null) { 1777 if (pos.getErrorIndex() < 0) { 1778 pos.setErrorIndex(0); 1779 } 1780 return null; 1781 } 1782 try { 1783 DateTimeBuilder builder = unresolved.toBuilder() 1784 .resolve(formatter.getResolverStyle(), formatter.getResolverFields()); 1785 if (query == null) { 1786 return builder; 1787 } 1788 return builder.build(query); 1789 } catch (RuntimeException ex) { 1790 pos.setErrorIndex(0); 1791 return null; 1792 } 1793 } 1794 } 1795 1796 } 1797