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