1 /*
2  *  Copyright 2001-2014 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  */

16 package org.joda.time.format;
17
18 import java.io.IOException;
19 import java.io.Writer;
20 import java.util.Locale;
21
22 import org.joda.time.Chronology;
23 import org.joda.time.DateTime;
24 import org.joda.time.DateTimeUtils;
25 import org.joda.time.DateTimeZone;
26 import org.joda.time.LocalDate;
27 import org.joda.time.LocalDateTime;
28 import org.joda.time.LocalTime;
29 import org.joda.time.MutableDateTime;
30 import org.joda.time.ReadWritableInstant;
31 import org.joda.time.ReadableInstant;
32 import org.joda.time.ReadablePartial;
33
34 /**
35  * Controls the printing and parsing of a datetime to and from a string.
36  * <p>
37  * This class is the main API for printing and parsing used by most applications.
38  * Instances of this class are created via one of three factory classes:
39  * <ul>
40  * <li>{@link DateTimeFormat} - formats by pattern and style</li>
41  * <li>{@link ISODateTimeFormat} - ISO8601 formats</li>
42  * <li>{@link DateTimeFormatterBuilder} - complex formats created via method calls</li>
43  * </ul>
44  * <p>
45  * An instance of this class holds a reference internally to one printer and
46  * one parser. It is possible that one of these may be null, in which case the
47  * formatter cannot print/parse. This can be checked via the {@link #isPrinter()}
48  * and {@link #isParser()} methods.
49  * <p>
50  * The underlying printer/parser can be altered to behave exactly as required
51  * by using one of the decorator modifiers:
52  * <ul>
53  * <li>{@link #withLocale(Locale)} - returns a new formatter that uses the specified locale</li>
54  * <li>{@link #withZone(DateTimeZone)} - returns a new formatter that uses the specified time zone</li>
55  * <li>{@link #withChronology(Chronology)} - returns a new formatter that uses the specified chronology</li>
56  * <li>{@link #withOffsetParsed()} - returns a new formatter that returns the parsed time zone offset</li>
57  * <li>{@link #withPivotYear(int)} - returns a new formatter with the specified pivot year</li>
58  * <li>{@link #withDefaultYear(int)} - returns a new formatter with the specified default year</li>
59  * </ul>
60  * Each of these returns a new formatter (instances of this class are immutable).
61  * <p>
62  * The main methods of the class are the <code>printXxx</code> and
63  * <code>parseXxx</code> methods. These are used as follows:
64  * <pre>
65  * // print using the defaults (default locale, chronology/zone of the datetime)
66  * String dateStr = formatter.print(dt);
67  * // print using the French locale
68  * String dateStr = formatter.withLocale(Locale.FRENCH).print(dt);
69  * // print using the UTC zone
70  * String dateStr = formatter.withZone(DateTimeZone.UTC).print(dt);
71  * 
72  * // parse using the Paris zone
73  * DateTime date = formatter.withZone(DateTimeZone.forID("Europe/Paris")).parseDateTime(str);
74  * </pre>
75  * <p>
76  * Parsing builds up the resultant instant by 'setting' the value of each parsed field
77  * from largest to smallest onto an initial instant, typically 1970-01-01T00:00Z.
78  * This design means that day-of-month is set before day-of-week.
79  * As such, if both the day-of-month and day-of-week are parsed, and the day-of-week
80  * is incorrect, then the day-of-week overrides the day-of-month.
81  * 
82  * This has a side effect if the input is not consistent.
83  * 
84  * 
85  * @author Brian S O'Neill
86  * @author Stephen Colebourne
87  * @author Fredrik Borgh
88  * @since 1.0
89  */

90 public class DateTimeFormatter {
91
92     /** The internal printer used to output the datetime. */
93     private final InternalPrinter iPrinter;
94     /** The internal parser used to output the datetime. */
95     private final InternalParser iParser;
96     /** The locale to use for printing and parsing. */
97     private final Locale iLocale;
98     /** Whether the offset is parsed. */
99     private final boolean iOffsetParsed;
100     /** The chronology to use as an override. */
101     private final Chronology iChrono;
102     /** The zone to use as an override. */
103     private final DateTimeZone iZone;
104     /** The pivot year to use for two-digit year parsing. */
105     private final Integer iPivotYear;
106     /** The default year for parsing month/day without year. */
107     private final int iDefaultYear;
108
109     /**
110      * Creates a new formatter, however you will normally use the factory
111      * or the builder.
112      * 
113      * @param printer  the internal printer, null if cannot print
114      * @param parser  the internal parser, null if cannot parse
115      */

116     public DateTimeFormatter(
117             DateTimePrinter printer, DateTimeParser parser) {
118         this(DateTimePrinterInternalPrinter.of(printer), DateTimeParserInternalParser.of(parser));
119     }
120
121     /**
122      * Creates a new formatter, however you will normally use the factory
123      * or the builder.
124      * 
125      * @param printer  the internal printer, null if cannot print
126      * @param parser  the internal parser, null if cannot parse
127      */

128     DateTimeFormatter(
129             InternalPrinter printer, InternalParser parser) {
130         super();
131         iPrinter = printer;
132         iParser = parser;
133         iLocale = null;
134         iOffsetParsed = false;
135         iChrono = null;
136         iZone = null;
137         iPivotYear = null;
138         iDefaultYear = 2000;
139     }
140
141     /**
142      * Constructor.
143      */

144     private DateTimeFormatter(
145             InternalPrinter printer, InternalParser parser,
146             Locale locale, boolean offsetParsed,
147             Chronology chrono, DateTimeZone zone,
148             Integer pivotYear, int defaultYear) {
149         super();
150         iPrinter = printer;
151         iParser = parser;
152         iLocale = locale;
153         iOffsetParsed = offsetParsed;
154         iChrono = chrono;
155         iZone = zone;
156         iPivotYear = pivotYear;
157         iDefaultYear = defaultYear;
158     }
159
160     //-----------------------------------------------------------------------
161     /**
162      * Is this formatter capable of printing.
163      * 
164      * @return true if this is a printer
165      */

166     public boolean isPrinter() {
167         return (iPrinter != null);
168     }
169
170     /**
171      * Gets the internal printer object that performs the real printing work.
172      * 
173      * @return the internal printer; is null if printing not supported
174      */

175     public DateTimePrinter getPrinter() {
176         return InternalPrinterDateTimePrinter.of(iPrinter);
177     }
178
179     /**
180      * Gets the internal printer object that performs the real printing work.
181      * 
182      * @return the internal printer; is null if printing not supported
183      */

184     InternalPrinter getPrinter0() {
185         return iPrinter;
186     }
187
188     /**
189      * Is this formatter capable of parsing.
190      * 
191      * @return true if this is a parser
192      */

193     public boolean isParser() {
194         return (iParser != null);
195     }
196
197     /**
198      * Gets the internal parser object that performs the real parsing work.
199      * 
200      * @return the internal parser; is null if parsing not supported
201      */

202     public DateTimeParser getParser() {
203         return InternalParserDateTimeParser.of(iParser);
204     }
205
206     InternalParser getParser0() {
207         return iParser;
208     }
209
210     //-----------------------------------------------------------------------
211     /**
212      * Returns a new formatter with a different locale that will be used
213      * for printing and parsing.
214      * <p>
215      * A DateTimeFormatter is immutable, so a new instance is returned,
216      * and the original is unaltered and still usable.
217      * 
218      * @param locale the locale to use; if null, formatter uses default locale
219      * at invocation time
220      * @return the new formatter
221      */

222     public DateTimeFormatter withLocale(Locale locale) {
223         if (locale == getLocale() || (locale != null && locale.equals(getLocale()))) {
224             return this;
225         }
226         return new DateTimeFormatter(iPrinter, iParser, locale,
227                 iOffsetParsed, iChrono, iZone, iPivotYear, iDefaultYear);
228     }
229
230     /**
231      * Gets the locale that will be used for printing and parsing.
232      * 
233      * @return the locale to use; if null, formatter uses default locale at
234      * invocation time
235      */

236     public Locale getLocale() {
237         return iLocale;
238     }
239
240     //-----------------------------------------------------------------------
241     /**
242      * Returns a new formatter that will create a datetime with a time zone
243      * equal to that of the offset of the parsed string.
244      * <p>
245      * After calling this method, a string '2004-06-09T10:20:30-08:00' will
246      * create a datetime with a zone of -08:00 (a fixed zone, with no daylight
247      * savings rules). If the parsed string represents a local time (no zone
248      * offset) the parsed datetime will be in the default zone.
249      * <p>
250      * Calling this method sets the override zone to null.
251      * Calling the override zone method sets this flag off.
252      * 
253      * @return the new formatter
254      */

255     public DateTimeFormatter withOffsetParsed() {
256         if (iOffsetParsed == true) {
257             return this;
258         }
259         return new DateTimeFormatter(iPrinter, iParser, iLocale,
260                 true, iChrono, null, iPivotYear, iDefaultYear);
261     }
262
263     /**
264      * Checks whether the offset from the string is used as the zone of
265      * the parsed datetime.
266      * 
267      * @return true if the offset from the string is used as the zone
268      */

269     public boolean isOffsetParsed() {
270         return iOffsetParsed;
271     }
272
273     //-----------------------------------------------------------------------
274     /**
275      * Returns a new formatter that will use the specified chronology in
276      * preference to that of the printed object, or ISO on a parse.
277      * <p>
278      * When printing, this chronology will be used in preference to the chronology
279      * from the datetime that would otherwise be used.
280      * <p>
281      * When parsing, this chronology will be set on the parsed datetime.
282      * <p>
283      * A null chronology means no-override.
284      * If both an override chronology and an override zone are set, the
285      * override zone will take precedence over the zone in the chronology.
286      * 
287      * @param chrono  the chronology to use as an override
288      * @return the new formatter
289      */

290     public DateTimeFormatter withChronology(Chronology chrono) {
291         if (iChrono == chrono) {
292             return this;
293         }
294         return new DateTimeFormatter(iPrinter, iParser, iLocale,
295                 iOffsetParsed, chrono, iZone, iPivotYear, iDefaultYear);
296     }
297
298     /**
299      * Gets the chronology to use as an override.
300      * 
301      * @return the chronology to use as an override
302      */

303     public Chronology getChronology() {
304         return iChrono;
305     }
306
307     /**
308      * Gets the chronology to use as an override.
309      * 
310      * @return the chronology to use as an override
311      * @deprecated Use the method with the correct spelling
312      */

313     @Deprecated
314     public Chronology getChronolgy() {
315         return iChrono;
316     }
317
318     //-----------------------------------------------------------------------
319     /**
320      * Returns a new formatter that will use the UTC zone in preference
321      * to the zone of the printed object, or default zone on a parse.
322      * <p>
323      * When printing, UTC will be used in preference to the zone
324      * from the datetime that would otherwise be used.
325      * <p>
326      * When parsing, UTC will be set on the parsed datetime.
327      * <p>
328      * If both an override chronology and an override zone are set, the
329      * override zone will take precedence over the zone in the chronology.
330      * 
331      * @return the new formatter, never null
332      * @since 2.0
333      */

334     public DateTimeFormatter withZoneUTC() {
335         return withZone(DateTimeZone.UTC);
336     }
337
338     /**
339      * Returns a new formatter that will use the specified zone in preference
340      * to the zone of the printed object, or default zone on a parse.
341      * <p>
342      * When printing, this zone will be used in preference to the zone
343      * from the datetime that would otherwise be used.
344      * <p>
345      * When parsing, this zone will be set on the parsed datetime.
346      * <p>
347      * A null zone means of no-override.
348      * If both an override chronology and an override zone are set, the
349      * override zone will take precedence over the zone in the chronology.
350      * 
351      * @param zone  the zone to use as an override
352      * @return the new formatter
353      */

354     public DateTimeFormatter withZone(DateTimeZone zone) {
355         if (iZone == zone) {
356             return this;
357         }
358         return new DateTimeFormatter(iPrinter, iParser, iLocale,
359                 false, iChrono, zone, iPivotYear, iDefaultYear);
360     }
361
362     /**
363      * Gets the zone to use as an override.
364      * 
365      * @return the zone to use as an override
366      */

367     public DateTimeZone getZone() {
368         return iZone;
369     }
370
371     //-----------------------------------------------------------------------
372     /**
373      * Returns a new formatter that will use the specified pivot year for two
374      * digit year parsing in preference to that stored in the parser.
375      * <p>
376      * This setting is useful for changing the pivot year of formats built
377      * using a pattern - {@link DateTimeFormat#forPattern(String)}.
378      * <p>
379      * When parsing, this pivot year is used. Null means no-override.
380      * There is no effect when printing.
381      * <p>
382      * The pivot year enables a two digit year to be converted to a four
383      * digit year. The pivot represents the year in the middle of the
384      * supported range of years. Thus the full range of years that will
385      * be built is <code>(pivot - 50) .. (pivot + 49)</code>.
386      *
387      * <pre>
388      * pivot   supported range   00 is   20 is   40 is   60 is   80 is
389      * ---------------------------------------------------------------
390      * 1950      1900..1999      1900    1920    1940    1960    1980
391      * 1975      1925..2024      2000    2020    1940    1960    1980
392      * 2000      1950..2049      2000    2020    2040    1960    1980
393      * 2025      1975..2074      2000    2020    2040    2060    1980
394      * 2050      2000..2099      2000    2020    2040    2060    2080
395      * </pre>
396      *
397      * @param pivotYear  the pivot year to use as an override when parsing
398      * @return the new formatter
399      * @since 1.1
400      */

401     public DateTimeFormatter withPivotYear(Integer pivotYear) {
402         if (iPivotYear == pivotYear || (iPivotYear != null && iPivotYear.equals(pivotYear))) {
403             return this;
404         }
405         return new DateTimeFormatter(iPrinter, iParser, iLocale,
406                 iOffsetParsed, iChrono, iZone, pivotYear, iDefaultYear);
407     }
408
409     /**
410      * Returns a new formatter that will use the specified pivot year for two
411      * digit year parsing in preference to that stored in the parser.
412      * <p>
413      * This setting is useful for changing the pivot year of formats built
414      * using a pattern - {@link DateTimeFormat#forPattern(String)}.
415      * <p>
416      * When parsing, this pivot year is used.
417      * There is no effect when printing.
418      * <p>
419      * The pivot year enables a two digit year to be converted to a four
420      * digit year. The pivot represents the year in the middle of the
421      * supported range of years. Thus the full range of years that will
422      * be built is <code>(pivot - 50) .. (pivot + 49)</code>.
423      *
424      * <pre>
425      * pivot   supported range   00 is   20 is   40 is   60 is   80 is
426      * ---------------------------------------------------------------
427      * 1950      1900..1999      1900    1920    1940    1960    1980
428      * 1975      1925..2024      2000    2020    1940    1960    1980
429      * 2000      1950..2049      2000    2020    2040    1960    1980
430      * 2025      1975..2074      2000    2020    2040    2060    1980
431      * 2050      2000..2099      2000    2020    2040    2060    2080
432      * </pre>
433      *
434      * @param pivotYear  the pivot year to use as an override when parsing
435      * @return the new formatter
436      * @since 1.1
437      */

438     public DateTimeFormatter withPivotYear(int pivotYear) {
439         return withPivotYear(Integer.valueOf(pivotYear));
440     }
441
442     /**
443      * Gets the pivot year to use as an override.
444      *
445      * @return the pivot year to use as an override
446      * @since 1.1
447      */

448     public Integer getPivotYear() {
449       return iPivotYear;
450     }
451
452     //-----------------------------------------------------------------------
453     /**
454      * Returns a new formatter that will use the specified default year.
455      * <p>
456      * The default year is used when parsing in the case where there is a
457      * month or a day but not a year. Specifically, it is used if there is
458      * a field parsed with a duration between the length of a month and the
459      * length of a day inclusive.
460      * <p>
461      * This value is typically used to move the year from 1970 to a leap year
462      * to enable February 29th to be parsed.
463      * Unless customised, the year 2000 is used.
464      * <p>
465      * This setting has no effect when printing.
466      *
467      * @param defaultYear  the default year to use
468      * @return the new formatter, not null
469      * @since 2.0
470      */

471     public DateTimeFormatter withDefaultYear(int defaultYear) {
472         return new DateTimeFormatter(iPrinter, iParser, iLocale,
473                 iOffsetParsed, iChrono, iZone, iPivotYear, defaultYear);
474     }
475
476     /**
477      * Gets the default year for parsing months and days.
478      *
479      * @return the default year for parsing months and days
480      * @since 2.0
481      */

482     public int getDefaultYear() {
483       return iDefaultYear;
484     }
485
486     //-----------------------------------------------------------------------
487     /**
488      * Prints a ReadableInstant, using the chronology supplied by the instant.
489      *
490      * @param buf  the destination to format to, not null
491      * @param instant  instant to format, null means now
492      */

493     public void printTo(StringBuffer buf, ReadableInstant instant) {
494         try {
495             printTo((Appendable) buf, instant);
496         } catch (IOException ex) {
497             // StringBuffer does not throw IOException
498         }
499     }
500
501     /**
502      * Prints a ReadableInstant, using the chronology supplied by the instant.
503      *
504      * @param out  the destination to format to, not null
505      * @param instant  instant to format, null means now
506      */

507     public void printTo(Writer out, ReadableInstant instant) throws IOException {
508         printTo((Appendable) out, instant);
509     }
510
511     /**
512      * Prints a ReadableInstant, using the chronology supplied by the instant.
513      *
514      * @param appendable  the destination to format to, not null
515      * @param instant  instant to format, null means now
516      * @since 2.0
517      */

518     public void printTo(Appendable appendable, ReadableInstant instant) throws IOException {
519         long millis = DateTimeUtils.getInstantMillis(instant);
520         Chronology chrono = DateTimeUtils.getInstantChronology(instant);
521         printTo(appendable, millis, chrono);
522     }
523
524     //-----------------------------------------------------------------------
525     /**
526      * Prints an instant from milliseconds since 1970-01-01T00:00:00Z,
527      * using ISO chronology in the default DateTimeZone.
528      *
529      * @param buf  the destination to format to, not null
530      * @param instant  millis since 1970-01-01T00:00:00Z
531      */

532     public void printTo(StringBuffer buf, long instant) {
533         try {
534             printTo((Appendable) buf, instant);
535         } catch (IOException ex) {
536             // StringBuffer does not throw IOException
537         }
538     }
539
540     /**
541      * Prints an instant from milliseconds since 1970-01-01T00:00:00Z,
542      * using ISO chronology in the default DateTimeZone.
543      *
544      * @param out  the destination to format to, not null
545      * @param instant  millis since 1970-01-01T00:00:00Z
546      */

547     public void printTo(Writer out, long instant) throws IOException {
548         printTo((Appendable) out, instant);
549     }
550
551     /**
552      * Prints an instant from milliseconds since 1970-01-01T00:00:00Z,
553      * using ISO chronology in the default DateTimeZone.
554      *
555      * @param appendable  the destination to format to, not null
556      * @param instant  millis since 1970-01-01T00:00:00Z
557      * @since 2.0
558      */

559     public void printTo(Appendable appendable, long instant) throws IOException {
560         printTo(appendable, instant, null);
561     }
562
563     //-----------------------------------------------------------------------
564     /**
565      * Prints a ReadablePartial.
566      * <p>
567      * Neither the override chronology nor the override zone are used
568      * by this method.
569      *
570      * @param buf  the destination to format to, not null
571      * @param partial  partial to format
572      */

573     public void printTo(StringBuffer buf, ReadablePartial partial) {
574         try {
575             printTo((Appendable) buf, partial);
576         } catch (IOException ex) {
577             // StringBuffer does not throw IOException
578         }
579     }
580
581     /**
582      * Prints a ReadablePartial.
583      * <p>
584      * Neither the override chronology nor the override zone are used
585      * by this method.
586      *
587      * @param out  the destination to format to, not null
588      * @param partial  partial to format
589      */

590     public void printTo(Writer out, ReadablePartial partial) throws IOException {
591         printTo((Appendable) out, partial);
592     }
593
594     /**
595      * Prints a ReadablePartial.
596      * <p>
597      * Neither the override chronology nor the override zone are used
598      * by this method.
599      *
600      * @param appendable  the destination to format to, not null
601      * @param partial  partial to format
602      * @since 2.0
603      */

604     public void printTo(Appendable appendable, ReadablePartial partial) throws IOException {
605         InternalPrinter printer = requirePrinter();
606         if (partial == null) {
607             throw new IllegalArgumentException("The partial must not be null");
608         }
609         printer.printTo(appendable, partial, iLocale);
610     }
611
612     //-----------------------------------------------------------------------
613     /**
614      * Prints a ReadableInstant to a String.
615      * <p>
616      * This method will use the override zone and the override chronology if
617      * they are set. Otherwise it will use the chronology and zone of the instant.
618      *
619      * @param instant  instant to format, null means now
620      * @return the printed result
621      */

622     public String print(ReadableInstant instant) {
623         StringBuilder buf = new StringBuilder(requirePrinter().estimatePrintedLength());
624         try {
625             printTo((Appendable) buf, instant);
626         } catch (IOException ex) {
627             // StringBuilder does not throw IOException
628         }
629         return buf.toString();
630     }
631
632     /**
633      * Prints a millisecond instant to a String.
634      * <p>
635      * This method will use the override zone and the override chronology if
636      * they are set. Otherwise it will use the ISO chronology and default zone.
637      *
638      * @param instant  millis since 1970-01-01T00:00:00Z
639      * @return the printed result
640      */

641     public String print(long instant) {
642         StringBuilder buf = new StringBuilder(requirePrinter().estimatePrintedLength());
643         try {
644             printTo((Appendable) buf, instant);
645         } catch (IOException ex) {
646             // StringBuilder does not throw IOException
647         }
648         return buf.toString();
649     }
650
651     /**
652      * Prints a ReadablePartial to a new String.
653      * <p>
654      * Neither the override chronology nor the override zone are used
655      * by this method.
656      *
657      * @param partial  partial to format
658      * @return the printed result
659      */

660     public String print(ReadablePartial partial) {
661         StringBuilder buf = new StringBuilder(requirePrinter().estimatePrintedLength());
662         try {
663             printTo((Appendable) buf, partial);
664         } catch (IOException ex) {
665             // StringBuilder does not throw IOException
666         }
667         return buf.toString();
668     }
669
670     private void printTo(Appendable appendable, long instant, Chronology chrono) throws IOException {
671         InternalPrinter printer = requirePrinter();
672         chrono = selectChronology(chrono);
673         // Shift instant into local time (UTC) to avoid excessive offset
674         // calculations when printing multiple fields in a composite printer.
675         DateTimeZone zone = chrono.getZone();
676         int offset = zone.getOffset(instant);
677         long adjustedInstant = instant + offset;
678         if ((instant ^ adjustedInstant) < 0 && (instant ^ offset) >= 0) {
679             // Time zone offset overflow, so revert to UTC.
680             zone = DateTimeZone.UTC;
681             offset = 0;
682             adjustedInstant = instant;
683         }
684         printer.printTo(appendable, adjustedInstant, chrono.withUTC(), offset, zone, iLocale);
685     }
686
687     /**
688      * Checks whether printing is supported.
689      * 
690      * @throws UnsupportedOperationException if printing is not supported
691      */

692     private InternalPrinter requirePrinter() {
693         InternalPrinter printer = iPrinter;
694         if (printer == null) {
695             throw new UnsupportedOperationException("Printing not supported");
696         }
697         return printer;
698     }
699
700     //-----------------------------------------------------------------------
701     /**
702      * Parses a datetime from the given text, at the given position, saving the
703      * result into the fields of the given ReadWritableInstant. If the parse
704      * succeeds, the return value is the new text position. Note that the parse
705      * may succeed without fully reading the text and in this case those fields
706      * that were read will be set.
707      * <p>
708      * Only those fields present in the string will be changed in the specified
709      * instant. All other fields will remain unaltered. Thus if the string only
710      * contains a year and a month, then the day and time will be retained from
711      * the input instant. If this is not the behaviour you want, then reset the
712      * fields before calling this method, or use {@link #parseDateTime(String)}
713      * or {@link #parseMutableDateTime(String)}.
714      * <p>
715      * If it fails, the return value is negative, but the instant may still be
716      * modified. To determine the position where the parse failed, apply the
717      * one's complement operator (~) on the return value.
718      * <p>
719      * This parse method ignores the {@link #getDefaultYear() default year} and
720      * parses using the year from the supplied instant based on the chronology
721      * and time-zone of the supplied instant.
722      * <p>
723      * The parse will use the chronology of the instant.
724      *
725      * @param instant  an instant that will be modified, not null
726      * @param text  the text to parse
727      * @param position  position to start parsing from
728      * @return new position, negative value means parse failed -
729      *  apply complement operator (~) to get position of failure
730      * @throws UnsupportedOperationException if parsing is not supported
731      * @throws IllegalArgumentException if the instant is null
732      * @throws IllegalArgumentException if any field is out of range
733      */

734     public int parseInto(ReadWritableInstant instant, String text, int position) {
735         InternalParser parser = requireParser();
736         if (instant == null) {
737             throw new IllegalArgumentException("Instant must not be null");
738         }
739         
740         long instantMillis = instant.getMillis();
741         Chronology chrono = instant.getChronology();
742         int defaultYear = DateTimeUtils.getChronology(chrono).year().get(instantMillis);
743         long instantLocal = instantMillis + chrono.getZone().getOffset(instantMillis);
744         chrono = selectChronology(chrono);
745         
746         DateTimeParserBucket bucket = new DateTimeParserBucket(
747             instantLocal, chrono, iLocale, iPivotYear, defaultYear);
748         int newPos = parser.parseInto(bucket, text, position);
749         instant.setMillis(bucket.computeMillis(false, text));
750         if (iOffsetParsed && bucket.getOffsetInteger() != null) {
751             int parsedOffset = bucket.getOffsetInteger();
752             DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
753             chrono = chrono.withZone(parsedZone);
754         } else if (bucket.getZone() != null) {
755             chrono = chrono.withZone(bucket.getZone());
756         }
757         instant.setChronology(chrono);
758         if (iZone != null) {
759             instant.setZone(iZone);
760         }
761         return newPos;
762     }
763
764     /**
765      * Parses a datetime from the given text, returning the number of
766      * milliseconds since the epoch, 1970-01-01T00:00:00Z.
767      * <p>
768      * The parse will use the ISO chronology, and the default time zone.
769      * If the text contains a time zone string then that will be taken into account.
770      *
771      * @param text  the text to parse, not null
772      * @return parsed value expressed in milliseconds since the epoch
773      * @throws UnsupportedOperationException if parsing is not supported
774      * @throws IllegalArgumentException if the text to parse is invalid
775      */

776     public long parseMillis(String text) {
777         InternalParser parser = requireParser();
778         Chronology chrono = selectChronology(iChrono);
779         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear);
780         return bucket.doParseMillis(parser, text);
781     }
782
783     /**
784      * Parses only the local date from the given text, returning a new LocalDate.
785      * <p>
786      * This will parse the text fully according to the formatter, using the UTC zone.
787      * Once parsed, only the local date will be used.
788      * This means that any parsed time, time-zone or offset field is completely ignored.
789      * It also means that the zone and offset-parsed settings are ignored.
790      *
791      * @param text  the text to parse, not null
792      * @return the parsed date, never null
793      * @throws UnsupportedOperationException if parsing is not supported
794      * @throws IllegalArgumentException if the text to parse is invalid
795      * @since 2.0
796      */

797     public LocalDate parseLocalDate(String text) {
798         return parseLocalDateTime(text).toLocalDate();
799     }
800
801     /**
802      * Parses only the local time from the given text, returning a new LocalTime.
803      * <p>
804      * This will parse the text fully according to the formatter, using the UTC zone.
805      * Once parsed, only the local time will be used.
806      * This means that any parsed date, time-zone or offset field is completely ignored.
807      * It also means that the zone and offset-parsed settings are ignored.
808      *
809      * @param text  the text to parse, not null
810      * @return the parsed time, never null
811      * @throws UnsupportedOperationException if parsing is not supported
812      * @throws IllegalArgumentException if the text to parse is invalid
813      * @since 2.0
814      */

815     public LocalTime parseLocalTime(String text) {
816         return parseLocalDateTime(text).toLocalTime();
817     }
818
819     /**
820      * Parses only the local date-time from the given text, returning a new LocalDateTime.
821      * <p>
822      * This will parse the text fully according to the formatter, using the UTC zone.
823      * Once parsed, only the local date-time will be used.
824      * This means that any parsed time-zone or offset field is completely ignored.
825      * It also means that the zone and offset-parsed settings are ignored.
826      *
827      * @param text  the text to parse, not null
828      * @return the parsed date-time, never null
829      * @throws UnsupportedOperationException if parsing is not supported
830      * @throws IllegalArgumentException if the text to parse is invalid
831      * @since 2.0
832      */

833     public LocalDateTime parseLocalDateTime(String text) {
834         InternalParser parser = requireParser();
835         
836         Chronology chrono = selectChronology(null).withUTC();  // always use UTC, avoiding DST gaps
837         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear);
838         int newPos = parser.parseInto(bucket, text, 0);
839         if (newPos >= 0) {
840             if (newPos >= text.length()) {
841                 long millis = bucket.computeMillis(true, text);
842                 if (bucket.getOffsetInteger() != null) {  // treat withOffsetParsed() as being true
843                     int parsedOffset = bucket.getOffsetInteger();
844                     DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
845                     chrono = chrono.withZone(parsedZone);
846                 } else if (bucket.getZone() != null) {
847                     chrono = chrono.withZone(bucket.getZone());
848                 }
849                 return new LocalDateTime(millis, chrono);
850             }
851         } else {
852             newPos = ~newPos;
853         }
854         throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos));
855     }
856
857     /**
858      * Parses a date-time from the given text, returning a new DateTime.
859      * <p>
860      * The parse will use the zone and chronology specified on this formatter.
861      * <p>
862      * If the text contains a time zone string then that will be taken into
863      * account in adjusting the time of day as follows.
864      * If the {@link #withOffsetParsed()} has been called, then the resulting
865      * DateTime will have a fixed offset based on the parsed time zone.
866      * Otherwise the resulting DateTime will have the zone of this formatter,
867      * but the parsed zone may have caused the time to be adjusted.
868      *
869      * @param text  the text to parse, not null
870      * @return the parsed date-time, never null
871      * @throws UnsupportedOperationException if parsing is not supported
872      * @throws IllegalArgumentException if the text to parse is invalid
873      */

874     public DateTime parseDateTime(String text) {
875         InternalParser parser = requireParser();
876         
877         Chronology chrono = selectChronology(null);
878         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear);
879         int newPos = parser.parseInto(bucket, text, 0);
880         if (newPos >= 0) {
881             if (newPos >= text.length()) {
882                 long millis = bucket.computeMillis(true, text);
883                 if (iOffsetParsed && bucket.getOffsetInteger() != null) {
884                     int parsedOffset = bucket.getOffsetInteger();
885                     DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
886                     chrono = chrono.withZone(parsedZone);
887                 } else if (bucket.getZone() != null) {
888                     chrono = chrono.withZone(bucket.getZone());
889                 }
890                 DateTime dt = new DateTime(millis, chrono);
891                 if (iZone != null) {
892                     dt = dt.withZone(iZone);
893                 }
894                 return dt;
895             }
896         } else {
897             newPos = ~newPos;
898         }
899         throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos));
900     }
901
902     /**
903      * Parses a date-time from the given text, returning a new MutableDateTime.
904      * <p>
905      * The parse will use the zone and chronology specified on this formatter.
906      * <p>
907      * If the text contains a time zone string then that will be taken into
908      * account in adjusting the time of day as follows.
909      * If the {@link #withOffsetParsed()} has been called, then the resulting
910      * DateTime will have a fixed offset based on the parsed time zone.
911      * Otherwise the resulting DateTime will have the zone of this formatter,
912      * but the parsed zone may have caused the time to be adjusted.
913      *
914      * @param text  the text to parse, not null
915      * @return the parsed date-time, never null
916      * @throws UnsupportedOperationException if parsing is not supported
917      * @throws IllegalArgumentException if the text to parse is invalid
918      */

919     public MutableDateTime parseMutableDateTime(String text) {
920         InternalParser parser = requireParser();
921         
922         Chronology chrono = selectChronology(null);
923         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear);
924         int newPos = parser.parseInto(bucket, text, 0);
925         if (newPos >= 0) {
926             if (newPos >= text.length()) {
927                 long millis = bucket.computeMillis(true, text);
928                 if (iOffsetParsed && bucket.getOffsetInteger() != null) {
929                     int parsedOffset = bucket.getOffsetInteger();
930                     DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
931                     chrono = chrono.withZone(parsedZone);
932                 } else if (bucket.getZone() != null) {
933                     chrono = chrono.withZone(bucket.getZone());
934                 }
935                 MutableDateTime dt = new MutableDateTime(millis, chrono);
936                 if (iZone != null) {
937                     dt.setZone(iZone);
938                 }
939                 return dt;
940             }
941         } else {
942             newPos = ~newPos;
943         }
944         throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos));
945     }
946
947     /**
948      * Checks whether parsing is supported.
949      * 
950      * @throws UnsupportedOperationException if parsing is not supported
951      */

952     private InternalParser requireParser() {
953         InternalParser parser = iParser;
954         if (parser == null) {
955             throw new UnsupportedOperationException("Parsing not supported");
956         }
957         return parser;
958     }
959
960     //-----------------------------------------------------------------------
961     /**
962      * Determines the correct chronology to use.
963      *
964      * @param chrono  the proposed chronology
965      * @return the actual chronology
966      */

967     private Chronology selectChronology(Chronology chrono) {
968         chrono = DateTimeUtils.getChronology(chrono);
969         if (iChrono != null) {
970             chrono = iChrono;
971         }
972         if (iZone != null) {
973             chrono = chrono.withZone(iZone);
974         }
975         return chrono;
976     }
977
978 }
979