EMMA Coverage Report (generated Tue Oct 28 00:01:11 GMT 2008)
[all classes][org.joda.time.format]

COVERAGE SUMMARY FOR SOURCE FILE [ISODateTimeFormat.java]

nameclass, %method, %block, %line, %
ISODateTimeFormat.java100% (1/1)100% (72/72)99%  (1652/1661)99%  (334/337)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ISODateTimeFormat100% (1/1)100% (72/72)99%  (1652/1661)99%  (334/337)
dateByOrdinal (DateTimeFormatterBuilder, Collection, boolean, boolean): boolean 100% (1/1)92%  (36/39)91%  (10/11)
dateByWeek (DateTimeFormatterBuilder, Collection, boolean, boolean): boolean 100% (1/1)97%  (116/119)97%  (31/32)
dateByMonth (DateTimeFormatterBuilder, Collection, boolean, boolean): boolean 100% (1/1)98%  (117/120)97%  (31/32)
ISODateTimeFormat (): void 100% (1/1)100% (3/3)100% (2/2)
appendSeparator (DateTimeFormatterBuilder, boolean): void 100% (1/1)100% (7/7)100% (3/3)
basicDate (): DateTimeFormatter 100% (1/1)100% (18/18)100% (3/3)
basicDateTime (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
basicDateTimeNoMillis (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
basicOrdinalDate (): DateTimeFormatter 100% (1/1)100% (15/15)100% (3/3)
basicOrdinalDateTime (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
basicOrdinalDateTimeNoMillis (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
basicTTime (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
basicTTimeNoMillis (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
basicTime (): DateTimeFormatter 100% (1/1)100% (28/28)100% (3/3)
basicTimeNoMillis (): DateTimeFormatter 100% (1/1)100% (23/23)100% (3/3)
basicWeekDate (): DateTimeFormatter 100% (1/1)100% (20/20)100% (3/3)
basicWeekDateTime (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
basicWeekDateTimeNoMillis (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
checkNotStrictISO (Collection, boolean): void 100% (1/1)100% (15/15)100% (3/3)
date (): DateTimeFormatter 100% (1/1)100% (2/2)100% (1/1)
dateElementParser (): DateTimeFormatter 100% (1/1)100% (57/57)100% (3/3)
dateHour (): DateTimeFormatter 100% (1/1)100% (15/15)100% (3/3)
dateHourMinute (): DateTimeFormatter 100% (1/1)100% (15/15)100% (3/3)
dateHourMinuteSecond (): DateTimeFormatter 100% (1/1)100% (15/15)100% (3/3)
dateHourMinuteSecondFraction (): DateTimeFormatter 100% (1/1)100% (15/15)100% (3/3)
dateHourMinuteSecondMillis (): DateTimeFormatter 100% (1/1)100% (15/15)100% (3/3)
dateOptionalTimeParser (): DateTimeFormatter 100% (1/1)100% (26/26)100% (4/4)
dateParser (): DateTimeFormatter 100% (1/1)100% (22/22)100% (4/4)
dateTime (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
dateTimeNoMillis (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
dateTimeParser (): DateTimeFormatter 100% (1/1)100% (34/34)100% (4/4)
dayOfMonthElement (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
dayOfWeekElement (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
dayOfYearElement (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
forFields (Collection, boolean, boolean): DateTimeFormatter 100% (1/1)100% (139/139)100% (30/30)
fractionElement (): DateTimeFormatter 100% (1/1)100% (14/14)100% (3/3)
hour (): DateTimeFormatter 100% (1/1)100% (2/2)100% (1/1)
hourElement (): DateTimeFormatter 100% (1/1)100% (11/11)100% (3/3)
hourMinute (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
hourMinuteSecond (): DateTimeFormatter 100% (1/1)100% (15/15)100% (3/3)
hourMinuteSecondFraction (): DateTimeFormatter 100% (1/1)100% (17/17)100% (3/3)
hourMinuteSecondMillis (): DateTimeFormatter 100% (1/1)100% (20/20)100% (3/3)
literalTElement (): DateTimeFormatter 100% (1/1)100% (11/11)100% (3/3)
localDateOptionalTimeParser (): DateTimeFormatter 100% (1/1)100% (24/24)100% (4/4)
localDateParser (): DateTimeFormatter 100% (1/1)100% (8/8)100% (3/3)
localTimeParser (): DateTimeFormatter 100% (1/1)100% (16/16)100% (3/3)
minuteElement (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
monthElement (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
offsetElement (): DateTimeFormatter 100% (1/1)100% (14/14)100% (3/3)
ordinalDate (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
ordinalDateTime (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
ordinalDateTimeNoMillis (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
secondElement (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
tTime (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
tTimeNoMillis (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
time (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
time (DateTimeFormatterBuilder, Collection, boolean, boolean, boolean, boolea... 100% (1/1)100% (187/187)100% (37/37)
timeElementParser (): DateTimeFormatter 100% (1/1)100% (106/106)100% (4/4)
timeNoMillis (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
timeParser (): DateTimeFormatter 100% (1/1)100% (17/17)100% (3/3)
weekDate (): DateTimeFormatter 100% (1/1)100% (2/2)100% (1/1)
weekDateTime (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
weekDateTimeNoMillis (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
weekElement (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
weekyear (): DateTimeFormatter 100% (1/1)100% (2/2)100% (1/1)
weekyearElement (): DateTimeFormatter 100% (1/1)100% (12/12)100% (3/3)
weekyearWeek (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
weekyearWeekDay (): DateTimeFormatter 100% (1/1)100% (15/15)100% (3/3)
year (): DateTimeFormatter 100% (1/1)100% (2/2)100% (1/1)
yearElement (): DateTimeFormatter 100% (1/1)100% (12/12)100% (3/3)
yearMonth (): DateTimeFormatter 100% (1/1)100% (13/13)100% (3/3)
yearMonthDay (): DateTimeFormatter 100% (1/1)100% (15/15)100% (3/3)

1/*
2 *  Copyright 2001-2006,2008 Stephen Colebourne
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 */
16package org.joda.time.format;
17 
18import java.util.Collection;
19import java.util.HashSet;
20import java.util.Set;
21 
22import org.joda.time.DateTimeFieldType;
23import org.joda.time.DateTimeZone;
24 
25/**
26 * Factory that creates instances of DateTimeFormatter for the ISO8601 standard.
27 * <p>
28 * Datetime formatting is performed by the {@link DateTimeFormatter} class.
29 * Three classes provide factory methods to create formatters, and this is one.
30 * The others are {@link DateTimeFormat} and {@link DateTimeFormatterBuilder}.
31 * <p>
32 * ISO8601 is the international standard for data interchange. It defines a
33 * framework, rather than an absolute standard. As a result this provider has a
34 * number of methods that represent common uses of the framework. The most common
35 * formats are {@link #date() date}, {@link #time() time}, and {@link #dateTime() dateTime}.
36 * <p>
37 * For example, to format a date time in ISO format:
38 * <pre>
39 * DateTime dt = new DateTime();
40 * DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
41 * String str = fmt.print(dt);
42 * </pre>
43 * <p>
44 * It is important to understand that these formatters are not linked to
45 * the <code>ISOChronology</code>. These formatters may be used with any
46 * chronology, however there may be certain side effects with more unusual
47 * chronologies. For example, the ISO formatters rely on dayOfWeek being
48 * single digit, dayOfMonth being two digit and dayOfYear being three digit.
49 * A chronology with a ten day week would thus cause issues. However, in
50 * general, it is safe to use these formatters with other chronologies.
51 * <p>
52 * ISODateTimeFormat is thread-safe and immutable, and the formatters it
53 * returns are as well.
54 *
55 * @author Brian S O'Neill
56 * @since 1.0
57 * @see DateTimeFormat
58 * @see DateTimeFormatterBuilder
59 */
60public class ISODateTimeFormat {
61 
62    //-----------------------------------------------------------------------
63    private static DateTimeFormatter
64        ye,  // year element (yyyy)
65        mye, // monthOfYear element (-MM)
66        dme, // dayOfMonth element (-dd)
67        we,  // weekyear element (xxxx)
68        wwe, // weekOfWeekyear element (-ww)
69        dwe, // dayOfWeek element (-ee)
70        dye, // dayOfYear element (-DDD)
71        hde, // hourOfDay element (HH)
72        mhe, // minuteOfHour element (:mm)
73        sme, // secondOfMinute element (:ss)
74        fse, // fractionOfSecond element (.SSSSSSSSS)
75        ze,  // zone offset element
76        lte, // literal 'T' element
77        
78        //y,   // year (same as year element)
79        ym,  // year month
80        ymd, // year month day
81 
82        //w,   // weekyear (same as weekyear element)
83        ww,  // weekyear week
84        wwd, // weekyear week day
85 
86        //h,    // hour (same as hour element)
87        hm,   // hour minute
88        hms,  // hour minute second
89        hmsl, // hour minute second millis
90        hmsf, // hour minute second fraction
91 
92        dh,    // date hour
93        dhm,   // date hour minute
94        dhms,  // date hour minute second
95        dhmsl, // date hour minute second millis
96        dhmsf, // date hour minute second fraction
97 
98        //d,  // date (same as ymd)
99        t,  // time
100        tx,  // time no millis
101        tt,  // Ttime
102        ttx,  // Ttime no millis
103        dt, // date time
104        dtx, // date time no millis
105 
106        //wd,  // week date (same as wwd)
107        wdt, // week date time
108        wdtx, // week date time no millis
109 
110        od,  // ordinal date (same as yd)
111        odt, // ordinal date time
112        odtx, // ordinal date time no millis
113 
114        bd,  // basic date
115        bt,  // basic time
116        btx,  // basic time no millis
117        btt, // basic Ttime
118        bttx, // basic Ttime no millis
119        bdt, // basic date time
120        bdtx, // basic date time no millis
121 
122        bod,  // basic ordinal date
123        bodt, // basic ordinal date time
124        bodtx, // basic ordinal date time no millis
125 
126        bwd,  // basic week date
127        bwdt, // basic week date time
128        bwdtx, // basic week date time no millis
129 
130        dpe, // date parser element
131        tpe, // time parser element
132        dp,  // date parser
133        ldp, // local date parser
134        tp,  // time parser
135        ltp, // local time parser
136        dtp, // date time parser
137        dotp, // date optional time parser
138        ldotp; // local date optional time parser
139 
140    /**
141     * Constructor.
142     *
143     * @since 1.1 (previously private)
144     */
145    protected ISODateTimeFormat() {
146        super();
147    }
148 
149    //-----------------------------------------------------------------------
150    /**
151     * Returns a formatter that outputs only those fields specified.
152     * <p>
153     * This method examines the fields provided and returns an ISO-style
154     * formatter that best fits. This can be useful for outputting
155     * less-common ISO styles, such as YearMonth (YYYY-MM) or MonthDay (--MM-DD).
156     * <p>
157     * The list provided may have overlapping fields, such as dayOfWeek and
158     * dayOfMonth. In this case, the style is chosen based on the following
159     * list, thus in the example, the calendar style is chosen as dayOfMonth
160     * is higher in priority than dayOfWeek:
161     * <ul>
162     * <li>monthOfYear - calendar date style
163     * <li>dayOfYear - ordinal date style
164     * <li>weekOfWeekYear - week date style
165     * <li>dayOfMonth - calendar date style
166     * <li>dayOfWeek - week date style
167     * <li>year
168     * <li>weekyear
169     * </ul>
170     * The supported formats are:
171     * <pre>
172     * Extended      Basic       Fields
173     * 2005-03-25    20050325    year/monthOfYear/dayOfMonth
174     * 2005-03       2005-03     year/monthOfYear
175     * 2005--25      2005--25    year/dayOfMonth *
176     * 2005          2005        year
177     * --03-25       --0325      monthOfYear/dayOfMonth
178     * --03          --03        monthOfYear
179     * ---03         ---03       dayOfMonth
180     * 2005-084      2005084     year/dayOfYear
181     * -084          -084        dayOfYear
182     * 2005-W12-5    2005W125    weekyear/weekOfWeekyear/dayOfWeek
183     * 2005-W-5      2005W-5     weekyear/dayOfWeek *
184     * 2005-W12      2005W12     weekyear/weekOfWeekyear
185     * -W12-5        -W125       weekOfWeekyear/dayOfWeek
186     * -W12          -W12        weekOfWeekyear
187     * -W-5          -W-5        dayOfWeek
188     * 10:20:30.040  102030.040  hour/minute/second/milli
189     * 10:20:30      102030      hour/minute/second
190     * 10:20         1020        hour/minute
191     * 10            10          hour
192     * -20:30.040    -2030.040   minute/second/milli
193     * -20:30        -2030       minute/second
194     * -20           -20         minute
195     * --30.040      --30.040    second/milli
196     * --30          --30        second
197     * ---.040       ---.040     milli *
198     * 10-30.040     10-30.040   hour/second/milli *
199     * 10:20-.040    1020-.040   hour/minute/milli *
200     * 10-30         10-30       hour/second *
201     * 10--.040      10--.040    hour/milli *
202     * -20-.040      -20-.040    minute/milli *
203     *   plus datetime formats like {date}T{time}
204     * </pre>
205     * * indiates that this is not an official ISO format and can be excluded
206     * by passing in <code>strictISO</code> as <code>true</code>.
207     * <p>
208     * This method can side effect the input collection of fields.
209     * If the input collection is modifiable, then each field that was added to
210     * the formatter will be removed from the collection, including any duplicates.
211     * If the input collection is unmodifiable then no side effect occurs.
212     * <p>
213     * This side effect processing is useful if you need to know whether all
214     * the fields were converted into the formatter or not. To achieve this,
215     * pass in a modifiable list, and check that it is empty on exit.
216     *
217     * @param fields  the fields to get a formatter for, not null,
218     *  updated by the method call unless unmodifiable,
219     *  removing those fields built in the formatter
220     * @param extended  true to use the extended format (with separators)
221     * @param strictISO  true to stick exactly to ISO8601, false to include additional formats
222     * @return a suitable formatter
223     * @throws IllegalArgumentException if there is no format for the fields
224     * @since 1.1
225     */
226    public static DateTimeFormatter forFields(
227        Collection fields,
228        boolean extended,
229        boolean strictISO) {
230        
231        if (fields == null || fields.size() == 0) {
232            throw new IllegalArgumentException("The fields must not be null or empty");
233        }
234        Set workingFields = new HashSet(fields);
235        int inputSize = workingFields.size();
236        boolean reducedPrec = false;
237        DateTimeFormatterBuilder bld = new DateTimeFormatterBuilder();
238        // date
239        if (workingFields.contains(DateTimeFieldType.monthOfYear())) {
240            reducedPrec = dateByMonth(bld, workingFields, extended, strictISO);
241        } else if (workingFields.contains(DateTimeFieldType.dayOfYear())) {
242            reducedPrec = dateByOrdinal(bld, workingFields, extended, strictISO);
243        } else if (workingFields.contains(DateTimeFieldType.weekOfWeekyear())) {
244            reducedPrec = dateByWeek(bld, workingFields, extended, strictISO);
245        } else if (workingFields.contains(DateTimeFieldType.dayOfMonth())) {
246            reducedPrec = dateByMonth(bld, workingFields, extended, strictISO);
247        } else if (workingFields.contains(DateTimeFieldType.dayOfWeek())) {
248            reducedPrec = dateByWeek(bld, workingFields, extended, strictISO);
249        } else if (workingFields.remove(DateTimeFieldType.year())) {
250            bld.append(yearElement());
251            reducedPrec = true;
252        } else if (workingFields.remove(DateTimeFieldType.weekyear())) {
253            bld.append(weekyearElement());
254            reducedPrec = true;
255        }
256        boolean datePresent = (workingFields.size() < inputSize);
257        
258        // time
259        time(bld, workingFields, extended, strictISO, reducedPrec, datePresent);
260        
261        // result
262        if (bld.canBuildFormatter() == false) {
263            throw new IllegalArgumentException("No valid format for fields: " + fields);
264        }
265        
266        // side effect the input collection to indicate the processed fields
267        // handling unmodifiable collections with no side effect
268        try {
269            fields.retainAll(workingFields);
270        } catch (UnsupportedOperationException ex) {
271            // ignore, so we can handle unmodifiable collections
272        }
273        return bld.toFormatter();
274    }
275 
276    //-----------------------------------------------------------------------
277    /**
278     * Creates a date using the calendar date format.
279     * Specification reference: 5.2.1.
280     *
281     * @param bld  the builder
282     * @param fields  the fields
283     * @param extended  true to use extended format
284     * @param strictISO  true to only allow ISO formats
285     * @return true if reduced precision
286     * @since 1.1
287     */
288    private static boolean dateByMonth(
289        DateTimeFormatterBuilder bld,
290        Collection fields,
291        boolean extended,
292        boolean strictISO) {
293        
294        boolean reducedPrec = false;
295        if (fields.remove(DateTimeFieldType.year())) {
296            bld.append(yearElement());
297            if (fields.remove(DateTimeFieldType.monthOfYear())) {
298                if (fields.remove(DateTimeFieldType.dayOfMonth())) {
299                    // YYYY-MM-DD/YYYYMMDD
300                    appendSeparator(bld, extended);
301                    bld.appendMonthOfYear(2);
302                    appendSeparator(bld, extended);
303                    bld.appendDayOfMonth(2);
304                } else {
305                    // YYYY-MM/YYYY-MM
306                    bld.appendLiteral('-');
307                    bld.appendMonthOfYear(2);
308                    reducedPrec = true;
309                }
310            } else {
311                if (fields.remove(DateTimeFieldType.dayOfMonth())) {
312                    // YYYY--DD/YYYY--DD (non-iso)
313                    checkNotStrictISO(fields, strictISO);
314                    bld.appendLiteral('-');
315                    bld.appendLiteral('-');
316                    bld.appendDayOfMonth(2);
317                } else {
318                    // YYYY/YYYY
319                    reducedPrec = true;
320                }
321            }
322            
323        } else if (fields.remove(DateTimeFieldType.monthOfYear())) {
324            bld.appendLiteral('-');
325            bld.appendLiteral('-');
326            bld.appendMonthOfYear(2);
327            if (fields.remove(DateTimeFieldType.dayOfMonth())) {
328                // --MM-DD/--MMDD
329                appendSeparator(bld, extended);
330                bld.appendDayOfMonth(2);
331            } else {
332                // --MM/--MM
333                reducedPrec = true;
334            }
335        } else if (fields.remove(DateTimeFieldType.dayOfMonth())) {
336            // ---DD/---DD
337            bld.appendLiteral('-');
338            bld.appendLiteral('-');
339            bld.appendLiteral('-');
340            bld.appendDayOfMonth(2);
341        }
342        return reducedPrec;
343    }
344 
345    //-----------------------------------------------------------------------
346    /**
347     * Creates a date using the ordinal date format.
348     * Specification reference: 5.2.2.
349     *
350     * @param bld  the builder
351     * @param fields  the fields
352     * @param extended  true to use extended format
353     * @param strictISO  true to only allow ISO formats
354     * @since 1.1
355     */
356    private static boolean dateByOrdinal(
357        DateTimeFormatterBuilder bld,
358        Collection fields,
359        boolean extended,
360        boolean strictISO) {
361        
362        boolean reducedPrec = false;
363        if (fields.remove(DateTimeFieldType.year())) {
364            bld.append(yearElement());
365            if (fields.remove(DateTimeFieldType.dayOfYear())) {
366                // YYYY-DDD/YYYYDDD
367                appendSeparator(bld, extended);
368                bld.appendDayOfYear(3);
369            } else {
370                // YYYY/YYYY
371                reducedPrec = true;
372            }
373            
374        } else if (fields.remove(DateTimeFieldType.dayOfYear())) {
375            // -DDD/-DDD
376            bld.appendLiteral('-');
377            bld.appendDayOfYear(3);
378        }
379        return reducedPrec;
380    }
381 
382    //-----------------------------------------------------------------------
383    /**
384     * Creates a date using the calendar date format.
385     * Specification reference: 5.2.3.
386     *
387     * @param bld  the builder
388     * @param fields  the fields
389     * @param extended  true to use extended format
390     * @param strictISO  true to only allow ISO formats
391     * @since 1.1
392     */
393    private static boolean dateByWeek(
394        DateTimeFormatterBuilder bld,
395        Collection fields,
396        boolean extended,
397        boolean strictISO) {
398        
399        boolean reducedPrec = false;
400        if (fields.remove(DateTimeFieldType.weekyear())) {
401            bld.append(weekyearElement());
402            if (fields.remove(DateTimeFieldType.weekOfWeekyear())) {
403                appendSeparator(bld, extended);
404                bld.appendLiteral('W');
405                bld.appendWeekOfWeekyear(2);
406                if (fields.remove(DateTimeFieldType.dayOfWeek())) {
407                    // YYYY-WWW-D/YYYYWWWD
408                    appendSeparator(bld, extended);
409                    bld.appendDayOfWeek(1);
410                } else {
411                    // YYYY-WWW/YYYY-WWW
412                    reducedPrec = true;
413                }
414            } else {
415                if (fields.remove(DateTimeFieldType.dayOfWeek())) {
416                    // YYYY-W-D/YYYYW-D (non-iso)
417                    checkNotStrictISO(fields, strictISO);
418                    appendSeparator(bld, extended);
419                    bld.appendLiteral('W');
420                    bld.appendLiteral('-');
421                    bld.appendDayOfWeek(1);
422                } else {
423                    // YYYY/YYYY
424                    reducedPrec = true;
425                }
426            }
427            
428        } else if (fields.remove(DateTimeFieldType.weekOfWeekyear())) {
429            bld.appendLiteral('-');
430            bld.appendLiteral('W');
431            bld.appendWeekOfWeekyear(2);
432            if (fields.remove(DateTimeFieldType.dayOfWeek())) {
433                // -WWW-D/-WWWD
434                appendSeparator(bld, extended);
435                bld.appendDayOfWeek(1);
436            } else {
437                // -WWW/-WWW
438                reducedPrec = true;
439            }
440        } else if (fields.remove(DateTimeFieldType.dayOfWeek())) {
441            // -W-D/-W-D
442            bld.appendLiteral('-');
443            bld.appendLiteral('W');
444            bld.appendLiteral('-');
445            bld.appendDayOfWeek(1);
446        }
447        return reducedPrec;
448    }
449 
450    //-----------------------------------------------------------------------
451    /**
452     * Adds the time fields to the builder.
453     * Specification reference: 5.3.1.
454     * 
455     * @param bld  the builder
456     * @param fields  the fields
457     * @param extended  whether to use the extended format
458     * @param strictISO  whether to be strict
459     * @param reducedPrec  whether the date was reduced precision
460     * @param datePresent  whether there was a date
461     * @since 1.1
462     */
463    private static void time(
464        DateTimeFormatterBuilder bld,
465        Collection fields,
466        boolean extended,
467        boolean strictISO,
468        boolean reducedPrec,
469        boolean datePresent) {
470        
471        boolean hour = fields.remove(DateTimeFieldType.hourOfDay());
472        boolean minute = fields.remove(DateTimeFieldType.minuteOfHour());
473        boolean second = fields.remove(DateTimeFieldType.secondOfMinute());
474        boolean milli = fields.remove(DateTimeFieldType.millisOfSecond());
475        if (!hour && !minute && !second && !milli) {
476            return;
477        }
478        if (hour || minute || second || milli) {
479            if (strictISO && reducedPrec) {
480                throw new IllegalArgumentException("No valid ISO8601 format for fields because Date was reduced precision: " + fields);
481            }
482            if (datePresent) {
483                bld.appendLiteral('T');
484            }
485        }
486        if (hour && minute && second || (hour && !second && !milli)) {
487            // OK - HMSm/HMS/HM/H - valid in combination with date
488        } else {
489            if (strictISO && datePresent) {
490                throw new IllegalArgumentException("No valid ISO8601 format for fields because Time was truncated: " + fields);
491            }
492            if (!hour && (minute && second || (minute && !milli) || second)) {
493                // OK - MSm/MS/M/Sm/S - valid ISO formats
494            } else {
495                if (strictISO) {
496                    throw new IllegalArgumentException("No valid ISO8601 format for fields: " + fields);
497                }
498            }
499        }
500        if (hour) {
501            bld.appendHourOfDay(2);
502        } else if (minute || second || milli) {
503            bld.appendLiteral('-');
504        }
505        if (extended && hour && minute) {
506            bld.appendLiteral(':');
507        }
508        if (minute) {
509            bld.appendMinuteOfHour(2);
510        } else if (second || milli) {
511            bld.appendLiteral('-');
512        }
513        if (extended && minute && second) {
514            bld.appendLiteral(':');
515        }
516        if (second) {
517            bld.appendSecondOfMinute(2);
518        } else if (milli) {
519            bld.appendLiteral('-');
520        }
521        if (milli) {
522            bld.appendLiteral('.');
523            bld.appendMillisOfSecond(3);
524        }
525    }
526 
527    //-----------------------------------------------------------------------
528    /**
529     * Checks that the iso only flag is not set, throwing an exception if it is.
530     * 
531     * @param fields  the fields
532     * @param strictISO  true if only ISO formats allowed
533     * @since 1.1
534     */
535    private static void checkNotStrictISO(Collection fields, boolean strictISO) {
536        if (strictISO) {
537            throw new IllegalArgumentException("No valid ISO8601 format for fields: " + fields);
538        }
539    }
540 
541    /**
542     * Appends the separator if necessary.
543     *
544     * @param bld  the builder
545     * @param extended  whether to append the separator
546     * @param sep  the separator
547     * @since 1.1
548     */
549    private static void appendSeparator(DateTimeFormatterBuilder bld, boolean extended) {
550        if (extended) {
551            bld.appendLiteral('-');
552        }
553    }
554 
555    //-----------------------------------------------------------------------
556    /**
557     * Returns a generic ISO date parser for parsing dates with a possible zone.
558     * It accepts formats described by the following syntax:
559     * <pre>
560     * date              = date-element ['T' offset]
561     * date-element      = std-date-element | ord-date-element | week-date-element
562     * std-date-element  = yyyy ['-' MM ['-' dd]]
563     * ord-date-element  = yyyy ['-' DDD]
564     * week-date-element = xxxx '-W' ww ['-' e]
565     * offset            = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
566     * </pre>
567     */
568    public static DateTimeFormatter dateParser() {
569        if (dp == null) {
570            DateTimeParser tOffset = new DateTimeFormatterBuilder()
571                .appendLiteral('T')
572                .append(offsetElement()).toParser();
573            dp = new DateTimeFormatterBuilder()
574                .append(dateElementParser())
575                .appendOptional(tOffset)
576                .toFormatter();
577        }
578        return dp;
579    }
580 
581    /**
582     * Returns a generic ISO date parser for parsing local dates.
583     * This parser is initialised with the local (UTC) time zone.
584     * <p>
585     * It accepts formats described by the following syntax:
586     * <pre>
587     * date-element      = std-date-element | ord-date-element | week-date-element
588     * std-date-element  = yyyy ['-' MM ['-' dd]]
589     * ord-date-element  = yyyy ['-' DDD]
590     * week-date-element = xxxx '-W' ww ['-' e]
591     * </pre>
592     * @since 1.3
593     */
594    public static DateTimeFormatter localDateParser() {
595        if (ldp == null) {
596            ldp = dateElementParser().withZone(DateTimeZone.UTC);
597        }
598        return ldp;
599    }
600 
601    /**
602     * Returns a generic ISO date parser for parsing dates.
603     * It accepts formats described by the following syntax:
604     * <pre>
605     * date-element      = std-date-element | ord-date-element | week-date-element
606     * std-date-element  = yyyy ['-' MM ['-' dd]]
607     * ord-date-element  = yyyy ['-' DDD]
608     * week-date-element = xxxx '-W' ww ['-' e]
609     * </pre>
610     */
611    public static DateTimeFormatter dateElementParser() {
612        if (dpe == null) {
613            dpe = new DateTimeFormatterBuilder()
614                .append(null, new DateTimeParser[] {
615                    new DateTimeFormatterBuilder()
616                    .append(yearElement())
617                    .appendOptional
618                    (new DateTimeFormatterBuilder()
619                     .append(monthElement())
620                     .appendOptional(dayOfMonthElement().getParser())
621                     .toParser())
622                    .toParser(),
623                    new DateTimeFormatterBuilder()
624                    .append(weekyearElement())
625                    .append(weekElement())
626                    .appendOptional(dayOfWeekElement().getParser())
627                    .toParser(),
628                    new DateTimeFormatterBuilder()
629                    .append(yearElement())
630                    .append(dayOfYearElement())
631                    .toParser()
632                })
633                .toFormatter();
634        }
635        return dpe;
636    }
637 
638    /**
639     * Returns a generic ISO time parser for parsing times with a possible zone.
640     * It accepts formats described by the following syntax:
641     * <pre>
642     * time           = ['T'] time-element [offset]
643     * time-element   = HH [minute-element] | [fraction]
644     * minute-element = ':' mm [second-element] | [fraction]
645     * second-element = ':' ss [fraction]
646     * fraction       = ('.' | ',') digit+
647     * offset         = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
648     * </pre>
649     */
650    public static DateTimeFormatter timeParser() {
651        if (tp == null) {
652            tp = new DateTimeFormatterBuilder()
653                .appendOptional(literalTElement().getParser())
654                .append(timeElementParser())
655                .appendOptional(offsetElement().getParser())
656                .toFormatter();
657        }
658        return tp;
659    }
660 
661    /**
662     * Returns a generic ISO time parser for parsing local times.
663     * This parser is initialised with the local (UTC) time zone.
664     * <p>
665     * It accepts formats described by the following syntax:
666     * <pre>
667     * time           = ['T'] time-element
668     * time-element   = HH [minute-element] | [fraction]
669     * minute-element = ':' mm [second-element] | [fraction]
670     * second-element = ':' ss [fraction]
671     * fraction       = ('.' | ',') digit+
672     * </pre>
673     * @since 1.3
674     */
675    public static DateTimeFormatter localTimeParser() {
676        if (ltp == null) {
677            ltp = new DateTimeFormatterBuilder()
678                .appendOptional(literalTElement().getParser())
679                .append(timeElementParser())
680                .toFormatter().withZone(DateTimeZone.UTC);
681        }
682        return ltp;
683    }
684 
685    /**
686     * Returns a generic ISO time parser. It accepts formats described by
687     * the following syntax:
688     * <pre>
689     * time-element   = HH [minute-element] | [fraction]
690     * minute-element = ':' mm [second-element] | [fraction]
691     * second-element = ':' ss [fraction]
692     * fraction       = ('.' | ',') digit+
693     * </pre>
694     */
695    public static DateTimeFormatter timeElementParser() {
696        if (tpe == null) {
697            // Decimal point can be either '.' or ','
698            DateTimeParser decimalPoint = new DateTimeFormatterBuilder()
699                .append(null, new DateTimeParser[] {
700                    new DateTimeFormatterBuilder()
701                    .appendLiteral('.')
702                    .toParser(),
703                    new DateTimeFormatterBuilder()
704                    .appendLiteral(',')
705                    .toParser()
706                })
707                .toParser();
708 
709            tpe = new DateTimeFormatterBuilder()
710                // time-element
711                .append(hourElement())
712                .append
713                (null, new DateTimeParser[] {
714                    new DateTimeFormatterBuilder()
715                    // minute-element
716                    .append(minuteElement())
717                    .append
718                    (null, new DateTimeParser[] {
719                        new DateTimeFormatterBuilder()
720                        // second-element
721                        .append(secondElement())
722                        // second fraction
723                        .appendOptional(new DateTimeFormatterBuilder()
724                                        .append(decimalPoint)
725                                        .appendFractionOfSecond(1, 9)
726                                        .toParser())
727                        .toParser(),
728                        // minute fraction
729                        new DateTimeFormatterBuilder()
730                        .append(decimalPoint)
731                        .appendFractionOfMinute(1, 9)
732                        .toParser(),
733                        null
734                    })
735                    .toParser(),
736                    // hour fraction
737                    new DateTimeFormatterBuilder()
738                    .append(decimalPoint)
739                    .appendFractionOfHour(1, 9)
740                    .toParser(),
741                    null
742                })
743                .toFormatter();
744        }
745        return tpe;
746    }
747 
748    /**
749     * Returns a generic ISO datetime parser which parses either a date or
750     * a time or both. It accepts formats described by the following syntax:
751     * <pre>
752     * datetime          = time | date-opt-time
753     * time              = 'T' time-element [offset]
754     * date-opt-time     = date-element ['T' [time-element] [offset]]
755     * date-element      = std-date-element | ord-date-element | week-date-element
756     * std-date-element  = yyyy ['-' MM ['-' dd]]
757     * ord-date-element  = yyyy ['-' DDD]
758     * week-date-element = xxxx '-W' ww ['-' e]
759     * time-element      = HH [minute-element] | [fraction]
760     * minute-element    = ':' mm [second-element] | [fraction]
761     * second-element    = ':' ss [fraction]
762     * fraction          = ('.' | ',') digit+
763     * offset            = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
764     * </pre>
765     */
766    public static DateTimeFormatter dateTimeParser() {
767        if (dtp == null) {
768            // This is different from the general time parser in that the 'T'
769            // is required.
770            DateTimeParser time = new DateTimeFormatterBuilder()
771                .appendLiteral('T')
772                .append(timeElementParser())
773                .appendOptional(offsetElement().getParser())
774                .toParser();
775            dtp = new DateTimeFormatterBuilder()
776                .append(null, new DateTimeParser[] {time, dateOptionalTimeParser().getParser()})
777                .toFormatter();
778        }
779        return dtp;
780    }
781 
782    /**
783     * Returns a generic ISO datetime parser where the date is mandatory and
784     * the time is optional. This parser can parse zoned datetimes.
785     * It accepts formats described by the following syntax:
786     * <pre>
787     * date-opt-time     = date-element ['T' [time-element] [offset]]
788     * date-element      = std-date-element | ord-date-element | week-date-element
789     * std-date-element  = yyyy ['-' MM ['-' dd]]
790     * ord-date-element  = yyyy ['-' DDD]
791     * week-date-element = xxxx '-W' ww ['-' e]
792     * time-element      = HH [minute-element] | [fraction]
793     * minute-element    = ':' mm [second-element] | [fraction]
794     * second-element    = ':' ss [fraction]
795     * fraction          = ('.' | ',') digit+
796     * </pre>
797     * @since 1.3
798     */
799    public static DateTimeFormatter dateOptionalTimeParser() {
800        if (dotp == null) {
801            DateTimeParser timeOrOffset = new DateTimeFormatterBuilder()
802                .appendLiteral('T')
803                .appendOptional(timeElementParser().getParser())
804                .appendOptional(offsetElement().getParser())
805                .toParser();
806            dotp = new DateTimeFormatterBuilder()
807                .append(dateElementParser())
808                .appendOptional(timeOrOffset)
809                .toFormatter();
810        }
811        return dotp;
812    }
813 
814    /**
815     * Returns a generic ISO datetime parser where the date is mandatory and
816     * the time is optional. This parser only parses local datetimes.
817     * This parser is initialised with the local (UTC) time zone.
818     * <p>
819     * It accepts formats described by the following syntax:
820     * <pre>
821     * datetime          = date-element ['T' time-element]
822     * date-element      = std-date-element | ord-date-element | week-date-element
823     * std-date-element  = yyyy ['-' MM ['-' dd]]
824     * ord-date-element  = yyyy ['-' DDD]
825     * week-date-element = xxxx '-W' ww ['-' e]
826     * time-element      = HH [minute-element] | [fraction]
827     * minute-element    = ':' mm [second-element] | [fraction]
828     * second-element    = ':' ss [fraction]
829     * fraction          = ('.' | ',') digit+
830     * </pre>
831     * @since 1.3
832     */
833    public static DateTimeFormatter localDateOptionalTimeParser() {
834        if (ldotp == null) {
835            DateTimeParser time = new DateTimeFormatterBuilder()
836                .appendLiteral('T')
837                .append(timeElementParser())
838                .toParser();
839            ldotp = new DateTimeFormatterBuilder()
840                .append(dateElementParser())
841                .appendOptional(time)
842                .toFormatter().withZone(DateTimeZone.UTC);
843        }
844        return ldotp;
845    }
846 
847    //-----------------------------------------------------------------------
848    /**
849     * Returns a formatter for a full date as four digit year, two digit month
850     * of year, and two digit day of month (yyyy-MM-dd).
851     * 
852     * @return a formatter for yyyy-MM-dd
853     */
854    public static DateTimeFormatter date() {
855        return yearMonthDay();
856    }
857 
858    /**
859     * Returns a formatter for a two digit hour of day, two digit minute of
860     * hour, two digit second of minute, three digit fraction of second, and
861     * time zone offset (HH:mm:ss.SSSZZ).
862     * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
863     * 
864     * @return a formatter for HH:mm:ss.SSSZZ
865     */
866    public static DateTimeFormatter time() {
867        if (t == null) {
868            t = new DateTimeFormatterBuilder()
869                .append(hourMinuteSecondFraction())
870                .append(offsetElement())
871                .toFormatter();
872        }
873        return t;
874    }
875 
876    /**
877     * Returns a formatter for a two digit hour of day, two digit minute of
878     * hour, two digit second of minute, and time zone offset (HH:mm:ssZZ).
879     * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
880     * 
881     * @return a formatter for HH:mm:ssZZ
882     */
883    public static DateTimeFormatter timeNoMillis() {
884        if (tx == null) {
885            tx = new DateTimeFormatterBuilder()
886                .append(hourMinuteSecond())
887                .append(offsetElement())
888                .toFormatter();
889        }
890        return tx;
891    }
892 
893    /**
894     * Returns a formatter for a two digit hour of day, two digit minute of
895     * hour, two digit second of minute, three digit fraction of second, and
896     * time zone offset prefixed by 'T' ('T'HH:mm:ss.SSSZZ).
897     * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
898     * 
899     * @return a formatter for 'T'HH:mm:ss.SSSZZ
900     */
901    public static DateTimeFormatter tTime() {
902        if (tt == null) {
903            tt = new DateTimeFormatterBuilder()
904                .append(literalTElement())
905                .append(time())
906                .toFormatter();
907        }
908        return tt;
909    }
910 
911    /**
912     * Returns a formatter for a two digit hour of day, two digit minute of
913     * hour, two digit second of minute, and time zone offset prefixed
914     * by 'T' ('T'HH:mm:ssZZ).
915     * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
916     * 
917     * @return a formatter for 'T'HH:mm:ssZZ
918     */
919    public static DateTimeFormatter tTimeNoMillis() {
920        if (ttx == null) {
921            ttx = new DateTimeFormatterBuilder()
922                .append(literalTElement())
923                .append(timeNoMillis())
924                .toFormatter();
925        }
926        return ttx;
927    }
928 
929    /**
930     * Returns a formatter that combines a full date and time, separated by a 'T'
931     * (yyyy-MM-dd'T'HH:mm:ss.SSSZZ).
932     * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
933     * 
934     * @return a formatter for yyyy-MM-dd'T'HH:mm:ss.SSSZZ
935     */
936    public static DateTimeFormatter dateTime() {
937        if (dt == null) {
938            dt = new DateTimeFormatterBuilder()
939                .append(date())
940                .append(tTime())
941                .toFormatter();
942        }
943        return dt;
944    }
945 
946    /**
947     * Returns a formatter that combines a full date and time without millis,
948     * separated by a 'T' (yyyy-MM-dd'T'HH:mm:ssZZ).
949     * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
950     * 
951     * @return a formatter for yyyy-MM-dd'T'HH:mm:ssZZ
952     */
953    public static DateTimeFormatter dateTimeNoMillis() {
954        if (dtx == null) {
955            dtx = new DateTimeFormatterBuilder()
956                .append(date())
957                .append(tTimeNoMillis())
958                .toFormatter();
959        }
960        return dtx;
961    }
962 
963    /**
964     * Returns a formatter for a full ordinal date, using a four
965     * digit year and three digit dayOfYear (yyyy-DDD).
966     * 
967     * @return a formatter for yyyy-DDD
968     * @since 1.1
969     */
970    public static DateTimeFormatter ordinalDate() {
971        if (od == null) {
972            od = new DateTimeFormatterBuilder()
973                .append(yearElement())
974                .append(dayOfYearElement())
975                .toFormatter();
976        }
977        return od;
978    }
979 
980    /**
981     * Returns a formatter for a full ordinal date and time, using a four
982     * digit year and three digit dayOfYear (yyyy-DDD'T'HH:mm:ss.SSSZZ).
983     * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
984     * 
985     * @return a formatter for yyyy-DDD'T'HH:mm:ss.SSSZZ
986     * @since 1.1
987     */
988    public static DateTimeFormatter ordinalDateTime() {
989        if (odt == null) {
990            odt = new DateTimeFormatterBuilder()
991                .append(ordinalDate())
992                .append(tTime())
993                .toFormatter();
994        }
995        return odt;
996    }
997 
998    /**
999     * Returns a formatter for a full ordinal date and time without millis,
1000     * using a four digit year and three digit dayOfYear (yyyy-DDD'T'HH:mm:ssZZ).
1001     * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1002     * 
1003     * @return a formatter for yyyy-DDD'T'HH:mm:ssZZ
1004     * @since 1.1
1005     */
1006    public static DateTimeFormatter ordinalDateTimeNoMillis() {
1007        if (odtx == null) {
1008            odtx = new DateTimeFormatterBuilder()
1009                .append(ordinalDate())
1010                .append(tTimeNoMillis())
1011                .toFormatter();
1012        }
1013        return odtx;
1014    }
1015 
1016    /**
1017     * Returns a formatter for a full date as four digit weekyear, two digit
1018     * week of weekyear, and one digit day of week (xxxx-'W'ww-e).
1019     * 
1020     * @return a formatter for xxxx-'W'ww-e
1021     */
1022    public static DateTimeFormatter weekDate() {
1023        return weekyearWeekDay();
1024    }
1025 
1026    /**
1027     * Returns a formatter that combines a full weekyear date and time,
1028     * separated by a 'T' (xxxx-'W'ww-e'T'HH:mm:ss.SSSZZ).
1029     * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1030     * 
1031     * @return a formatter for xxxx-'W'ww-e'T'HH:mm:ss.SSSZZ
1032     */
1033    public static DateTimeFormatter weekDateTime() {
1034        if (wdt == null) {
1035            wdt = new DateTimeFormatterBuilder()
1036                .append(weekDate())
1037                .append(tTime())
1038                .toFormatter();
1039        }
1040        return wdt;
1041    }
1042 
1043    /**
1044     * Returns a formatter that combines a full weekyear date and time without millis,
1045     * separated by a 'T' (xxxx-'W'ww-e'T'HH:mm:ssZZ).
1046     * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1047     * 
1048     * @return a formatter for xxxx-'W'ww-e'T'HH:mm:ssZZ
1049     */
1050    public static DateTimeFormatter weekDateTimeNoMillis() {
1051        if (wdtx == null) {
1052            wdtx = new DateTimeFormatterBuilder()
1053                .append(weekDate())
1054                .append(tTimeNoMillis())
1055                .toFormatter();
1056        }
1057        return wdtx;
1058    }
1059 
1060    //-----------------------------------------------------------------------
1061    /**
1062     * Returns a basic formatter for a full date as four digit year, two digit
1063     * month of year, and two digit day of month (yyyyMMdd).
1064     * 
1065     * @return a formatter for yyyyMMdd
1066     */
1067    public static DateTimeFormatter basicDate() {
1068        if (bd == null) {
1069            bd = new DateTimeFormatterBuilder()
1070                .appendYear(4, 4)
1071                .appendFixedDecimal(DateTimeFieldType.monthOfYear(), 2)
1072                .appendFixedDecimal(DateTimeFieldType.dayOfMonth(), 2)
1073                .toFormatter();
1074        }
1075        return bd;
1076    }
1077 
1078    /**
1079     * Returns a basic formatter for a two digit hour of day, two digit minute
1080     * of hour, two digit second of minute, three digit millis, and time zone
1081     * offset (HHmmss.SSSZ).
1082     * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero.
1083     * 
1084     * @return a formatter for HHmmss.SSSZ
1085     */
1086    public static DateTimeFormatter basicTime() {
1087        if (bt == null) {
1088            bt = new DateTimeFormatterBuilder()
1089                .appendFixedDecimal(DateTimeFieldType.hourOfDay(), 2)
1090                .appendFixedDecimal(DateTimeFieldType.minuteOfHour(), 2)
1091                .appendFixedDecimal(DateTimeFieldType.secondOfMinute(), 2)
1092                .appendLiteral('.')
1093                .appendFractionOfSecond(3, 9)
1094                .appendTimeZoneOffset("Z", false, 2, 2)
1095                .toFormatter();
1096        }
1097        return bt;
1098    }
1099 
1100    /**
1101     * Returns a basic formatter for a two digit hour of day, two digit minute
1102     * of hour, two digit second of minute, and time zone offset (HHmmssZ).
1103     * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero.
1104     * 
1105     * @return a formatter for HHmmssZ
1106     */
1107    public static DateTimeFormatter basicTimeNoMillis() {
1108        if (btx == null) {
1109            btx = new DateTimeFormatterBuilder()
1110                .appendFixedDecimal(DateTimeFieldType.hourOfDay(), 2)
1111                .appendFixedDecimal(DateTimeFieldType.minuteOfHour(), 2)
1112                .appendFixedDecimal(DateTimeFieldType.secondOfMinute(), 2)
1113                .appendTimeZoneOffset("Z", false, 2, 2)
1114                .toFormatter();
1115        }
1116        return btx;
1117    }
1118 
1119    /**
1120     * Returns a basic formatter for a two digit hour of day, two digit minute
1121     * of hour, two digit second of minute, three digit millis, and time zone
1122     * offset prefixed by 'T' ('T'HHmmss.SSSZ).
1123     * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero.
1124     * 
1125     * @return a formatter for 'T'HHmmss.SSSZ
1126     */
1127    public static DateTimeFormatter basicTTime() {
1128        if (btt == null) {
1129            btt = new DateTimeFormatterBuilder()
1130                .append(literalTElement())
1131                .append(basicTime())
1132                .toFormatter();
1133        }
1134        return btt;
1135    }
1136 
1137    /**
1138     * Returns a basic formatter for a two digit hour of day, two digit minute
1139     * of hour, two digit second of minute, and time zone offset prefixed by 'T'
1140     * ('T'HHmmssZ).
1141     * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero.
1142     * 
1143     * @return a formatter for 'T'HHmmssZ
1144     */
1145    public static DateTimeFormatter basicTTimeNoMillis() {
1146        if (bttx == null) {
1147            bttx = new DateTimeFormatterBuilder()
1148                .append(literalTElement())
1149                .append(basicTimeNoMillis())
1150                .toFormatter();
1151        }
1152        return bttx;
1153    }
1154 
1155    /**
1156     * Returns a basic formatter that combines a basic date and time, separated
1157     * by a 'T' (yyyyMMdd'T'HHmmss.SSSZ).
1158     * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero.
1159     * 
1160     * @return a formatter for yyyyMMdd'T'HHmmss.SSSZ
1161     */
1162    public static DateTimeFormatter basicDateTime() {
1163        if (bdt == null) {
1164            bdt = new DateTimeFormatterBuilder()
1165                .append(basicDate())
1166                .append(basicTTime())
1167                .toFormatter();
1168        }
1169        return bdt;
1170    }
1171 
1172    /**
1173     * Returns a basic formatter that combines a basic date and time without millis,
1174     * separated by a 'T' (yyyyMMdd'T'HHmmssZ).
1175     * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero.
1176     * 
1177     * @return a formatter for yyyyMMdd'T'HHmmssZ
1178     */
1179    public static DateTimeFormatter basicDateTimeNoMillis() {
1180        if (bdtx == null) {
1181            bdtx = new DateTimeFormatterBuilder()
1182                .append(basicDate())
1183                .append(basicTTimeNoMillis())
1184                .toFormatter();
1185        }
1186        return bdtx;
1187    }
1188 
1189    /**
1190     * Returns a formatter for a full ordinal date, using a four
1191     * digit year and three digit dayOfYear (yyyyDDD).
1192     * 
1193     * @return a formatter for yyyyDDD
1194     * @since 1.1
1195     */
1196    public static DateTimeFormatter basicOrdinalDate() {
1197        if (bod == null) {
1198            bod = new DateTimeFormatterBuilder()
1199                .appendYear(4, 4)
1200                .appendFixedDecimal(DateTimeFieldType.dayOfYear(), 3)
1201                .toFormatter();
1202        }
1203        return bod;
1204    }
1205 
1206    /**
1207     * Returns a formatter for a full ordinal date and time, using a four
1208     * digit year and three digit dayOfYear (yyyyDDD'T'HHmmss.SSSZ).
1209     * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero.
1210     * 
1211     * @return a formatter for yyyyDDD'T'HHmmss.SSSZ
1212     * @since 1.1
1213     */
1214    public static DateTimeFormatter basicOrdinalDateTime() {
1215        if (bodt == null) {
1216            bodt = new DateTimeFormatterBuilder()
1217                .append(basicOrdinalDate())
1218                .append(basicTTime())
1219                .toFormatter();
1220        }
1221        return bodt;
1222    }
1223 
1224    /**
1225     * Returns a formatter for a full ordinal date and time without millis,
1226     * using a four digit year and three digit dayOfYear (yyyyDDD'T'HHmmssZ).
1227     * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero.
1228     * 
1229     * @return a formatter for yyyyDDD'T'HHmmssZ
1230     * @since 1.1
1231     */
1232    public static DateTimeFormatter basicOrdinalDateTimeNoMillis() {
1233        if (bodtx == null) {
1234            bodtx = new DateTimeFormatterBuilder()
1235                .append(basicOrdinalDate())
1236                .append(basicTTimeNoMillis())
1237                .toFormatter();
1238        }
1239        return bodtx;
1240    }
1241 
1242    /**
1243     * Returns a basic formatter for a full date as four digit weekyear, two
1244     * digit week of weekyear, and one digit day of week (xxxx'W'wwe).
1245     * 
1246     * @return a formatter for xxxx'W'wwe
1247     */
1248    public static DateTimeFormatter basicWeekDate() {
1249        if (bwd == null) {
1250            bwd = new DateTimeFormatterBuilder()
1251                .appendWeekyear(4, 4)
1252                .appendLiteral('W')
1253                .appendFixedDecimal(DateTimeFieldType.weekOfWeekyear(), 2)
1254                .appendFixedDecimal(DateTimeFieldType.dayOfWeek(), 1)
1255                .toFormatter();
1256        }
1257        return bwd;
1258    }
1259 
1260    /**
1261     * Returns a basic formatter that combines a basic weekyear date and time,
1262     * separated by a 'T' (xxxx'W'wwe'T'HHmmss.SSSZ).
1263     * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero.
1264     * 
1265     * @return a formatter for xxxx'W'wwe'T'HHmmss.SSSZ
1266     */
1267    public static DateTimeFormatter basicWeekDateTime() {
1268        if (bwdt == null) {
1269            bwdt = new DateTimeFormatterBuilder()
1270                .append(basicWeekDate())
1271                .append(basicTTime())
1272                .toFormatter();
1273        }
1274        return bwdt;
1275    }
1276 
1277    /**
1278     * Returns a basic formatter that combines a basic weekyear date and time
1279     * without millis, separated by a 'T' (xxxx'W'wwe'T'HHmmssZ).
1280     * The time zone offset is 'Z' for zero, and of the form '\u00b1HHmm' for non-zero.
1281     * 
1282     * @return a formatter for xxxx'W'wwe'T'HHmmssZ
1283     */
1284    public static DateTimeFormatter basicWeekDateTimeNoMillis() {
1285        if (bwdtx == null) {
1286            bwdtx = new DateTimeFormatterBuilder()
1287                .append(basicWeekDate())
1288                .append(basicTTimeNoMillis())
1289                .toFormatter();
1290        }
1291        return bwdtx;
1292    }
1293 
1294    //-----------------------------------------------------------------------
1295    /**
1296     * Returns a formatter for a four digit year. (yyyy)
1297     * 
1298     * @return a formatter for yyyy
1299     */
1300    public static DateTimeFormatter year() {
1301        return yearElement();
1302    }
1303 
1304    /**
1305     * Returns a formatter for a four digit year and two digit month of
1306     * year. (yyyy-MM)
1307     * 
1308     * @return a formatter for yyyy-MM
1309     */
1310    public static DateTimeFormatter yearMonth() {
1311        if (ym == null) {
1312            ym = new DateTimeFormatterBuilder()
1313                .append(yearElement())
1314                .append(monthElement())
1315                .toFormatter();
1316        }
1317        return ym;
1318    }
1319 
1320    /**
1321     * Returns a formatter for a four digit year, two digit month of year, and
1322     * two digit day of month. (yyyy-MM-dd)
1323     * 
1324     * @return a formatter for yyyy-MM-dd
1325     */
1326    public static DateTimeFormatter yearMonthDay() {
1327        if (ymd == null) {
1328            ymd = new DateTimeFormatterBuilder()
1329                .append(yearElement())
1330                .append(monthElement())
1331                .append(dayOfMonthElement())
1332                .toFormatter();
1333        }
1334        return ymd;
1335    }
1336 
1337    /**
1338     * Returns a formatter for a four digit weekyear. (xxxx)
1339     * 
1340     * @return a formatter for xxxx
1341     */
1342    public static DateTimeFormatter weekyear() {
1343        return weekyearElement();
1344    }
1345 
1346    /**
1347     * Returns a formatter for a four digit weekyear and two digit week of
1348     * weekyear. (xxxx-'W'ww)
1349     * 
1350     * @return a formatter for xxxx-'W'ww
1351     */
1352    public static DateTimeFormatter weekyearWeek() {
1353        if (ww == null) {
1354            ww = new DateTimeFormatterBuilder()
1355                .append(weekyearElement())
1356                .append(weekElement())
1357                .toFormatter();
1358        }
1359        return ww;
1360    }
1361 
1362    /**
1363     * Returns a formatter for a four digit weekyear, two digit week of
1364     * weekyear, and one digit day of week. (xxxx-'W'ww-e)
1365     * 
1366     * @return a formatter for xxxx-'W'ww-e
1367     */
1368    public static DateTimeFormatter weekyearWeekDay() {
1369        if (wwd == null) {
1370            wwd = new DateTimeFormatterBuilder()
1371                .append(weekyearElement())
1372                .append(weekElement())
1373                .append(dayOfWeekElement())
1374                .toFormatter();
1375        }
1376        return wwd;
1377    }
1378 
1379    /**
1380     * Returns a formatter for a two digit hour of day. (HH)
1381     * 
1382     * @return a formatter for HH
1383     */
1384    public static DateTimeFormatter hour() {
1385        return hourElement();
1386    }
1387 
1388    /**
1389     * Returns a formatter for a two digit hour of day and two digit minute of
1390     * hour. (HH:mm)
1391     * 
1392     * @return a formatter for HH:mm
1393     */
1394    public static DateTimeFormatter hourMinute() {
1395        if (hm == null) {
1396            hm = new DateTimeFormatterBuilder()
1397                .append(hourElement())
1398                .append(minuteElement())
1399                .toFormatter();
1400        }
1401        return hm;
1402    }
1403 
1404    /**
1405     * Returns a formatter for a two digit hour of day, two digit minute of
1406     * hour, and two digit second of minute. (HH:mm:ss)
1407     * 
1408     * @return a formatter for HH:mm:ss
1409     */
1410    public static DateTimeFormatter hourMinuteSecond() {
1411        if (hms == null) {
1412            hms = new DateTimeFormatterBuilder()
1413                .append(hourElement())
1414                .append(minuteElement())
1415                .append(secondElement())
1416                .toFormatter();
1417        }
1418        return hms;
1419    }
1420 
1421    /**
1422     * Returns a formatter for a two digit hour of day, two digit minute of
1423     * hour, two digit second of minute, and three digit fraction of
1424     * second (HH:mm:ss.SSS). Parsing will parse up to 3 fractional second
1425     * digits.
1426     * 
1427     * @return a formatter for HH:mm:ss.SSS
1428     */
1429    public static DateTimeFormatter hourMinuteSecondMillis() {
1430        if (hmsl == null) {
1431            hmsl = new DateTimeFormatterBuilder()
1432                .append(hourElement())
1433                .append(minuteElement())
1434                .append(secondElement())
1435                .appendLiteral('.')
1436                .appendFractionOfSecond(3, 3)
1437                .toFormatter();
1438        }
1439        return hmsl;
1440    }
1441 
1442    /**
1443     * Returns a formatter for a two digit hour of day, two digit minute of
1444     * hour, two digit second of minute, and three digit fraction of
1445     * second (HH:mm:ss.SSS). Parsing will parse up to 9 fractional second
1446     * digits, throwing away all except the first three.
1447     * 
1448     * @return a formatter for HH:mm:ss.SSS
1449     */
1450    public static DateTimeFormatter hourMinuteSecondFraction() {
1451        if (hmsf == null) {
1452            hmsf = new DateTimeFormatterBuilder()
1453                .append(hourElement())
1454                .append(minuteElement())
1455                .append(secondElement())
1456                .append(fractionElement())
1457                .toFormatter();
1458        }
1459        return hmsf;
1460    }
1461 
1462    /**
1463     * Returns a formatter that combines a full date and two digit hour of
1464     * day. (yyyy-MM-dd'T'HH)
1465     * 
1466     * @return a formatter for yyyy-MM-dd'T'HH
1467     */
1468    public static DateTimeFormatter dateHour() {
1469        if (dh == null) {
1470            dh = new DateTimeFormatterBuilder()
1471                .append(date())
1472                .append(literalTElement())
1473                .append(hour())
1474                .toFormatter();
1475        }
1476        return dh;
1477    }
1478 
1479    /**
1480     * Returns a formatter that combines a full date, two digit hour of day,
1481     * and two digit minute of hour. (yyyy-MM-dd'T'HH:mm)
1482     * 
1483     * @return a formatter for yyyy-MM-dd'T'HH:mm
1484     */
1485    public static DateTimeFormatter dateHourMinute() {
1486        if (dhm == null) {
1487            dhm = new DateTimeFormatterBuilder()
1488                .append(date())
1489                .append(literalTElement())
1490                .append(hourMinute())
1491                .toFormatter();
1492        }
1493        return dhm;
1494    }
1495 
1496    /**
1497     * Returns a formatter that combines a full date, two digit hour of day,
1498     * two digit minute of hour, and two digit second of
1499     * minute. (yyyy-MM-dd'T'HH:mm:ss)
1500     * 
1501     * @return a formatter for yyyy-MM-dd'T'HH:mm:ss
1502     */
1503    public static DateTimeFormatter dateHourMinuteSecond() {
1504        if (dhms == null) {
1505            dhms = new DateTimeFormatterBuilder()
1506                .append(date())
1507                .append(literalTElement())
1508                .append(hourMinuteSecond())
1509                .toFormatter();
1510        }
1511        return dhms;
1512    }
1513 
1514    /**
1515     * Returns a formatter that combines a full date, two digit hour of day,
1516     * two digit minute of hour, two digit second of minute, and three digit
1517     * fraction of second (yyyy-MM-dd'T'HH:mm:ss.SSS). Parsing will parse up
1518     * to 3 fractional second digits.
1519     * 
1520     * @return a formatter for yyyy-MM-dd'T'HH:mm:ss.SSS
1521     */
1522    public static DateTimeFormatter dateHourMinuteSecondMillis() {
1523        if (dhmsl == null) {
1524            dhmsl = new DateTimeFormatterBuilder()
1525                .append(date())
1526                .append(literalTElement())
1527                .append(hourMinuteSecondMillis())
1528                .toFormatter();
1529        }
1530        return dhmsl;
1531    }
1532 
1533    /**
1534     * Returns a formatter that combines a full date, two digit hour of day,
1535     * two digit minute of hour, two digit second of minute, and three digit
1536     * fraction of second (yyyy-MM-dd'T'HH:mm:ss.SSS). Parsing will parse up
1537     * to 9 fractional second digits, throwing away all except the first three.
1538     * 
1539     * @return a formatter for yyyy-MM-dd'T'HH:mm:ss.SSS
1540     */
1541    public static DateTimeFormatter dateHourMinuteSecondFraction() {
1542        if (dhmsf == null) {
1543            dhmsf = new DateTimeFormatterBuilder()
1544                .append(date())
1545                .append(literalTElement())
1546                .append(hourMinuteSecondFraction())
1547                .toFormatter();
1548        }
1549        return dhmsf;
1550    }
1551 
1552    //-----------------------------------------------------------------------
1553    private static DateTimeFormatter yearElement() {
1554        if (ye == null) {
1555            ye = new DateTimeFormatterBuilder()
1556                .appendYear(4, 9)
1557                .toFormatter();
1558        }
1559        return ye;
1560    }
1561 
1562    private static DateTimeFormatter monthElement() {
1563        if (mye == null) {
1564            mye = new DateTimeFormatterBuilder()
1565                .appendLiteral('-')
1566                .appendMonthOfYear(2)
1567                .toFormatter();
1568        }
1569        return mye;
1570    }
1571 
1572    private static DateTimeFormatter dayOfMonthElement() {
1573        if (dme == null) {
1574            dme = new DateTimeFormatterBuilder()
1575                .appendLiteral('-')
1576                .appendDayOfMonth(2)
1577                .toFormatter();
1578        }
1579        return dme;
1580    }
1581 
1582    private static DateTimeFormatter weekyearElement() {
1583        if (we == null) {
1584            we = new DateTimeFormatterBuilder()
1585                .appendWeekyear(4, 9)
1586                .toFormatter();
1587        }
1588        return we;
1589    }
1590 
1591    private static DateTimeFormatter weekElement() {
1592        if (wwe == null) {
1593            wwe = new DateTimeFormatterBuilder()
1594                .appendLiteral("-W")
1595                .appendWeekOfWeekyear(2)
1596                .toFormatter();
1597        }
1598        return wwe;
1599    }
1600 
1601    private static DateTimeFormatter dayOfWeekElement() {
1602        if (dwe == null) {
1603            dwe = new DateTimeFormatterBuilder()
1604                .appendLiteral('-')
1605                .appendDayOfWeek(1)
1606                .toFormatter();
1607        }
1608        return dwe;
1609    }
1610 
1611    private static DateTimeFormatter dayOfYearElement() {
1612        if (dye == null) {
1613            dye = new DateTimeFormatterBuilder()
1614                .appendLiteral('-')
1615                .appendDayOfYear(3)
1616                .toFormatter();
1617        }
1618        return dye;
1619    }
1620    
1621    private static DateTimeFormatter literalTElement() {
1622        if (lte == null) {
1623            lte = new DateTimeFormatterBuilder()
1624                .appendLiteral('T')
1625                .toFormatter();
1626        }
1627        return lte;
1628    }
1629 
1630    private static DateTimeFormatter hourElement() {
1631        if (hde == null) {
1632            hde = new DateTimeFormatterBuilder()
1633                .appendHourOfDay(2)
1634                .toFormatter();
1635        }
1636        return hde;
1637    }
1638 
1639    private static DateTimeFormatter minuteElement() {
1640        if (mhe == null) {
1641            mhe = new DateTimeFormatterBuilder()
1642                .appendLiteral(':')
1643                .appendMinuteOfHour(2)
1644                .toFormatter();
1645        }
1646        return mhe;
1647    }
1648 
1649    private static DateTimeFormatter secondElement() {
1650        if (sme == null) {
1651            sme = new DateTimeFormatterBuilder()
1652                .appendLiteral(':')
1653                .appendSecondOfMinute(2)
1654                .toFormatter();
1655        }
1656        return sme;
1657    }
1658 
1659    private static DateTimeFormatter fractionElement() {
1660        if (fse == null) {
1661            fse = new DateTimeFormatterBuilder()
1662                .appendLiteral('.')
1663                // Support parsing up to nanosecond precision even though
1664                // those extra digits will be dropped.
1665                .appendFractionOfSecond(3, 9)
1666                .toFormatter();
1667        }
1668        return fse;
1669    }
1670 
1671    private static DateTimeFormatter offsetElement() {
1672        if (ze == null) {
1673            ze = new DateTimeFormatterBuilder()
1674                .appendTimeZoneOffset("Z", true, 2, 4)
1675                .toFormatter();
1676        }
1677        return ze;
1678    }
1679 
1680}

[all classes][org.joda.time.format]
EMMA 2.0.5312 (C) Vladimir Roubtsov