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     * <li>{@link #withPivotYear()} - returns a new formatter with the specified pivot year</li>
058     * <li>{@link #withDefaultYear()} - returns a new formatter with the specified default year</li>
059     * </ul>
060     * Each of these returns a new formatter (instances of this class are immutable).
061     * <p>
062     * The main methods of the class are the <code>printXxx</code> and
063     * <code>parseXxx</code> methods. These are used as follows:
064     * <pre>
065     * // print using the defaults (default locale, chronology/zone of the datetime)
066     * String dateStr = formatter.print(dt);
067     * // print using the French locale
068     * String dateStr = formatter.withLocale(Locale.FRENCH).print(dt);
069     * // print using the UTC zone
070     * String dateStr = formatter.withZone(DateTimeZone.UTC).print(dt);
071     * 
072     * // parse using the Paris zone
073     * DateTime date = formatter.withZone(DateTimeZone.forID("Europe/Paris")).parseDateTime(str);
074     * </pre>
075     * 
076     * @author Brian S O'Neill
077     * @author Stephen Colebourne
078     * @author Fredrik Borgh
079     * @since 1.0
080     */
081    public class DateTimeFormatter {
082    
083        /** The internal printer used to output the datetime. */
084        private final DateTimePrinter iPrinter;
085        /** The internal parser used to output the datetime. */
086        private final DateTimeParser iParser;
087        /** The locale to use for printing and parsing. */
088        private final Locale iLocale;
089        /** Whether the offset is parsed. */
090        private final boolean iOffsetParsed;
091        /** The chronology to use as an override. */
092        private final Chronology iChrono;
093        /** The zone to use as an override. */
094        private final DateTimeZone iZone;
095        /** The pivot year to use for two-digit year parsing. */
096        private final Integer iPivotYear;
097        /** The default year for parsing month/day without year. */
098        private final int iDefaultYear;
099    
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    }