View Javadoc

1   /*
2    *  Copyright 2001-2011 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()} - returns a new formatter with the specified pivot year</li>
58   * <li>{@link #withDefaultYear()} - 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   * 
76   * @author Brian S O'Neill
77   * @author Stephen Colebourne
78   * @author Fredrik Borgh
79   * @since 1.0
80   */
81  public class DateTimeFormatter {
82  
83      /** The internal printer used to output the datetime. */
84      private final DateTimePrinter iPrinter;
85      /** The internal parser used to output the datetime. */
86      private final DateTimeParser iParser;
87      /** The locale to use for printing and parsing. */
88      private final Locale iLocale;
89      /** Whether the offset is parsed. */
90      private final boolean iOffsetParsed;
91      /** The chronology to use as an override. */
92      private final Chronology iChrono;
93      /** The zone to use as an override. */
94      private final DateTimeZone iZone;
95      /** The pivot year to use for two-digit year parsing. */
96      private final Integer iPivotYear;
97      /** The default year for parsing month/day without year. */
98      private final int iDefaultYear;
99  
100     /**
101      * Creates a new formatter, however you will normally use the factory
102      * or the builder.
103      * 
104      * @param printer  the internal printer, null if cannot print
105      * @param parser  the internal parser, null if cannot parse
106      */
107     public DateTimeFormatter(
108             DateTimePrinter printer, DateTimeParser parser) {
109         super();
110         iPrinter = printer;
111         iParser = parser;
112         iLocale = null;
113         iOffsetParsed = false;
114         iChrono = null;
115         iZone = null;
116         iPivotYear = null;
117         iDefaultYear = 2000;
118     }
119 
120     /**
121      * Constructor.
122      */
123     private DateTimeFormatter(
124             DateTimePrinter printer, DateTimeParser parser,
125             Locale locale, boolean offsetParsed,
126             Chronology chrono, DateTimeZone zone,
127             Integer pivotYear, int defaultYear) {
128         super();
129         iPrinter = printer;
130         iParser = parser;
131         iLocale = locale;
132         iOffsetParsed = offsetParsed;
133         iChrono = chrono;
134         iZone = zone;
135         iPivotYear = pivotYear;
136         iDefaultYear = defaultYear;
137     }
138 
139     //-----------------------------------------------------------------------
140     /**
141      * Is this formatter capable of printing.
142      * 
143      * @return true if this is a printer
144      */
145     public boolean isPrinter() {
146         return (iPrinter != null);
147     }
148 
149     /**
150      * Gets the internal printer object that performs the real printing work.
151      * 
152      * @return the internal printer; is null if printing not supported
153      */
154     public DateTimePrinter getPrinter() {
155         return iPrinter;
156     }
157 
158     /**
159      * Is this formatter capable of parsing.
160      * 
161      * @return true if this is a parser
162      */
163     public boolean isParser() {
164         return (iParser != null);
165     }
166 
167     /**
168      * Gets the internal parser object that performs the real parsing work.
169      * 
170      * @return the internal parser; is null if parsing not supported
171      */
172     public DateTimeParser getParser() {
173         return iParser;
174     }
175 
176     //-----------------------------------------------------------------------
177     /**
178      * Returns a new formatter with a different locale that will be used
179      * for printing and parsing.
180      * <p>
181      * A DateTimeFormatter is immutable, so a new instance is returned,
182      * and the original is unaltered and still usable.
183      * 
184      * @param locale the locale to use; if null, formatter uses default locale
185      * at invocation time
186      * @return the new formatter
187      */
188     public DateTimeFormatter withLocale(Locale locale) {
189         if (locale == getLocale() || (locale != null && locale.equals(getLocale()))) {
190             return this;
191         }
192         return new DateTimeFormatter(iPrinter, iParser, locale,
193                 iOffsetParsed, iChrono, iZone, iPivotYear, iDefaultYear);
194     }
195 
196     /**
197      * Gets the locale that will be used for printing and parsing.
198      * 
199      * @return the locale to use; if null, formatter uses default locale at
200      * invocation time
201      */
202     public Locale getLocale() {
203         return iLocale;
204     }
205 
206     //-----------------------------------------------------------------------
207     /**
208      * Returns a new formatter that will create a datetime with a time zone
209      * equal to that of the offset of the parsed string.
210      * <p>
211      * After calling this method, a string '2004-06-09T10:20:30-08:00' will
212      * create a datetime with a zone of -08:00 (a fixed zone, with no daylight
213      * savings rules). If the parsed string represents a local time (no zone
214      * offset) the parsed datetime will be in the default zone.
215      * <p>
216      * Calling this method sets the override zone to null.
217      * Calling the override zone method sets this flag off.
218      * 
219      * @return the new formatter
220      */
221     public DateTimeFormatter withOffsetParsed() {
222         if (iOffsetParsed == true) {
223             return this;
224         }
225         return new DateTimeFormatter(iPrinter, iParser, iLocale,
226                 true, iChrono, null, iPivotYear, iDefaultYear);
227     }
228 
229     /**
230      * Checks whether the offset from the string is used as the zone of
231      * the parsed datetime.
232      * 
233      * @return true if the offset from the string is used as the zone
234      */
235     public boolean isOffsetParsed() {
236         return iOffsetParsed;
237     }
238 
239     //-----------------------------------------------------------------------
240     /**
241      * Returns a new formatter that will use the specified chronology in
242      * preference to that of the printed object, or ISO on a parse.
243      * <p>
244      * When printing, this chronolgy will be used in preference to the chronology
245      * from the datetime that would otherwise be used.
246      * <p>
247      * When parsing, this chronology will be set on the parsed datetime.
248      * <p>
249      * A null chronology means no-override.
250      * If both an override chronology and an override zone are set, the
251      * override zone will take precedence over the zone in the chronology.
252      * 
253      * @param chrono  the chronology to use as an override
254      * @return the new formatter
255      */
256     public DateTimeFormatter withChronology(Chronology chrono) {
257         if (iChrono == chrono) {
258             return this;
259         }
260         return new DateTimeFormatter(iPrinter, iParser, iLocale,
261                 iOffsetParsed, chrono, iZone, iPivotYear, iDefaultYear);
262     }
263 
264     /**
265      * Gets the chronology to use as an override.
266      * 
267      * @return the chronology to use as an override
268      */
269     public Chronology getChronology() {
270         return iChrono;
271     }
272 
273     /**
274      * Gets the chronology to use as an override.
275      * 
276      * @return the chronology to use as an override
277      * @deprecated Use the method with the correct spelling
278      */
279     @Deprecated
280     public Chronology getChronolgy() {
281         return iChrono;
282     }
283 
284     //-----------------------------------------------------------------------
285     /**
286      * Returns a new formatter that will use the UTC zone in preference
287      * to the zone of the printed object, or default zone on a parse.
288      * <p>
289      * When printing, UTC will be used in preference to the zone
290      * from the datetime that would otherwise be used.
291      * <p>
292      * When parsing, UTC will be set on the parsed datetime.
293      * <p>
294      * If both an override chronology and an override zone are set, the
295      * override zone will take precedence over the zone in the chronology.
296      * 
297      * @return the new formatter, never null
298      * @since 2.0
299      */
300     public DateTimeFormatter withZoneUTC() {
301         return withZone(DateTimeZone.UTC);
302     }
303 
304     /**
305      * Returns a new formatter that will use the specified zone in preference
306      * to the zone of the printed object, or default zone on a parse.
307      * <p>
308      * When printing, this zone will be used in preference to the zone
309      * from the datetime that would otherwise be used.
310      * <p>
311      * When parsing, this zone will be set on the parsed datetime.
312      * <p>
313      * A null zone means of no-override.
314      * If both an override chronology and an override zone are set, the
315      * override zone will take precedence over the zone in the chronology.
316      * 
317      * @param zone  the zone to use as an override
318      * @return the new formatter
319      */
320     public DateTimeFormatter withZone(DateTimeZone zone) {
321         if (iZone == zone) {
322             return this;
323         }
324         return new DateTimeFormatter(iPrinter, iParser, iLocale,
325                 false, iChrono, zone, iPivotYear, iDefaultYear);
326     }
327 
328     /**
329      * Gets the zone to use as an override.
330      * 
331      * @return the zone to use as an override
332      */
333     public DateTimeZone getZone() {
334         return iZone;
335     }
336 
337     //-----------------------------------------------------------------------
338     /**
339      * Returns a new formatter that will use the specified pivot year for two
340      * digit year parsing in preference to that stored in the parser.
341      * <p>
342      * This setting is useful for changing the pivot year of formats built
343      * using a pattern - {@link DateTimeFormat#forPattern(String)}.
344      * <p>
345      * When parsing, this pivot year is used. Null means no-override.
346      * There is no effect when printing.
347      * <p>
348      * The pivot year enables a two digit year to be converted to a four
349      * digit year. The pivot represents the year in the middle of the
350      * supported range of years. Thus the full range of years that will
351      * be built is <code>(pivot - 50) .. (pivot + 49)</code>.
352      *
353      * <pre>
354      * pivot   supported range   00 is   20 is   40 is   60 is   80 is
355      * ---------------------------------------------------------------
356      * 1950      1900..1999      1900    1920    1940    1960    1980
357      * 1975      1925..2024      2000    2020    1940    1960    1980
358      * 2000      1950..2049      2000    2020    2040    1960    1980
359      * 2025      1975..2074      2000    2020    2040    2060    1980
360      * 2050      2000..2099      2000    2020    2040    2060    2080
361      * </pre>
362      *
363      * @param pivotYear  the pivot year to use as an override when parsing
364      * @return the new formatter
365      * @since 1.1
366      */
367     public DateTimeFormatter withPivotYear(Integer pivotYear) {
368         if (iPivotYear == pivotYear || (iPivotYear != null && iPivotYear.equals(pivotYear))) {
369             return this;
370         }
371         return new DateTimeFormatter(iPrinter, iParser, iLocale,
372                 iOffsetParsed, iChrono, iZone, pivotYear, iDefaultYear);
373     }
374 
375     /**
376      * Returns a new formatter that will use the specified pivot year for two
377      * digit year parsing in preference to that stored in the parser.
378      * <p>
379      * This setting is useful for changing the pivot year of formats built
380      * using a pattern - {@link DateTimeFormat#forPattern(String)}.
381      * <p>
382      * When parsing, this pivot year is used.
383      * There is no effect when printing.
384      * <p>
385      * The pivot year enables a two digit year to be converted to a four
386      * digit year. The pivot represents the year in the middle of the
387      * supported range of years. Thus the full range of years that will
388      * be built is <code>(pivot - 50) .. (pivot + 49)</code>.
389      *
390      * <pre>
391      * pivot   supported range   00 is   20 is   40 is   60 is   80 is
392      * ---------------------------------------------------------------
393      * 1950      1900..1999      1900    1920    1940    1960    1980
394      * 1975      1925..2024      2000    2020    1940    1960    1980
395      * 2000      1950..2049      2000    2020    2040    1960    1980
396      * 2025      1975..2074      2000    2020    2040    2060    1980
397      * 2050      2000..2099      2000    2020    2040    2060    2080
398      * </pre>
399      *
400      * @param pivotYear  the pivot year to use as an override when parsing
401      * @return the new formatter
402      * @since 1.1
403      */
404     public DateTimeFormatter withPivotYear(int pivotYear) {
405         return withPivotYear(Integer.valueOf(pivotYear));
406     }
407 
408     /**
409      * Gets the pivot year to use as an override.
410      *
411      * @return the pivot year to use as an override
412      * @since 1.1
413      */
414     public Integer getPivotYear() {
415       return iPivotYear;
416     }
417 
418     //-----------------------------------------------------------------------
419     /**
420      * Returns a new formatter that will use the specified default year.
421      * <p>
422      * The default year is used when parsing in the case where there is a
423      * month or a day but not a year. Specifically, it is used if there is
424      * a field parsed with a duration between the length of a month and the
425      * length of a day inclusive.
426      * <p>
427      * This value is typically used to move the year from 1970 to a leap year
428      * to enable February 29th to be parsed.
429      * Unless customised, the year 2000 is used.
430      * <p>
431      * This setting has no effect when printing.
432      *
433      * @param defaultYear  the default year to use
434      * @return the new formatter, not null
435      * @since 2.0
436      */
437     public DateTimeFormatter withDefaultYear(int defaultYear) {
438         return new DateTimeFormatter(iPrinter, iParser, iLocale,
439                 iOffsetParsed, iChrono, iZone, iPivotYear, defaultYear);
440     }
441 
442     /**
443      * Gets the default year for parsing months and days.
444      *
445      * @return the default year for parsing months and days
446      * @since 2.0
447      */
448     public int getDefaultYear() {
449       return iDefaultYear;
450     }
451 
452     //-----------------------------------------------------------------------
453     /**
454      * Prints a ReadableInstant, using the chronology supplied by the instant.
455      *
456      * @param buf  the destination to format to, not null
457      * @param instant  instant to format, null means now
458      */
459     public void printTo(StringBuffer buf, ReadableInstant instant) {
460         long millis = DateTimeUtils.getInstantMillis(instant);
461         Chronology chrono = DateTimeUtils.getInstantChronology(instant);
462         printTo(buf, millis, chrono);
463     }
464 
465     /**
466      * Prints a ReadableInstant, using the chronology supplied by the instant.
467      *
468      * @param out  the destination to format to, not null
469      * @param instant  instant to format, null means now
470      */
471     public void printTo(Writer out, ReadableInstant instant) throws IOException {
472         long millis = DateTimeUtils.getInstantMillis(instant);
473         Chronology chrono = DateTimeUtils.getInstantChronology(instant);
474         printTo(out, millis, chrono);
475     }
476 
477     /**
478      * Prints a ReadableInstant, using the chronology supplied by the instant.
479      *
480      * @param appendable  the destination to format to, not null
481      * @param instant  instant to format, null means now
482      * @since 2.0
483      */
484     public void printTo(Appendable appendable, ReadableInstant instant) throws IOException {
485         appendable.append(print(instant));
486     }
487 
488     //-----------------------------------------------------------------------
489     /**
490      * Prints an instant from milliseconds since 1970-01-01T00:00:00Z,
491      * using ISO chronology in the default DateTimeZone.
492      *
493      * @param buf  the destination to format to, not null
494      * @param instant  millis since 1970-01-01T00:00:00Z
495      */
496     public void printTo(StringBuffer buf, long instant) {
497         printTo(buf, instant, null);
498     }
499 
500     /**
501      * Prints an instant from milliseconds since 1970-01-01T00:00:00Z,
502      * using ISO chronology in the default DateTimeZone.
503      *
504      * @param out  the destination to format to, not null
505      * @param instant  millis since 1970-01-01T00:00:00Z
506      */
507     public void printTo(Writer out, long instant) throws IOException {
508         printTo(out, instant, null);
509     }
510 
511     /**
512      * Prints an instant from milliseconds since 1970-01-01T00:00:00Z,
513      * using ISO chronology in the default DateTimeZone.
514      *
515      * @param appendable  the destination to format to, not null
516      * @param instant  millis since 1970-01-01T00:00:00Z
517      * @since 2.0
518      */
519     public void printTo(Appendable appendable, long instant) throws IOException {
520         appendable.append(print(instant));
521     }
522 
523     //-----------------------------------------------------------------------
524     /**
525      * Prints a ReadablePartial.
526      * <p>
527      * Neither the override chronology nor the override zone are used
528      * by this method.
529      *
530      * @param buf  the destination to format to, not null
531      * @param partial  partial to format
532      */
533     public void printTo(StringBuffer buf, ReadablePartial partial) {
534         DateTimePrinter printer = requirePrinter();
535         if (partial == null) {
536             throw new IllegalArgumentException("The partial must not be null");
537         }
538         printer.printTo(buf, partial, iLocale);
539     }
540 
541     /**
542      * Prints a ReadablePartial.
543      * <p>
544      * Neither the override chronology nor the override zone are used
545      * by this method.
546      *
547      * @param out  the destination to format to, not null
548      * @param partial  partial to format
549      */
550     public void printTo(Writer out, ReadablePartial partial) throws IOException {
551         DateTimePrinter printer = requirePrinter();
552         if (partial == null) {
553             throw new IllegalArgumentException("The partial must not be null");
554         }
555         printer.printTo(out, partial, iLocale);
556     }
557 
558     /**
559      * Prints a ReadablePartial.
560      * <p>
561      * Neither the override chronology nor the override zone are used
562      * by this method.
563      *
564      * @param appendable  the destination to format to, not null
565      * @param partial  partial to format
566      * @since 2.0
567      */
568     public void printTo(Appendable appendable, ReadablePartial partial) throws IOException {
569         appendable.append(print(partial));
570     }
571 
572     //-----------------------------------------------------------------------
573     /**
574      * Prints a ReadableInstant to a String.
575      * <p>
576      * This method will use the override zone and the override chronololgy if
577      * they are set. Otherwise it will use the chronology and zone of the instant.
578      *
579      * @param instant  instant to format, null means now
580      * @return the printed result
581      */
582     public String print(ReadableInstant instant) {
583         StringBuffer buf = new StringBuffer(requirePrinter().estimatePrintedLength());
584         printTo(buf, instant);
585         return buf.toString();
586     }
587 
588     /**
589      * Prints a millisecond instant to a String.
590      * <p>
591      * This method will use the override zone and the override chronololgy if
592      * they are set. Otherwise it will use the ISO chronology and default zone.
593      *
594      * @param instant  millis since 1970-01-01T00:00:00Z
595      * @return the printed result
596      */
597     public String print(long instant) {
598         StringBuffer buf = new StringBuffer(requirePrinter().estimatePrintedLength());
599         printTo(buf, instant);
600         return buf.toString();
601     }
602 
603     /**
604      * Prints a ReadablePartial to a new String.
605      * <p>
606      * Neither the override chronology nor the override zone are used
607      * by this method.
608      *
609      * @param partial  partial to format
610      * @return the printed result
611      */
612     public String print(ReadablePartial partial) {
613         StringBuffer buf = new StringBuffer(requirePrinter().estimatePrintedLength());
614         printTo(buf, partial);
615         return buf.toString();
616     }
617 
618     private void printTo(StringBuffer buf, long instant, Chronology chrono) {
619         DateTimePrinter printer = requirePrinter();
620         chrono = selectChronology(chrono);
621         // Shift instant into local time (UTC) to avoid excessive offset
622         // calculations when printing multiple fields in a composite printer.
623         DateTimeZone zone = chrono.getZone();
624         int offset = zone.getOffset(instant);
625         long adjustedInstant = instant + offset;
626         if ((instant ^ adjustedInstant) < 0 && (instant ^ offset) >= 0) {
627             // Time zone offset overflow, so revert to UTC.
628             zone = DateTimeZone.UTC;
629             offset = 0;
630             adjustedInstant = instant;
631         }
632         printer.printTo(buf, adjustedInstant, chrono.withUTC(), offset, zone, iLocale);
633     }
634 
635     private void printTo(Writer buf, long instant, Chronology chrono) throws IOException {
636         DateTimePrinter printer = requirePrinter();
637         chrono = selectChronology(chrono);
638         // Shift instant into local time (UTC) to avoid excessive offset
639         // calculations when printing multiple fields in a composite printer.
640         DateTimeZone zone = chrono.getZone();
641         int offset = zone.getOffset(instant);
642         long adjustedInstant = instant + offset;
643         if ((instant ^ adjustedInstant) < 0 && (instant ^ offset) >= 0) {
644             // Time zone offset overflow, so revert to UTC.
645             zone = DateTimeZone.UTC;
646             offset = 0;
647             adjustedInstant = instant;
648         }
649         printer.printTo(buf, adjustedInstant, chrono.withUTC(), offset, zone, iLocale);
650     }
651 
652     /**
653      * Checks whether printing is supported.
654      * 
655      * @throws UnsupportedOperationException if printing is not supported
656      */
657     private DateTimePrinter requirePrinter() {
658         DateTimePrinter printer = iPrinter;
659         if (printer == null) {
660             throw new UnsupportedOperationException("Printing not supported");
661         }
662         return printer;
663     }
664 
665     //-----------------------------------------------------------------------
666     /**
667      * Parses a datetime from the given text, at the given position, saving the
668      * result into the fields of the given ReadWritableInstant. If the parse
669      * succeeds, the return value is the new text position. Note that the parse
670      * may succeed without fully reading the text and in this case those fields
671      * that were read will be set.
672      * <p>
673      * Only those fields present in the string will be changed in the specified
674      * instant. All other fields will remain unaltered. Thus if the string only
675      * contains a year and a month, then the day and time will be retained from
676      * the input instant. If this is not the behaviour you want, then reset the
677      * fields before calling this method, or use {@link #parseDateTime(String)}
678      * or {@link #parseMutableDateTime(String)}.
679      * <p>
680      * If it fails, the return value is negative, but the instant may still be
681      * modified. To determine the position where the parse failed, apply the
682      * one's complement operator (~) on the return value.
683      * <p>
684      * This parse method ignores the {@link #getDefaultYear() default year} and
685      * parses using the year from the supplied instant as the default.
686      * <p>
687      * The parse will use the chronology of the instant.
688      *
689      * @param instant  an instant that will be modified, not null
690      * @param text  the text to parse
691      * @param position  position to start parsing from
692      * @return new position, negative value means parse failed -
693      *  apply complement operator (~) to get position of failure
694      * @throws UnsupportedOperationException if parsing is not supported
695      * @throws IllegalArgumentException if the instant is null
696      * @throws IllegalArgumentException if any field is out of range
697      */
698     public int parseInto(ReadWritableInstant instant, String text, int position) {
699         DateTimeParser parser = requireParser();
700         if (instant == null) {
701             throw new IllegalArgumentException("Instant must not be null");
702         }
703         
704         long instantMillis = instant.getMillis();
705         Chronology chrono = instant.getChronology();
706         long instantLocal = instantMillis + chrono.getZone().getOffset(instantMillis);
707         chrono = selectChronology(chrono);
708         
709         DateTimeParserBucket bucket = new DateTimeParserBucket(
710             instantLocal, chrono, iLocale, iPivotYear, chrono.year().get(instantLocal));
711         int newPos = parser.parseInto(bucket, text, position);
712         instant.setMillis(bucket.computeMillis(false, text));
713         if (iOffsetParsed && bucket.getOffsetInteger() != null) {
714             int parsedOffset = bucket.getOffsetInteger();
715             DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
716             chrono = chrono.withZone(parsedZone);
717         } else if (bucket.getZone() != null) {
718             chrono = chrono.withZone(bucket.getZone());
719         }
720         instant.setChronology(chrono);
721         if (iZone != null) {
722             instant.setZone(iZone);
723         }
724         return newPos;
725     }
726 
727     /**
728      * Parses a datetime from the given text, returning the number of
729      * milliseconds since the epoch, 1970-01-01T00:00:00Z.
730      * <p>
731      * The parse will use the ISO chronology, and the default time zone.
732      * If the text contains a time zone string then that will be taken into account.
733      *
734      * @param text  text to parse
735      * @return parsed value expressed in milliseconds since the epoch
736      * @throws UnsupportedOperationException if parsing is not supported
737      * @throws IllegalArgumentException if the text to parse is invalid
738      */
739     public long parseMillis(String text) {
740         DateTimeParser parser = requireParser();
741         
742         Chronology chrono = selectChronology(iChrono);
743         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear);
744         int newPos = parser.parseInto(bucket, text, 0);
745         if (newPos >= 0) {
746             if (newPos >= text.length()) {
747                 return bucket.computeMillis(true, text);
748             }
749         } else {
750             newPos = ~newPos;
751         }
752         throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos));
753     }
754 
755     /**
756      * Parses only the local date from the given text, returning a new LocalDate.
757      * <p>
758      * This will parse the text fully according to the formatter, using the UTC zone.
759      * Once parsed, only the local date will be used.
760      * This means that any parsed time, time-zone or offset field is completely ignored.
761      * It also means that the zone and offset-parsed settings are ignored.
762      *
763      * @param text  the text to parse, not null
764      * @return the parsed date, never null
765      * @throws UnsupportedOperationException if parsing is not supported
766      * @throws IllegalArgumentException if the text to parse is invalid
767      * @since 2.0
768      */
769     public LocalDate parseLocalDate(String text) {
770         return parseLocalDateTime(text).toLocalDate();
771     }
772 
773     /**
774      * Parses only the local time from the given text, returning a new LocalDate.
775      * <p>
776      * This will parse the text fully according to the formatter, using the UTC zone.
777      * Once parsed, only the local time will be used.
778      * This means that any parsed date, time-zone or offset field is completely ignored.
779      * It also means that the zone and offset-parsed settings are ignored.
780      *
781      * @param text  the text to parse, not null
782      * @return the parsed time, never null
783      * @throws UnsupportedOperationException if parsing is not supported
784      * @throws IllegalArgumentException if the text to parse is invalid
785      * @since 2.0
786      */
787     public LocalTime parseLocalTime(String text) {
788         return parseLocalDateTime(text).toLocalTime();
789     }
790 
791     /**
792      * Parses only the local date-time from the given text, returning a new LocalDate.
793      * <p>
794      * This will parse the text fully according to the formatter, using the UTC zone.
795      * Once parsed, only the local date-time will be used.
796      * This means that any parsed time-zone or offset field is completely ignored.
797      * It also means that the zone and offset-parsed settings are ignored.
798      *
799      * @param text  the text to parse, not null
800      * @return the parsed date-time, never null
801      * @throws UnsupportedOperationException if parsing is not supported
802      * @throws IllegalArgumentException if the text to parse is invalid
803      * @since 2.0
804      */
805     public LocalDateTime parseLocalDateTime(String text) {
806         DateTimeParser parser = requireParser();
807         
808         Chronology chrono = selectChronology(null).withUTC();  // always use UTC, avoiding DST gaps
809         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear);
810         int newPos = parser.parseInto(bucket, text, 0);
811         if (newPos >= 0) {
812             if (newPos >= text.length()) {
813                 long millis = bucket.computeMillis(true, text);
814                 if (bucket.getOffsetInteger() != null) {  // treat withOffsetParsed() as being true
815                     int parsedOffset = bucket.getOffsetInteger();
816                     DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
817                     chrono = chrono.withZone(parsedZone);
818                 } else if (bucket.getZone() != null) {
819                     chrono = chrono.withZone(bucket.getZone());
820                 }
821                 return new LocalDateTime(millis, chrono);
822             }
823         } else {
824             newPos = ~newPos;
825         }
826         throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos));
827     }
828 
829     /**
830      * Parses a date-time from the given text, returning a new DateTime.
831      * <p>
832      * The parse will use the zone and chronology specified on this formatter.
833      * <p>
834      * If the text contains a time zone string then that will be taken into
835      * account in adjusting the time of day as follows.
836      * If the {@link #withOffsetParsed()} has been called, then the resulting
837      * DateTime will have a fixed offset based on the parsed time zone.
838      * Otherwise the resulting DateTime will have the zone of this formatter,
839      * but the parsed zone may have caused the time to be adjusted.
840      *
841      * @param text  the text to parse, not null
842      * @return the parsed date-time, never null
843      * @throws UnsupportedOperationException if parsing is not supported
844      * @throws IllegalArgumentException if the text to parse is invalid
845      */
846     public DateTime parseDateTime(String text) {
847         DateTimeParser parser = requireParser();
848         
849         Chronology chrono = selectChronology(null);
850         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear);
851         int newPos = parser.parseInto(bucket, text, 0);
852         if (newPos >= 0) {
853             if (newPos >= text.length()) {
854                 long millis = bucket.computeMillis(true, text);
855                 if (iOffsetParsed && bucket.getOffsetInteger() != null) {
856                     int parsedOffset = bucket.getOffsetInteger();
857                     DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
858                     chrono = chrono.withZone(parsedZone);
859                 } else if (bucket.getZone() != null) {
860                     chrono = chrono.withZone(bucket.getZone());
861                 }
862                 DateTime dt = new DateTime(millis, chrono);
863                 if (iZone != null) {
864                     dt = dt.withZone(iZone);
865                 }
866                 return dt;
867             }
868         } else {
869             newPos = ~newPos;
870         }
871         throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos));
872     }
873 
874     /**
875      * Parses a date-time from the given text, returning a new MutableDateTime.
876      * <p>
877      * The parse will use the zone and chronology specified on this formatter.
878      * <p>
879      * If the text contains a time zone string then that will be taken into
880      * account in adjusting the time of day as follows.
881      * If the {@link #withOffsetParsed()} has been called, then the resulting
882      * DateTime will have a fixed offset based on the parsed time zone.
883      * Otherwise the resulting DateTime will have the zone of this formatter,
884      * but the parsed zone may have caused the time to be adjusted.
885      *
886      * @param text  the text to parse, not null
887      * @return the parsed date-time, never null
888      * @throws UnsupportedOperationException if parsing is not supported
889      * @throws IllegalArgumentException if the text to parse is invalid
890      */
891     public MutableDateTime parseMutableDateTime(String text) {
892         DateTimeParser parser = requireParser();
893         
894         Chronology chrono = selectChronology(null);
895         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear, iDefaultYear);
896         int newPos = parser.parseInto(bucket, text, 0);
897         if (newPos >= 0) {
898             if (newPos >= text.length()) {
899                 long millis = bucket.computeMillis(true, text);
900                 if (iOffsetParsed && bucket.getOffsetInteger() != null) {
901                     int parsedOffset = bucket.getOffsetInteger();
902                     DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
903                     chrono = chrono.withZone(parsedZone);
904                 } else if (bucket.getZone() != null) {
905                     chrono = chrono.withZone(bucket.getZone());
906                 }
907                 MutableDateTime dt = new MutableDateTime(millis, chrono);
908                 if (iZone != null) {
909                     dt.setZone(iZone);
910                 }
911                 return dt;
912             }
913         } else {
914             newPos = ~newPos;
915         }
916         throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos));
917     }
918 
919     /**
920      * Checks whether parsing is supported.
921      * 
922      * @throws UnsupportedOperationException if parsing is not supported
923      */
924     private DateTimeParser requireParser() {
925         DateTimeParser parser = iParser;
926         if (parser == null) {
927             throw new UnsupportedOperationException("Parsing not supported");
928         }
929         return parser;
930     }
931 
932     //-----------------------------------------------------------------------
933     /**
934      * Determines the correct chronology to use.
935      *
936      * @param chrono  the proposed chronology
937      * @return the actual chronology
938      */
939     private Chronology selectChronology(Chronology chrono) {
940         chrono = DateTimeUtils.getChronology(chrono);
941         if (iChrono != null) {
942             chrono = iChrono;
943         }
944         if (iZone != null) {
945             chrono = chrono.withZone(iZone);
946         }
947         return chrono;
948     }
949 
950 }