KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > joda > time > format > DateTimeFormatter


1 /*
2  * Copyright 2001-2005 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 JavaDoc;
19 import java.io.Writer JavaDoc;
20 import java.util.Locale JavaDoc;
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.MutableDateTime;
27 import org.joda.time.ReadWritableInstant;
28 import org.joda.time.ReadableInstant;
29 import org.joda.time.ReadablePartial;
30
31 /**
32  * Controls the printing and parsing of a datetime to and from a string.
33  * <p>
34  * This class is the main API for printing and parsing used by most applications.
35  * Instances of this class are created via one of three factory classes:
36  * <ul>
37  * <li>{@link DateTimeFormat} - formats by pattern and style</li>
38  * <li>{@link ISODateTimeFormat} - ISO8601 formats</li>
39  * <li>{@link DateTimeFormatterBuilder} - complex formats created via method calls</li>
40  * </ul>
41  * <p>
42  * An instance of this class holds a reference internally to one printer and
43  * one parser. It is possible that one of these may be null, in which case the
44  * formatter cannot print/parse. This can be checked via the {@link #isPrinter()}
45  * and {@link #isParser()} methods.
46  * <p>
47  * The underlying printer/parser can be altered to behave exactly as required
48  * by using one of the decorator modifiers:
49  * <ul>
50  * <li>{@link #withLocale(Locale)} - returns a new formatter that uses the specified locale</li>
51  * <li>{@link #withZone(DateTimeZone)} - returns a new formatter that uses the specified time zone</li>
52  * <li>{@link #withChronology(Chronology)} - returns a new formatter that uses the specified chronology</li>
53  * <li>{@link #withOffsetParsed()} - returns a new formatter that returns the parsed time zone offset</li>
54  * </ul>
55  * Each of these returns a new formatter (instances of this class are immutable).
56  * <p>
57  * The main methods of the class are the <code>printXxx</code> and
58  * <code>parseXxx</code> methods. These are used as follows:
59  * <pre>
60  * // print using the defaults (default locale, chronology/zone of the datetime)
61  * String dateStr = formatter.print(dt);
62  * // print using the French locale
63  * String dateStr = formatter.withLocale(Locale.FRENCH).print(dt);
64  * // print using the UTC zone
65  * String dateStr = formatter.withZone(DateTimeZone.UTC).print(dt);
66  *
67  * // parse using the Paris zone
68  * DateTime date = formatter.withZone(DateTimeZone.forID("Europe/Paris")).parseDateTime(str);
69  * </pre>
70  *
71  * @author Brian S O'Neill
72  * @author Stephen Colebourne
73  * @author Fredrik Borgh
74  * @since 1.0
75  */

76 public class DateTimeFormatter {
77
78     /** The internal printer used to output the datetime. */
79     private final DateTimePrinter iPrinter;
80     /** The internal parser used to output the datetime. */
81     private final DateTimeParser iParser;
82     /** The locale to use for printing and parsing. */
83     private final Locale JavaDoc iLocale;
84     /** Whether the offset is parsed. */
85     private final boolean iOffsetParsed;
86     /** The chronology to use as an override. */
87     private final Chronology iChrono;
88     /** The zone to use as an override. */
89     private final DateTimeZone iZone;
90     /* The pivot year to use for two-digit year parsing. */
91     private final Integer JavaDoc iPivotYear;
92
93     /**
94      * Creates a new formatter, however you will normally use the factory
95      * or the builder.
96      *
97      * @param printer the internal printer, null if cannot print
98      * @param parser the internal parser, null if cannot parse
99      */

100     public DateTimeFormatter(
101             DateTimePrinter printer, DateTimeParser parser) {
102         super();
103         iPrinter = printer;
104         iParser = parser;
105         iLocale = null;
106         iOffsetParsed = false;
107         iChrono = null;
108         iZone = null;
109         iPivotYear = null;
110     }
111
112     /**
113      * Constructor.
114      */

115     private DateTimeFormatter(
116             DateTimePrinter printer, DateTimeParser parser,
117             Locale JavaDoc locale, boolean offsetParsed,
118             Chronology chrono, DateTimeZone zone,
119             Integer JavaDoc pivotYear) {
120         super();
121         iPrinter = printer;
122         iParser = parser;
123         iLocale = locale;
124         iOffsetParsed = offsetParsed;
125         iChrono = chrono;
126         iZone = zone;
127         iPivotYear = pivotYear;
128     }
129
130     //-----------------------------------------------------------------------
131
/**
132      * Is this formatter capable of printing.
133      *
134      * @return true if this is a printer
135      */

136     public boolean isPrinter() {
137         return (iPrinter != null);
138     }
139
140     /**
141      * Gets the internal printer object that performs the real printing work.
142      *
143      * @return the internal printer
144      */

145     public DateTimePrinter getPrinter() {
146         return iPrinter;
147     }
148
149     /**
150      * Is this formatter capable of parsing.
151      *
152      * @return true if this is a parser
153      */

154     public boolean isParser() {
155         return (iParser != null);
156     }
157
158     /**
159      * Gets the internal parser object that performs the real parsing work.
160      *
161      * @return the internal parser
162      */

163     public DateTimeParser getParser() {
164         return iParser;
165     }
166
167     //-----------------------------------------------------------------------
168
/**
169      * Returns a new formatter with a different locale that will be used
170      * for printing and parsing.
171      * <p>
172      * A DateTimeFormatter is immutable, so a new instance is returned,
173      * and the original is unaltered and still usable.
174      *
175      * @param locale the locale to use
176      * @return the new formatter
177      */

178     public DateTimeFormatter withLocale(Locale JavaDoc locale) {
179         if (locale == getLocale() || (locale != null && locale.equals(getLocale()))) {
180             return this;
181         }
182         return new DateTimeFormatter(iPrinter, iParser, locale,
183                 iOffsetParsed, iChrono, iZone, iPivotYear);
184     }
185
186     /**
187      * Gets the locale that will be used for printing and parsing.
188      *
189      * @return the locale to use
190      */

191     public Locale JavaDoc getLocale() {
192         return iLocale;
193     }
194
195     //-----------------------------------------------------------------------
196
/**
197      * Returns a new formatter that will create a datetime with a time zone
198      * equal to that of the offset of the parsed string.
199      * <p>
200      * After calling this method, a string '2004-06-09T10:20:30-08:00' will
201      * create a datetime with a zone of -08:00 (a fixed zone, with no daylight
202      * savings rules). If the parsed string represents a local time (no zone
203      * offset) the parsed datetime will be in the default zone.
204      * <p>
205      * Calling this method sets the override zone to null.
206      * Calling the override zone method sets this flag off.
207      *
208      * @return the new formatter
209      */

210     public DateTimeFormatter withOffsetParsed() {
211         if (iOffsetParsed == true) {
212             return this;
213         }
214         return new DateTimeFormatter(iPrinter, iParser, iLocale,
215                 true, iChrono, null, iPivotYear);
216     }
217
218     /**
219      * Checks whether the offset from the string is used as the zone of
220      * the parsed datetime.
221      *
222      * @return true if the offset from the string is used as the zone
223      */

224     public boolean isOffsetParsed() {
225         return iOffsetParsed;
226     }
227
228     //-----------------------------------------------------------------------
229
/**
230      * Returns a new formatter that will use the specified chronology in
231      * preference to that of the printed object, or ISO on a parse.
232      * <p>
233      * When printing, this chronolgy will be used in preference to the chronology
234      * from the datetime that would otherwise be used.
235      * <p>
236      * When parsing, this chronology will be set on the parsed datetime.
237      * <p>
238      * A null chronology means no-override.
239      * If both an override chronology and an override zone are set, the
240      * override zone will take precedence over the zone in the chronology.
241      *
242      * @param chrono the chronology to use as an override
243      * @return the new formatter
244      */

245     public DateTimeFormatter withChronology(Chronology chrono) {
246         if (iChrono == chrono) {
247             return this;
248         }
249         return new DateTimeFormatter(iPrinter, iParser, iLocale,
250                 iOffsetParsed, chrono, iZone, iPivotYear);
251     }
252
253     /**
254      * Gets the chronology to use as an override.
255      *
256      * @return the chronology to use as an override
257      */

258     public Chronology getChronolgy() {
259         return iChrono;
260     }
261
262     //-----------------------------------------------------------------------
263
/**
264      * Returns a new formatter that will use the specified zone in preference
265      * to the zone of the printed object, or default zone on a parse.
266      * <p>
267      * When printing, this zone will be used in preference to the zone
268      * from the datetime that would otherwise be used.
269      * <p>
270      * When parsing, this zone will be set on the parsed datetime.
271      * <p>
272      * A null zone means of no-override.
273      * If both an override chronology and an override zone are set, the
274      * override zone will take precedence over the zone in the chronology.
275      *
276      * @param zone the zone to use as an override
277      * @return the new formatter
278      */

279     public DateTimeFormatter withZone(DateTimeZone zone) {
280         if (iZone == zone) {
281             return this;
282         }
283         return new DateTimeFormatter(iPrinter, iParser, iLocale,
284                 false, iChrono, zone, iPivotYear);
285     }
286
287     /**
288      * Gets the zone to use as an override.
289      *
290      * @return the zone to use as an override
291      */

292     public DateTimeZone getZone() {
293         return iZone;
294     }
295
296     //-----------------------------------------------------------------------
297
/**
298      * Returns a new formatter that will use the specified pivot year for two
299      * digit year parsing in preference to that stored in the parser.
300      * <p>
301      * This setting is useful for changing the pivot year of formats built
302      * using a pattern - {@link DateTimeFormat#forPattern(String)}.
303      * <p>
304      * When parsing, this pivot year is used. Null means no-override.
305      * There is no effect when printing.
306      * <p>
307      * The pivot year enables a two digit year to be converted to a four
308      * digit year. The pivot represents the year in the middle of the
309      * supported range of years. Thus the full range of years that will
310      * be built is <code>(pivot - 50) .. (pivot + 49)</code>.
311      *
312      * <pre>
313      * pivot supported range 00 is 20 is 40 is 60 is 80 is
314      * ---------------------------------------------------------------
315      * 1950 1900..1999 1900 1920 1940 1960 1980
316      * 1975 1925..2024 2000 2020 1940 1960 1980
317      * 2000 1950..2049 2000 2020 2040 1960 1980
318      * 2025 1975..2074 2000 2020 2040 2060 1980
319      * 2050 2000..2099 2000 2020 2040 2060 2080
320      * </pre>
321      *
322      * @param pivotYear the pivot year to use as an override when parsing
323      * @return the new formatter
324      * @since 1.1
325      */

326     public DateTimeFormatter withPivotYear(Integer JavaDoc pivotYear) {
327         if (iPivotYear == pivotYear || (iPivotYear != null && iPivotYear.equals(pivotYear))) {
328             return this;
329         }
330         return new DateTimeFormatter(iPrinter, iParser, iLocale,
331                 iOffsetParsed, iChrono, iZone, pivotYear);
332     }
333
334     /**
335      * Returns a new formatter that will use the specified pivot year for two
336      * digit year parsing in preference to that stored in the parser.
337      * <p>
338      * This setting is useful for changing the pivot year of formats built
339      * using a pattern - {@link DateTimeFormat#forPattern(String)}.
340      * <p>
341      * When parsing, this pivot year is used.
342      * There is no effect when printing.
343      * <p>
344      * The pivot year enables a two digit year to be converted to a four
345      * digit year. The pivot represents the year in the middle of the
346      * supported range of years. Thus the full range of years that will
347      * be built is <code>(pivot - 50) .. (pivot + 49)</code>.
348      *
349      * <pre>
350      * pivot supported range 00 is 20 is 40 is 60 is 80 is
351      * ---------------------------------------------------------------
352      * 1950 1900..1999 1900 1920 1940 1960 1980
353      * 1975 1925..2024 2000 2020 1940 1960 1980
354      * 2000 1950..2049 2000 2020 2040 1960 1980
355      * 2025 1975..2074 2000 2020 2040 2060 1980
356      * 2050 2000..2099 2000 2020 2040 2060 2080
357      * </pre>
358      *
359      * @param pivotYear the pivot year to use as an override when parsing
360      * @return the new formatter
361      * @since 1.1
362      */

363     public DateTimeFormatter withPivotYear(int pivotYear) {
364         return withPivotYear(new Integer JavaDoc(pivotYear));
365     }
366
367     /**
368      * Gets the pivot year to use as an override.
369      *
370      * @return the pivot year to use as an override
371      * @since 1.1
372      */

373     public Integer JavaDoc getPivotYear() {
374       return iPivotYear;
375     }
376
377     //-----------------------------------------------------------------------
378
/**
379      * Prints a ReadableInstant, using the chronology supplied by the instant.
380      *
381      * @param buf formatted instant is appended to this buffer
382      * @param instant instant to format, null means now
383      */

384     public void printTo(StringBuffer JavaDoc buf, ReadableInstant instant) {
385         checkPrinter();
386         
387         long millis = DateTimeUtils.getInstantMillis(instant);
388         Chronology chrono = DateTimeUtils.getInstantChronology(instant);
389         printTo(buf, millis, chrono);
390     }
391
392     /**
393      * Prints a ReadableInstant, using the chronology supplied by the instant.
394      *
395      * @param out formatted instant is written out
396      * @param instant instant to format, null means now
397      */

398     public void printTo(Writer JavaDoc out, ReadableInstant instant) throws IOException JavaDoc {
399         checkPrinter();
400         
401         long millis = DateTimeUtils.getInstantMillis(instant);
402         Chronology chrono = DateTimeUtils.getInstantChronology(instant);
403         printTo(out, millis, chrono);
404     }
405
406     //-----------------------------------------------------------------------
407
/**
408      * Prints an instant from milliseconds since 1970-01-01T00:00:00Z,
409      * using ISO chronology in the default DateTimeZone.
410      *
411      * @param buf formatted instant is appended to this buffer
412      * @param instant millis since 1970-01-01T00:00:00Z
413      */

414     public void printTo(StringBuffer JavaDoc buf, long instant) {
415         checkPrinter();
416         
417         printTo(buf, instant, null);
418     }
419
420     /**
421      * Prints an instant from milliseconds since 1970-01-01T00:00:00Z,
422      * using ISO chronology in the default DateTimeZone.
423      *
424      * @param out formatted instant is written out
425      * @param instant millis since 1970-01-01T00:00:00Z
426      */

427     public void printTo(Writer JavaDoc out, long instant) throws IOException JavaDoc {
428         checkPrinter();
429         
430         printTo(out, instant, null);
431     }
432
433     //-----------------------------------------------------------------------
434
/**
435      * Prints a ReadablePartial.
436      * <p>
437      * Neither the override chronology nor the override zone are used
438      * by this method.
439      *
440      * @param buf formatted partial is appended to this buffer
441      * @param partial partial to format
442      */

443     public void printTo(StringBuffer JavaDoc buf, ReadablePartial partial) {
444         checkPrinter();
445         if (partial == null) {
446             throw new IllegalArgumentException JavaDoc("The partial must not be null");
447         }
448         
449         iPrinter.printTo(buf, partial, iLocale);
450     }
451
452     /**
453      * Prints a ReadablePartial.
454      * <p>
455      * Neither the override chronology nor the override zone are used
456      * by this method.
457      *
458      * @param out formatted partial is written out
459      * @param partial partial to format
460      */

461     public void printTo(Writer JavaDoc out, ReadablePartial partial) throws IOException JavaDoc {
462         checkPrinter();
463         if (partial == null) {
464             throw new IllegalArgumentException JavaDoc("The partial must not be null");
465         }
466         
467         iPrinter.printTo(out, partial, iLocale);
468     }
469
470     //-----------------------------------------------------------------------
471
/**
472      * Prints a ReadableInstant to a String.
473      * <p>
474      * This method will use the override zone and the override chronololgy if
475      * they are set. Otherwise it will use the chronology and zone of the instant.
476      *
477      * @param instant instant to format, null means now
478      * @return the printed result
479      */

480     public String JavaDoc print(ReadableInstant instant) {
481         checkPrinter();
482         
483         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(iPrinter.estimatePrintedLength());
484         printTo(buf, instant);
485         return buf.toString();
486     }
487
488     /**
489      * Prints a millisecond instant to a String.
490      * <p>
491      * This method will use the override zone and the override chronololgy if
492      * they are set. Otherwise it will use the ISO chronology and default zone.
493      *
494      * @param instant millis since 1970-01-01T00:00:00Z
495      * @return the printed result
496      */

497     public String JavaDoc print(long instant) {
498         checkPrinter();
499         
500         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(iPrinter.estimatePrintedLength());
501         printTo(buf, instant);
502         return buf.toString();
503     }
504
505     /**
506      * Prints a ReadablePartial to a new String.
507      * <p>
508      * Neither the override chronology nor the override zone are used
509      * by this method.
510      *
511      * @param partial partial to format
512      * @return the printed result
513      */

514     public String JavaDoc print(ReadablePartial partial) {
515         checkPrinter();
516         
517         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(iPrinter.estimatePrintedLength());
518         printTo(buf, partial);
519         return buf.toString();
520     }
521
522     private void printTo(StringBuffer JavaDoc buf, long instant, Chronology chrono) {
523         chrono = selectChronology(chrono);
524         // Shift instant into local time (UTC) to avoid excessive offset
525
// calculations when printing multiple fields in a composite printer.
526
DateTimeZone zone = chrono.getZone();
527         int offset = zone.getOffset(instant);
528         long adjustedInstant = instant + offset;
529         if ((instant ^ adjustedInstant) < 0 && (instant ^ offset) >= 0) {
530             // Time zone offset overflow, so revert to UTC.
531
zone = DateTimeZone.UTC;
532             offset = 0;
533             adjustedInstant = instant;
534         }
535         iPrinter.printTo(buf, adjustedInstant, chrono.withUTC(), offset, zone, iLocale);
536     }
537
538     private void printTo(Writer JavaDoc buf, long instant, Chronology chrono) throws IOException JavaDoc {
539         chrono = selectChronology(chrono);
540         // Shift instant into local time (UTC) to avoid excessive offset
541
// calculations when printing multiple fields in a composite printer.
542
DateTimeZone zone = chrono.getZone();
543         int offset = zone.getOffset(instant);
544         long adjustedInstant = instant + offset;
545         if ((instant ^ adjustedInstant) < 0 && (instant ^ offset) >= 0) {
546             // Time zone offset overflow, so revert to UTC.
547
zone = DateTimeZone.UTC;
548             offset = 0;
549             adjustedInstant = instant;
550         }
551         iPrinter.printTo(buf, adjustedInstant, chrono.withUTC(), offset, zone, iLocale);
552     }
553
554     /**
555      * Checks whether printing is supported.
556      *
557      * @throws UnsupportedOperationException if printing is not supported
558      */

559     private void checkPrinter() {
560         if (iPrinter == null) {
561             throw new UnsupportedOperationException JavaDoc("Printing not supported");
562         }
563     }
564
565     //-----------------------------------------------------------------------
566
/**
567      * Parses a datetime from the given text, at the given position, saving the
568      * result into the fields of the given ReadWritableInstant. If the parse
569      * succeeds, the return value is the new text position. Note that the parse
570      * may succeed without fully reading the text and in this case those fields
571      * that were read will be set.
572      * <p>
573      * Only those fields present in the string will be changed in the specified
574      * instant. All other fields will remain unaltered. Thus if the string only
575      * contains a year and a month, then the day and time will be retained from
576      * the input instant. If this is not the behaviour you want, then reset the
577      * fields before calling this method, or use {@link #parseDateTime(String)}
578      * or {@link #parseMutableDateTime(String)}.
579      * <p>
580      * If it fails, the return value is negative, but the instant may still be
581      * modified. To determine the position where the parse failed, apply the
582      * one's complement operator (~) on the return value.
583      * <p>
584      * The parse will use the chronology of the instant.
585      *
586      * @param instant an instant that will be modified, not null
587      * @param text the text to parse
588      * @param position position to start parsing from
589      * @return new position, negative value means parse failed -
590      * apply complement operator (~) to get position of failure
591      * @throws UnsupportedOperationException if parsing is not supported
592      * @throws IllegalArgumentException if the instant is null
593      * @throws IllegalArgumentException if any field is out of range
594      */

595     public int parseInto(ReadWritableInstant instant, String JavaDoc text, int position) {
596         checkParser();
597         if (instant == null) {
598             throw new IllegalArgumentException JavaDoc("Instant must not be null");
599         }
600         
601         long instantMillis = instant.getMillis();
602         Chronology chrono = instant.getChronology();
603         long instantLocal = instantMillis + chrono.getZone().getOffset(instantMillis);
604         chrono = selectChronology(chrono);
605         
606         DateTimeParserBucket bucket = new DateTimeParserBucket
607             (instantLocal, chrono, iLocale, iPivotYear);
608         int newPos = iParser.parseInto(bucket, text, position);
609         instant.setMillis(bucket.computeMillis(false, text));
610         if (iOffsetParsed && bucket.getZone() == null) {
611             int parsedOffset = bucket.getOffset();
612             DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
613             chrono = chrono.withZone(parsedZone);
614         }
615         instant.setChronology(chrono);
616         return newPos;
617     }
618
619     /**
620      * Parses a datetime from the given text, returning the number of
621      * milliseconds since the epoch, 1970-01-01T00:00:00Z.
622      * <p>
623      * The parse will use the ISO chronology, and the default time zone.
624      * If the text contains a time zone string then that will be taken into account.
625      *
626      * @param text text to parse
627      * @return parsed value expressed in milliseconds since the epoch
628      * @throws UnsupportedOperationException if parsing is not supported
629      * @throws IllegalArgumentException if the text to parse is invalid
630      */

631     public long parseMillis(String JavaDoc text) {
632         checkParser();
633         
634         Chronology chrono = selectChronology(iChrono);
635         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear);
636         int newPos = iParser.parseInto(bucket, text, 0);
637         if (newPos >= 0) {
638             if (newPos >= text.length()) {
639                 return bucket.computeMillis(true, text);
640             }
641         } else {
642             newPos = ~newPos;
643         }
644         throw new IllegalArgumentException JavaDoc(FormatUtils.createErrorMessage(text, newPos));
645     }
646
647     /**
648      * Parses a datetime from the given text, returning a new DateTime.
649      * <p>
650      * The parse will use the zone and chronology specified on this formatter.
651      * <p>
652      * If the text contains a time zone string then that will be taken into
653      * account in adjusting the time of day as follows.
654      * If the {@link #withOffsetParsed()} has been called, then the resulting
655      * DateTime will have a fixed offset based on the parsed time zone.
656      * Otherwise the resulting DateTime will have the zone of this formatter,
657      * but the parsed zone may have caused the time to be adjusted.
658      *
659      * @param text the text to parse
660      * @return parsed value in a DateTime object
661      * @throws UnsupportedOperationException if parsing is not supported
662      * @throws IllegalArgumentException if the text to parse is invalid
663      */

664     public DateTime parseDateTime(String JavaDoc text) {
665         checkParser();
666         
667         Chronology chrono = selectChronology(null);
668         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear);
669         int newPos = iParser.parseInto(bucket, text, 0);
670         if (newPos >= 0) {
671             if (newPos >= text.length()) {
672                 long millis = bucket.computeMillis(true, text);
673                 if (iOffsetParsed && bucket.getZone() == null) {
674                     int parsedOffset = bucket.getOffset();
675                     DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
676                     chrono = chrono.withZone(parsedZone);
677                 }
678                 return new DateTime(millis, chrono);
679             }
680         } else {
681             newPos = ~newPos;
682         }
683         throw new IllegalArgumentException JavaDoc(FormatUtils.createErrorMessage(text, newPos));
684     }
685
686     /**
687      * Parses a datetime from the given text, returning a new MutableDateTime.
688      * <p>
689      * The parse will use the zone and chronology specified on this formatter.
690      * <p>
691      * If the text contains a time zone string then that will be taken into
692      * account in adjusting the time of day as follows.
693      * If the {@link #withOffsetParsed()} has been called, then the resulting
694      * DateTime will have a fixed offset based on the parsed time zone.
695      * Otherwise the resulting DateTime will have the zone of this formatter,
696      * but the parsed zone may have caused the time to be adjusted.
697      *
698      * @param text the text to parse
699      * @return parsed value in a MutableDateTime object
700      * @throws UnsupportedOperationException if parsing is not supported
701      * @throws IllegalArgumentException if the text to parse is invalid
702      */

703     public MutableDateTime parseMutableDateTime(String JavaDoc text) {
704         checkParser();
705         
706         Chronology chrono = selectChronology(null);
707         DateTimeParserBucket bucket = new DateTimeParserBucket(0, chrono, iLocale, iPivotYear);
708         int newPos = iParser.parseInto(bucket, text, 0);
709         if (newPos >= 0) {
710             if (newPos >= text.length()) {
711                 long millis = bucket.computeMillis(true, text);
712                 if (iOffsetParsed && bucket.getZone() == null) {
713                     int parsedOffset = bucket.getOffset();
714                     DateTimeZone parsedZone = DateTimeZone.forOffsetMillis(parsedOffset);
715                     chrono = chrono.withZone(parsedZone);
716                 }
717                 return new MutableDateTime(millis, chrono);
718             }
719         } else {
720             newPos = ~newPos;
721         }
722         throw new IllegalArgumentException JavaDoc(FormatUtils.createErrorMessage(text, newPos));
723     }
724
725     /**
726      * Checks whether parsing is supported.
727      *
728      * @throws UnsupportedOperationException if parsing is not supported
729      */

730     private void checkParser() {
731         if (iParser == null) {
732             throw new UnsupportedOperationException JavaDoc("Parsing not supported");
733         }
734     }
735
736     //-----------------------------------------------------------------------
737
/**
738      * Determines the correct chronology to use.
739      *
740      * @param chrono the proposed chronology
741      * @return the actual chronology
742      */

743     private Chronology selectChronology(Chronology chrono) {
744         chrono = DateTimeUtils.getChronology(chrono);
745         if (iChrono != null) {
746             chrono = iChrono;
747         }
748         if (iZone != null) {
749             chrono = chrono.withZone(iZone);
750         }
751         return chrono;
752     }
753
754 }
755
Popular Tags