1 /*
   2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  * This file is available under and governed by the GNU General Public
  28  * License version 2 only, as published by the Free Software Foundation.
  29  * However, the following notice accompanied the original version of this
  30  * file:
  31  *
  32  * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
  33  *
  34  * All rights reserved.
  35  *
  36  * Redistribution and use in source and binary forms, with or without
  37  * modification, are permitted provided that the following conditions are met:
  38  *
  39  *  * Redistributions of source code must retain the above copyright notice,
  40  *    this list of conditions and the following disclaimer.
  41  *
  42  *  * Redistributions in binary form must reproduce the above copyright notice,
  43  *    this list of conditions and the following disclaimer in the documentation
  44  *    and/or other materials provided with the distribution.
  45  *
  46  *  * Neither the name of JSR-310 nor the names of its contributors
  47  *    may be used to endorse or promote products derived from this software
  48  *    without specific prior written permission.
  49  *
  50  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  51  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  52  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  53  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  54  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  55  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  56  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  57  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  58  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  59  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  60  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61  */
  62 package java.time.format;
  63 
  64 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
  65 import static java.time.temporal.ChronoField.DAY_OF_WEEK;
  66 import static java.time.temporal.ChronoField.DAY_OF_YEAR;
  67 import static java.time.temporal.ChronoField.HOUR_OF_DAY;
  68 import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
  69 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
  70 import static java.time.temporal.ChronoField.NANO_OF_SECOND;
  71 import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
  72 import static java.time.temporal.ChronoField.YEAR;
  73 
  74 import java.time.ZoneId;
  75 import java.time.ZoneOffset;
  76 import java.time.temporal.ChronoField;
  77 import java.time.temporal.ISOFields;
  78 import java.util.HashMap;
  79 import java.util.Locale;
  80 import java.util.Map;
  81 import java.util.Objects;
  82 
  83 /**
  84  * Provides common implementations of {@code DateTimeFormatter}.
  85  * <p>
  86  * This utility class provides three different ways to obtain a formatter.
  87  * <p><ul>
  88  * <li>Using pattern letters, such as {@code yyyy-MMM-dd}
  89  * <li>Using localized styles, such as {@code long} or {@code medium}
  90  * <li>Using predefined constants, such as {@code isoLocalDate()}
  91  * </ul><p>
  92  *
  93  * <h3>Specification for implementors</h3>
  94  * This is a thread-safe utility class.
  95  * All returned formatters are immutable and thread-safe.
  96  *
  97  * @since 1.8
  98  */
  99 public final class DateTimeFormatters {
 100 
 101     /**
 102      * Private constructor since this is a utility class.
 103      */
 104     private DateTimeFormatters() {
 105     }
 106 
 107     //-----------------------------------------------------------------------
 108     /**
 109      * Creates a formatter using the specified pattern.
 110      * <p>
 111      * This method will create a formatter based on a simple pattern of letters and symbols.
 112      * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'.
 113      * <p>
 114      * The returned formatter will use the default locale, but this can be changed
 115      * using {@link DateTimeFormatter#withLocale(Locale)}.
 116      * <p>
 117      * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters.
 118      * The following pattern letters are defined:
 119      * <pre>
 120      *  Symbol  Meaning                     Presentation      Examples
 121      *  ------  -------                     ------------      -------
 122      *   G       era                         number/text       1; 01; AD; Anno Domini
 123      *   y       year                        year              2004; 04
 124      *   D       day-of-year                 number            189
 125      *   M       month-of-year               number/text       7; 07; Jul; July; J
 126      *   d       day-of-month                number            10
 127      *
 128      *   Q       quarter-of-year             number/text       3; 03; Q3
 129      *   Y       week-based-year             year              1996; 96
 130      *   w       week-of-year                number            27
 131      *   W       week-of-month               number            27
 132      *   e       localized day-of-week       number            2; Tue; Tuesday; T
 133      *   E       day-of-week                 number/text       2; Tue; Tuesday; T
 134      *   F       week-of-month               number            3
 135      *
 136      *   a       am-pm-of-day                text              PM
 137      *   h       clock-hour-of-am-pm (1-12)  number            12
 138      *   K       hour-of-am-pm (0-11)        number            0
 139      *   k       clock-hour-of-am-pm (1-24)  number            0
 140      *
 141      *   H       hour-of-day (0-23)          number            0
 142      *   m       minute-of-hour              number            30
 143      *   s       second-of-minute            number            55
 144      *   S       fraction-of-second          fraction          978
 145      *   A       milli-of-day                number            1234
 146      *   n       nano-of-second              number            987654321
 147      *   N       nano-of-day                 number            1234000000
 148      *
 149      *   I       time-zone ID                zoneId            America/Los_Angeles
 150      *   z       time-zone name              text              Pacific Standard Time; PST
 151      *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
 152      *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
 153      *
 154      *   p       pad next                    pad modifier      1
 155      *
 156      *   '       escape for text             delimiter
 157      *   ''      single quote                literal           '
 158      *   [       optional section start
 159      *   ]       optional section end
 160      *   {}      reserved for future use
 161      * </pre>
 162      * <p>
 163      * The count of pattern letters determine the format.
 164      * <p>
 165      * <b>Text</b>: The text style is determined based on the number of pattern letters used.
 166      * Less than 4 pattern letters will use the {@link TextStyle#SHORT short form}.
 167      * Exactly 4 pattern letters will use the {@link TextStyle#FULL full form}.
 168      * Exactly 5 pattern letters will use the {@link TextStyle#NARROW narrow form}.
 169      * <p>
 170      * <b>Number</b>: If the count of letters is one, then the value is printed using the minimum number
 171      * of digits and without padding as per {@link DateTimeFormatterBuilder#appendValue(java.time.temporal.TemporalField)}.
 172      * Otherwise, the count of digits is used as the width of the output field as per
 173      * {@link DateTimeFormatterBuilder#appendValue(java.time.temporal.TemporalField, int)}.
 174      * <p>
 175      * <b>Number/Text</b>: If the count of pattern letters is 3 or greater, use the Text rules above.
 176      * Otherwise use the Number rules above.
 177      * <p>
 178      * <b>Fraction</b>: Outputs the nano-of-second field as a fraction-of-second.
 179      * The nano-of-second value has nine digits, thus the count of pattern letters is from 1 to 9.
 180      * If it is less than 9, then the nano-of-second value is truncated, with only the most
 181      * significant digits being output.
 182      * When parsing in strict mode, the number of parsed digits must match the count of pattern letters.
 183      * When parsing in lenient mode, the number of parsed digits must be at least the count of pattern
 184      * letters, up to 9 digits.
 185      * <p>
 186      * <b>Year</b>: The count of letters determines the minimum field width below which padding is used.
 187      * If the count of letters is two, then a {@link DateTimeFormatterBuilder#appendValueReduced reduced}
 188      * two digit form is used.
 189      * For printing, this outputs the rightmost two digits. For parsing, this will parse using the
 190      * base value of 2000, resulting in a year within the range 2000 to 2099 inclusive.
 191      * If the count of letters is less than four (but not two), then the sign is only output for negative
 192      * years as per {@link SignStyle#NORMAL}.
 193      * Otherwise, the sign is output if the pad width is exceeded, as per {@link SignStyle#EXCEEDS_PAD}
 194      * <p>
 195      * <b>ZoneId</b>: 'I' outputs the zone ID, such as 'Europe/Paris'.
 196      * <p>
 197      * <b>Offset X</b>: This formats the offset using 'Z' when the offset is zero.
 198      * One letter outputs just the hour', such as '+01'
 199      * Two letters outputs the hour and minute, without a colon, such as '+0130'.
 200      * Three letters outputs the hour and minute, with a colon, such as '+01:30'.
 201      * Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'.
 202      * Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'.
 203      * <p>
 204      * <b>Offset Z</b>: This formats the offset using '+0000' or '+00:00' when the offset is zero.
 205      * One or two letters outputs the hour and minute, without a colon, such as '+0130'.
 206      * Three letters outputs the hour and minute, with a colon, such as '+01:30'.
 207      * <p>
 208      * <b>Zone names</b>: Time zone names ('z') cannot be parsed.
 209      * <p>
 210      * <b>Optional section</b>: The optional section markers work exactly like calling
 211      * {@link DateTimeFormatterBuilder#optionalStart()} and {@link DateTimeFormatterBuilder#optionalEnd()}.
 212      * <p>
 213      * <b>Pad modifier</b>: Modifies the pattern that immediately follows to be padded with spaces.
 214      * The pad width is determined by the number of pattern letters.
 215      * This is the same as calling {@link DateTimeFormatterBuilder#padNext(int)}.
 216      * <p>
 217      * For example, 'ppH' outputs the hour-of-day padded on the left with spaces to a width of 2.
 218      * <p>
 219      * Any unrecognized letter is an error.
 220      * Any non-letter character, other than '[', ']', '{', '}' and the single quote will be output directly.
 221      * Despite this, it is recommended to use single quotes around all characters that you want to
 222      * output directly to ensure that future changes do not break your application.
 223      * <p>
 224      * The pattern string is similar, but not identical, to {@link java.text.SimpleDateFormat SimpleDateFormat}.
 225      * Pattern letters 'E' and 'u' are merged, which changes the meaning of "E" and "EE" to be numeric.
 226      * Pattern letters 'Z' and 'X' are extended.
 227      * Pattern letter 'y' and 'Y' parse years of two digits and more than 4 digits differently.
 228      * Pattern letters 'n', 'A', 'N', 'I' and 'p' are added.
 229      * Number types will reject large numbers.
 230      * The pattern string is also similar, but not identical, to that defined by the
 231      * Unicode Common Locale Data Repository (CLDR).
 232      *
 233      * @param pattern  the pattern to use, not null
 234      * @return the formatter based on the pattern, not null
 235      * @throws IllegalArgumentException if the pattern is invalid
 236      * @see DateTimeFormatterBuilder#appendPattern(String)
 237      */
 238     public static DateTimeFormatter pattern(String pattern) {
 239         return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter();
 240     }
 241 
 242     /**
 243      * Creates a formatter using the specified pattern.
 244      * <p>
 245      * This method will create a formatter based on a simple pattern of letters and symbols.
 246      * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'.
 247      * <p>
 248      * See {@link #pattern(String)} for details of the pattern.
 249      * <p>
 250      * The returned formatter will use the specified locale, but this can be changed
 251      * using {@link DateTimeFormatter#withLocale(Locale)}.
 252      *
 253      * @param pattern  the pattern to use, not null
 254      * @param locale  the locale to use, not null
 255      * @return the formatter based on the pattern, not null
 256      * @throws IllegalArgumentException if the pattern is invalid
 257      * @see DateTimeFormatterBuilder#appendPattern(String)
 258      */
 259     public static DateTimeFormatter pattern(String pattern, Locale locale) {
 260         return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale);
 261     }
 262 
 263     //-----------------------------------------------------------------------
 264     /**
 265      * Returns a locale specific date format.
 266      * <p>
 267      * This returns a formatter that will print/parse a date.
 268      * The exact format pattern used varies by locale.
 269      * <p>
 270      * The locale is determined from the formatter. The formatter returned directly by
 271      * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}.
 272      * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)}
 273      * on the result of this method.
 274      * <p>
 275      * Note that the localized pattern is looked up lazily.
 276      * This {@code DateTimeFormatter} holds the style required and the locale,
 277      * looking up the pattern required on demand.
 278      *
 279      * @param dateStyle  the formatter style to obtain, not null
 280      * @return the date formatter, not null
 281      */
 282     public static DateTimeFormatter localizedDate(FormatStyle dateStyle) {
 283         Objects.requireNonNull(dateStyle, "dateStyle");
 284         return new DateTimeFormatterBuilder().appendLocalized(dateStyle, null).toFormatter();
 285     }
 286 
 287     /**
 288      * Returns a locale specific time format.
 289      * <p>
 290      * This returns a formatter that will print/parse a time.
 291      * The exact format pattern used varies by locale.
 292      * <p>
 293      * The locale is determined from the formatter. The formatter returned directly by
 294      * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}.
 295      * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)}
 296      * on the result of this method.
 297      * <p>
 298      * Note that the localized pattern is looked up lazily.
 299      * This {@code DateTimeFormatter} holds the style required and the locale,
 300      * looking up the pattern required on demand.
 301      *
 302      * @param timeStyle  the formatter style to obtain, not null
 303      * @return the time formatter, not null
 304      */
 305     public static DateTimeFormatter localizedTime(FormatStyle timeStyle) {
 306         Objects.requireNonNull(timeStyle, "timeStyle");
 307         return new DateTimeFormatterBuilder().appendLocalized(null, timeStyle).toFormatter();
 308     }
 309 
 310     /**
 311      * Returns a locale specific date-time format, which is typically of short length.
 312      * <p>
 313      * This returns a formatter that will print/parse a date-time.
 314      * The exact format pattern used varies by locale.
 315      * <p>
 316      * The locale is determined from the formatter. The formatter returned directly by
 317      * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}.
 318      * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)}
 319      * on the result of this method.
 320      * <p>
 321      * Note that the localized pattern is looked up lazily.
 322      * This {@code DateTimeFormatter} holds the style required and the locale,
 323      * looking up the pattern required on demand.
 324      *
 325      * @param dateTimeStyle  the formatter style to obtain, not null
 326      * @return the date-time formatter, not null
 327      */
 328     public static DateTimeFormatter localizedDateTime(FormatStyle dateTimeStyle) {
 329         Objects.requireNonNull(dateTimeStyle, "dateTimeStyle");
 330         return new DateTimeFormatterBuilder().appendLocalized(dateTimeStyle, dateTimeStyle).toFormatter();
 331     }
 332 
 333     /**
 334      * Returns a locale specific date and time format.
 335      * <p>
 336      * This returns a formatter that will print/parse a date-time.
 337      * The exact format pattern used varies by locale.
 338      * <p>
 339      * The locale is determined from the formatter. The formatter returned directly by
 340      * this method will use the {@link Locale#getDefault() default FORMAT locale}.
 341      * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)}
 342      * on the result of this method.
 343      * <p>
 344      * Note that the localized pattern is looked up lazily.
 345      * This {@code DateTimeFormatter} holds the style required and the locale,
 346      * looking up the pattern required on demand.
 347      *
 348      * @param dateStyle  the date formatter style to obtain, not null
 349      * @param timeStyle  the time formatter style to obtain, not null
 350      * @return the date, time or date-time formatter, not null
 351      */
 352     public static DateTimeFormatter localizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle) {
 353         Objects.requireNonNull(dateStyle, "dateStyle");
 354         Objects.requireNonNull(timeStyle, "timeStyle");
 355         return new DateTimeFormatterBuilder().appendLocalized(dateStyle, timeStyle).toFormatter();
 356     }
 357 
 358     //-----------------------------------------------------------------------
 359     /**
 360      * Returns the ISO date formatter that prints/parses a date without an offset,
 361      * such as '2011-12-03'.
 362      * <p>
 363      * This returns an immutable formatter capable of printing and parsing
 364      * the ISO-8601 extended local date format.
 365      * The format consists of:
 366      * <p><ul>
 367      * <li>Four digits or more for the {@link ChronoField#YEAR year}.
 368      * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits.
 369      * Years outside that range will have a prefixed positive or negative symbol.
 370      * <li>A dash
 371      * <li>Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}.
 372      *  This is pre-padded by zero to ensure two digits.
 373      * <li>A dash
 374      * <li>Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}.
 375      *  This is pre-padded by zero to ensure two digits.
 376      * </ul><p>
 377      *
 378      * @return the ISO local date formatter, not null
 379      */
 380     public static DateTimeFormatter isoLocalDate() {
 381         return ISO_LOCAL_DATE;
 382     }
 383 
 384     /** Singleton date formatter. */
 385     private static final DateTimeFormatter ISO_LOCAL_DATE;
 386     static {
 387         ISO_LOCAL_DATE = new DateTimeFormatterBuilder()
 388             .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
 389             .appendLiteral('-')
 390             .appendValue(MONTH_OF_YEAR, 2)
 391             .appendLiteral('-')
 392             .appendValue(DAY_OF_MONTH, 2)
 393             .toFormatter();
 394     }
 395 
 396     //-----------------------------------------------------------------------
 397     /**
 398      * Returns the ISO date formatter that prints/parses a date with an offset,
 399      * such as '2011-12-03+01:00'.
 400      * <p>
 401      * This returns an immutable formatter capable of printing and parsing
 402      * the ISO-8601 extended offset date format.
 403      * The format consists of:
 404      * <p><ul>
 405      * <li>The {@link #isoLocalDate()}
 406      * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
 407      *  they will be handled even though this is not part of the ISO-8601 standard.
 408      *  Parsing is case insensitive.
 409      * </ul><p>
 410      *
 411      * @return the ISO offset date formatter, not null
 412      */
 413     public static DateTimeFormatter isoOffsetDate() {
 414         return ISO_OFFSET_DATE;
 415     }
 416 
 417     /** Singleton date formatter. */
 418     private static final DateTimeFormatter ISO_OFFSET_DATE;
 419     static {
 420         ISO_OFFSET_DATE = new DateTimeFormatterBuilder()
 421             .parseCaseInsensitive()
 422             .append(ISO_LOCAL_DATE)
 423             .appendOffsetId()
 424             .toFormatter();
 425     }
 426 
 427     //-----------------------------------------------------------------------
 428     /**
 429      * Returns the ISO date formatter that prints/parses a date with the
 430      * offset if available, such as '2011-12-03' or '2011-12-03+01:00'.
 431      * <p>
 432      * This returns an immutable formatter capable of printing and parsing
 433      * the ISO-8601 extended date format.
 434      * The format consists of:
 435      * <p><ul>
 436      * <li>The {@link #isoLocalDate()}
 437      * <li>If the offset is not available to print/parse then the format is complete.
 438      * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
 439      *  they will be handled even though this is not part of the ISO-8601 standard.
 440      *  Parsing is case insensitive.
 441      * </ul><p>
 442      * As this formatter has an optional element, it may be necessary to parse using
 443      * {@link DateTimeFormatter#parseBest}.
 444      *
 445      * @return the ISO date formatter, not null
 446      */
 447     public static DateTimeFormatter isoDate() {
 448         return ISO_DATE;
 449     }
 450 
 451     /** Singleton date formatter. */
 452     private static final DateTimeFormatter ISO_DATE;
 453     static {
 454         ISO_DATE = new DateTimeFormatterBuilder()
 455             .parseCaseInsensitive()
 456             .append(ISO_LOCAL_DATE)
 457             .optionalStart()
 458             .appendOffsetId()
 459             .toFormatter();
 460     }
 461 
 462     //-----------------------------------------------------------------------
 463     /**
 464      * Returns the ISO time formatter that prints/parses a time without an offset,
 465      * such as '10:15' or '10:15:30'.
 466      * <p>
 467      * This returns an immutable formatter capable of printing and parsing
 468      * the ISO-8601 extended local time format.
 469      * The format consists of:
 470      * <p><ul>
 471      * <li>Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}.
 472      *  This is pre-padded by zero to ensure two digits.
 473      * <li>A colon
 474      * <li>Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}.
 475      *  This is pre-padded by zero to ensure two digits.
 476      * <li>If the second-of-minute is not available to print/parse then the format is complete.
 477      * <li>A colon
 478      * <li>Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}.
 479      *  This is pre-padded by zero to ensure two digits.
 480      * <li>If the nano-of-second is zero or not available to print/parse then the format is complete.
 481      * <li>A decimal point
 482      * <li>One to nine digits for the {@link ChronoField#NANO_OF_SECOND nano-of-second}.
 483      *  As many digits will be printed as required.
 484      * </ul><p>
 485      *
 486      * @return the ISO local time formatter, not null
 487      */
 488     public static DateTimeFormatter isoLocalTime() {
 489         return ISO_LOCAL_TIME;
 490     }
 491 
 492     /** Singleton date formatter. */
 493     private static final DateTimeFormatter ISO_LOCAL_TIME;
 494     static {
 495         ISO_LOCAL_TIME = new DateTimeFormatterBuilder()
 496             .appendValue(HOUR_OF_DAY, 2)
 497             .appendLiteral(':')
 498             .appendValue(MINUTE_OF_HOUR, 2)
 499             .optionalStart()
 500             .appendLiteral(':')
 501             .appendValue(SECOND_OF_MINUTE, 2)
 502             .optionalStart()
 503             .appendFraction(NANO_OF_SECOND, 0, 9, true)
 504             .toFormatter();
 505     }
 506 
 507     //-----------------------------------------------------------------------
 508     /**
 509      * Returns the ISO time formatter that prints/parses a time with an offset,
 510      * such as '10:15+01:00' or '10:15:30+01:00'.
 511      * <p>
 512      * This returns an immutable formatter capable of printing and parsing
 513      * the ISO-8601 extended offset time format.
 514      * The format consists of:
 515      * <p><ul>
 516      * <li>The {@link #isoLocalTime()}
 517      * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
 518      *  they will be handled even though this is not part of the ISO-8601 standard.
 519      *  Parsing is case insensitive.
 520      * </ul><p>
 521      *
 522      * @return the ISO offset time formatter, not null
 523      */
 524     public static DateTimeFormatter isoOffsetTime() {
 525         return ISO_OFFSET_TIME;
 526     }
 527 
 528     /** Singleton date formatter. */
 529     private static final DateTimeFormatter ISO_OFFSET_TIME;
 530     static {
 531         ISO_OFFSET_TIME = new DateTimeFormatterBuilder()
 532             .parseCaseInsensitive()
 533             .append(ISO_LOCAL_TIME)
 534             .appendOffsetId()
 535             .toFormatter();
 536     }
 537 
 538     //-----------------------------------------------------------------------
 539     /**
 540      * Returns the ISO time formatter that prints/parses a time, with the
 541      * offset if available, such as '10:15', '10:15:30' or '10:15:30+01:00'.
 542      * <p>
 543      * This returns an immutable formatter capable of printing and parsing
 544      * the ISO-8601 extended offset time format.
 545      * The format consists of:
 546      * <p><ul>
 547      * <li>The {@link #isoLocalTime()}
 548      * <li>If the offset is not available to print/parse then the format is complete.
 549      * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
 550      *  they will be handled even though this is not part of the ISO-8601 standard.
 551      *  Parsing is case insensitive.
 552      * </ul><p>
 553      * As this formatter has an optional element, it may be necessary to parse using
 554      * {@link DateTimeFormatter#parseBest}.
 555      *
 556      * @return the ISO time formatter, not null
 557      */
 558     public static DateTimeFormatter isoTime() {
 559         return ISO_TIME;
 560     }
 561 
 562     /** Singleton date formatter. */
 563     private static final DateTimeFormatter ISO_TIME;
 564     static {
 565         ISO_TIME = new DateTimeFormatterBuilder()
 566             .parseCaseInsensitive()
 567             .append(ISO_LOCAL_TIME)
 568             .optionalStart()
 569             .appendOffsetId()
 570             .toFormatter();
 571     }
 572 
 573     //-----------------------------------------------------------------------
 574     /**
 575      * Returns the ISO date formatter that prints/parses a date-time
 576      * without an offset, such as '2011-12-03T10:15:30'.
 577      * <p>
 578      * This returns an immutable formatter capable of printing and parsing
 579      * the ISO-8601 extended offset date-time format.
 580      * The format consists of:
 581      * <p><ul>
 582      * <li>The {@link #isoLocalDate()}
 583      * <li>The letter 'T'. Parsing is case insensitive.
 584      * <li>The {@link #isoLocalTime()}
 585      * </ul><p>
 586      *
 587      * @return the ISO local date-time formatter, not null
 588      */
 589     public static DateTimeFormatter isoLocalDateTime() {
 590         return ISO_LOCAL_DATE_TIME;
 591     }
 592 
 593     /** Singleton date formatter. */
 594     private static final DateTimeFormatter ISO_LOCAL_DATE_TIME;
 595     static {
 596         ISO_LOCAL_DATE_TIME = new DateTimeFormatterBuilder()
 597             .parseCaseInsensitive()
 598             .append(ISO_LOCAL_DATE)
 599             .appendLiteral('T')
 600             .append(ISO_LOCAL_TIME)
 601             .toFormatter();
 602     }
 603 
 604     //-----------------------------------------------------------------------
 605     /**
 606      * Returns the ISO date formatter that prints/parses a date-time
 607      * with an offset, such as '2011-12-03T10:15:30+01:00'.
 608      * <p>
 609      * This returns an immutable formatter capable of printing and parsing
 610      * the ISO-8601 extended offset date-time format.
 611      * The format consists of:
 612      * <p><ul>
 613      * <li>The {@link #isoLocalDateTime()}
 614      * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
 615      *  they will be handled even though this is not part of the ISO-8601 standard.
 616      *  Parsing is case insensitive.
 617      * </ul><p>
 618      *
 619      * @return the ISO offset date-time formatter, not null
 620      */
 621     public static DateTimeFormatter isoOffsetDateTime() {
 622         return ISO_OFFSET_DATE_TIME;
 623     }
 624 
 625     /** Singleton date formatter. */
 626     private static final DateTimeFormatter ISO_OFFSET_DATE_TIME;
 627     static {
 628         ISO_OFFSET_DATE_TIME = new DateTimeFormatterBuilder()
 629             .parseCaseInsensitive()
 630             .append(ISO_LOCAL_DATE_TIME)
 631             .appendOffsetId()
 632             .toFormatter();
 633     }
 634 
 635     //-----------------------------------------------------------------------
 636     /**
 637      * Returns the ISO date formatter that prints/parses a date-time with
 638      * offset and zone, such as '2011-12-03T10:15:30+01:00[Europe/Paris]'.
 639      * <p>
 640      * This returns an immutable formatter capable of printing and parsing
 641      * a format that extends the ISO-8601 extended offset date-time format
 642      * to add the time-zone.
 643      * The format consists of:
 644      * <p><ul>
 645      * <li>The {@link #isoOffsetDateTime()}
 646      * <li>If the zone ID is not available or is a {@code ZoneOffset} then the format is complete.
 647      * <li>An open square bracket '['.
 648      * <li>The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard.
 649      *  Parsing is case sensitive.
 650      * <li>A close square bracket ']'.
 651      * </ul><p>
 652      *
 653      * @return the ISO zoned date-time formatter, not null
 654      */
 655     public static DateTimeFormatter isoZonedDateTime() {
 656         return ISO_ZONED_DATE_TIME;
 657     }
 658 
 659     /** Singleton date formatter. */
 660     private static final DateTimeFormatter ISO_ZONED_DATE_TIME;
 661     static {
 662         ISO_ZONED_DATE_TIME = new DateTimeFormatterBuilder()
 663             .append(ISO_OFFSET_DATE_TIME)
 664             .optionalStart()
 665             .appendLiteral('[')
 666             .parseCaseSensitive()
 667             .appendZoneRegionId()
 668             .appendLiteral(']')
 669             .toFormatter();
 670     }
 671 
 672     //-----------------------------------------------------------------------
 673     /**
 674      * Returns the ISO date formatter that prints/parses a date-time
 675      * with the offset and zone if available, such as '2011-12-03T10:15:30',
 676      * '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]'.
 677      * <p>
 678      * This returns an immutable formatter capable of printing and parsing
 679      * the ISO-8601 extended offset date-time format.
 680      * The format consists of:
 681      * <p><ul>
 682      * <li>The {@link #isoLocalDateTime()}
 683      * <li>If the offset is not available to print/parse then the format is complete.
 684      * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
 685      *  they will be handled even though this is not part of the ISO-8601 standard.
 686      * <li>If the zone ID is not available or is a {@code ZoneOffset} then the format is complete.
 687      * <li>An open square bracket '['.
 688      * <li>The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard.
 689      *  Parsing is case sensitive.
 690      * <li>A close square bracket ']'.
 691      * </ul><p>
 692      * As this formatter has an optional element, it may be necessary to parse using
 693      * {@link DateTimeFormatter#parseBest}.
 694      *
 695      * @return the ISO date-time formatter, not null
 696      */
 697     public static DateTimeFormatter isoDateTime() {
 698         return ISO_DATE_TIME;
 699     }
 700 
 701     /** Singleton date formatter. */
 702     private static final DateTimeFormatter ISO_DATE_TIME;
 703     static {
 704         ISO_DATE_TIME = new DateTimeFormatterBuilder()
 705             .append(ISO_LOCAL_DATE_TIME)
 706             .optionalStart()
 707             .appendOffsetId()
 708             .optionalStart()
 709             .appendLiteral('[')
 710             .parseCaseSensitive()
 711             .appendZoneRegionId()
 712             .appendLiteral(']')
 713             .toFormatter();
 714     }
 715 
 716     //-----------------------------------------------------------------------
 717     /**
 718      * Returns the ISO date formatter that prints/parses the ordinal date
 719      * without an offset, such as '2012-337'.
 720      * <p>
 721      * This returns an immutable formatter capable of printing and parsing
 722      * the ISO-8601 extended ordinal date format.
 723      * The format consists of:
 724      * <p><ul>
 725      * <li>Four digits or more for the {@link ChronoField#YEAR year}.
 726      * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits.
 727      * Years outside that range will have a prefixed positive or negative symbol.
 728      * <li>A dash
 729      * <li>Three digits for the {@link ChronoField#DAY_OF_YEAR day-of-year}.
 730      *  This is pre-padded by zero to ensure three digits.
 731      * <li>If the offset is not available to print/parse then the format is complete.
 732      * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
 733      *  they will be handled even though this is not part of the ISO-8601 standard.
 734      *  Parsing is case insensitive.
 735      * </ul><p>
 736      * As this formatter has an optional element, it may be necessary to parse using
 737      * {@link DateTimeFormatter#parseBest}.
 738      *
 739      * @return the ISO ordinal date formatter, not null
 740      */
 741     public static DateTimeFormatter isoOrdinalDate() {
 742         return ISO_ORDINAL_DATE;
 743     }
 744 
 745     /** Singleton date formatter. */
 746     private static final DateTimeFormatter ISO_ORDINAL_DATE;
 747     static {
 748         ISO_ORDINAL_DATE = new DateTimeFormatterBuilder()
 749             .parseCaseInsensitive()
 750             .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
 751             .appendLiteral('-')
 752             .appendValue(DAY_OF_YEAR, 3)
 753             .optionalStart()
 754             .appendOffsetId()
 755             .toFormatter();
 756     }
 757 
 758     //-----------------------------------------------------------------------
 759     /**
 760      * Returns the ISO date formatter that prints/parses the week-based date
 761      * without an offset, such as '2012-W48-6'.
 762      * <p>
 763      * This returns an immutable formatter capable of printing and parsing
 764      * the ISO-8601 extended week-based date format.
 765      * The format consists of:
 766      * <p><ul>
 767      * <li>Four digits or more for the {@link ISOFields#WEEK_BASED_YEAR week-based-year}.
 768      * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits.
 769      * Years outside that range will have a prefixed positive or negative symbol.
 770      * <li>A dash
 771      * <li>The letter 'W'. Parsing is case insensitive.
 772      * <li>Two digits for the {@link ISOFields#WEEK_OF_WEEK_BASED_YEAR week-of-week-based-year}.
 773      *  This is pre-padded by zero to ensure three digits.
 774      * <li>A dash
 775      * <li>One digit for the {@link ChronoField#DAY_OF_WEEK day-of-week}.
 776      *  The value run from Monday (1) to Sunday (7).
 777      * <li>If the offset is not available to print/parse then the format is complete.
 778      * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
 779      *  they will be handled even though this is not part of the ISO-8601 standard.
 780      *  Parsing is case insensitive.
 781      * </ul><p>
 782      * As this formatter has an optional element, it may be necessary to parse using
 783      * {@link DateTimeFormatter#parseBest}.
 784      *
 785      * @return the ISO week-based date formatter, not null
 786      */
 787     public static DateTimeFormatter isoWeekDate() {
 788         return ISO_WEEK_DATE;
 789     }
 790 
 791     /** Singleton date formatter. */
 792     private static final DateTimeFormatter ISO_WEEK_DATE;
 793     static {
 794         ISO_WEEK_DATE = new DateTimeFormatterBuilder()
 795             .parseCaseInsensitive()
 796             .appendValue(ISOFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
 797             .appendLiteral("-W")
 798             .appendValue(ISOFields.WEEK_OF_WEEK_BASED_YEAR, 2)
 799             .appendLiteral('-')
 800             .appendValue(DAY_OF_WEEK, 1)
 801             .optionalStart()
 802             .appendOffsetId()
 803             .toFormatter();
 804     }
 805 
 806     //-----------------------------------------------------------------------
 807     /**
 808      * Returns the ISO instant formatter that prints/parses an instant in UTC.
 809      * <p>
 810      * This returns an immutable formatter capable of printing and parsing
 811      * the ISO-8601 instant format.
 812      * The format consists of:
 813      * <p><ul>
 814      * <li>The {@link #isoOffsetDateTime()} where the instant is converted from
 815      *  {@link ChronoField#INSTANT_SECONDS} and {@link ChronoField#NANO_OF_SECOND}
 816      *  using the {@code UTC} offset. Parsing is case insensitive.
 817      * </ul><p>
 818      *
 819      * @return the ISO instant formatter, not null
 820      */
 821     public static DateTimeFormatter isoInstant() {
 822         return ISO_INSTANT;
 823     }
 824 
 825     /** Singleton formatter. */
 826     private static final DateTimeFormatter ISO_INSTANT;
 827     static {
 828         ISO_INSTANT = new DateTimeFormatterBuilder()
 829             .parseCaseInsensitive()
 830             .appendInstant()
 831             .toFormatter();
 832     }
 833 
 834     //-----------------------------------------------------------------------
 835     /**
 836      * Returns the ISO date formatter that prints/parses a date without an offset,
 837      * such as '20111203'.
 838      * <p>
 839      * This returns an immutable formatter capable of printing and parsing
 840      * the ISO-8601 basic local date format.
 841      * The format consists of:
 842      * <p><ul>
 843      * <li>Four digits for the {@link ChronoField#YEAR year}.
 844      *  Only years in the range 0000 to 9999 are supported.
 845      * <li>Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}.
 846      *  This is pre-padded by zero to ensure two digits.
 847      * <li>Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}.
 848      *  This is pre-padded by zero to ensure two digits.
 849      * <li>If the offset is not available to print/parse then the format is complete.
 850      * <li>The {@link ZoneOffset#getId() offset ID} without colons. If the offset has
 851      *  seconds then they will be handled even though this is not part of the ISO-8601 standard.
 852      *  Parsing is case insensitive.
 853      * </ul><p>
 854      * As this formatter has an optional element, it may be necessary to parse using
 855      * {@link DateTimeFormatter#parseBest}.
 856      *
 857      * @return the ISO basic local date formatter, not null
 858      */
 859     public static DateTimeFormatter basicIsoDate() {
 860         return BASIC_ISO_DATE;
 861     }
 862 
 863     /** Singleton date formatter. */
 864     private static final DateTimeFormatter BASIC_ISO_DATE;
 865     static {
 866         BASIC_ISO_DATE = new DateTimeFormatterBuilder()
 867             .parseCaseInsensitive()
 868             .appendValue(YEAR, 4)
 869             .appendValue(MONTH_OF_YEAR, 2)
 870             .appendValue(DAY_OF_MONTH, 2)
 871             .optionalStart()
 872             .appendOffset("+HHMMss", "Z")
 873             .toFormatter();
 874     }
 875 
 876     //-----------------------------------------------------------------------
 877     /**
 878      * Returns the RFC-1123 date-time formatter, such as 'Tue, 3 Jun 2008 11:05:30 GMT'.
 879      * <p>
 880      * This returns an immutable formatter capable of printing and parsing
 881      * most of the RFC-1123 format.
 882      * RFC-1123 updates RFC-822 changing the year from two digits to four.
 883      * This implementation requires a four digit year.
 884      * This implementation also does not handle North American or military zone
 885      * names, only 'GMT' and offset amounts.
 886      * <p>
 887      * The format consists of:
 888      * <p><ul>
 889      * <li>If the day-of-week is not available to print/parse then jump to day-of-month.
 890      * <li>Three letter {@link ChronoField#DAY_OF_WEEK day-of-week} in English.
 891      * <li>A comma
 892      * <li>A space
 893      * <li>One or two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}.
 894      * <li>A space
 895      * <li>Three letter {@link ChronoField#MONTH_OF_YEAR month-of-year} in English.
 896      * <li>A space
 897      * <li>Four digits for the {@link ChronoField#YEAR year}.
 898      *  Only years in the range 0000 to 9999 are supported.
 899      * <li>A space
 900      * <li>Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}.
 901      *  This is pre-padded by zero to ensure two digits.
 902      * <li>A colon
 903      * <li>Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}.
 904      *  This is pre-padded by zero to ensure two digits.
 905      * <li>If the second-of-minute is not available to print/parse then jump to the next space.
 906      * <li>A colon
 907      * <li>Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}.
 908      *  This is pre-padded by zero to ensure two digits.
 909      * <li>A space
 910      * <li>The {@link ZoneOffset#getId() offset ID} without colons or seconds.
 911      *  An offset of zero uses "GMT". North American zone names and military zone names are not handled.
 912      * </ul><p>
 913      * Parsing is case insensitive.
 914      *
 915      * @return the RFC-1123 formatter, not null
 916      */
 917     public static DateTimeFormatter rfc1123() {
 918         return RFC_1123_DATE_TIME;
 919     }
 920 
 921     /** Singleton date formatter. */
 922     private static final DateTimeFormatter RFC_1123_DATE_TIME;
 923     static {
 924         // manually code maps to ensure correct data always used
 925         // (locale data can be changed by application code)
 926         Map<Long, String> dow = new HashMap<>();
 927         dow.put(1L, "Mon");
 928         dow.put(2L, "Tue");
 929         dow.put(3L, "Wed");
 930         dow.put(4L, "Thu");
 931         dow.put(5L, "Fri");
 932         dow.put(6L, "Sat");
 933         dow.put(7L, "Sun");
 934         Map<Long, String> moy = new HashMap<>();
 935         moy.put(1L, "Jan");
 936         moy.put(2L, "Feb");
 937         moy.put(3L, "Mar");
 938         moy.put(4L, "Apr");
 939         moy.put(5L, "May");
 940         moy.put(6L, "Jun");
 941         moy.put(7L, "Jul");
 942         moy.put(8L, "Aug");
 943         moy.put(9L, "Sep");
 944         moy.put(10L, "Oct");
 945         moy.put(11L, "Nov");
 946         moy.put(12L, "Dec");
 947         RFC_1123_DATE_TIME = new DateTimeFormatterBuilder()
 948             .parseCaseInsensitive()
 949             .parseLenient()
 950             .optionalStart()
 951             .appendText(DAY_OF_WEEK, dow)
 952             .appendLiteral(", ")
 953             .optionalEnd()
 954             .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE)
 955             .appendLiteral(' ')
 956             .appendText(MONTH_OF_YEAR, moy)
 957             .appendLiteral(' ')
 958             .appendValue(YEAR, 4)  // 2 digit year not handled
 959             .appendLiteral(' ')
 960             .appendValue(HOUR_OF_DAY, 2)
 961             .appendLiteral(':')
 962             .appendValue(MINUTE_OF_HOUR, 2)
 963             .optionalStart()
 964             .appendLiteral(':')
 965             .appendValue(SECOND_OF_MINUTE, 2)
 966             .optionalEnd()
 967             .appendLiteral(' ')
 968             .appendOffset("+HHMM", "GMT")  // should handle UT/Z/EST/EDT/CST/CDT/MST/MDT/PST/MDT
 969             .toFormatter();
 970     }
 971 
 972 }