jdk/src/share/classes/java/time/format/DateTimeFormatters.java
changeset 15658 55b829ca2334
parent 15657 c588664d547e
child 15659 e575dab44ff5
equal deleted inserted replaced
15657:c588664d547e 15658:55b829ca2334
     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 }