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