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