001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.lang3.time;
019
020import java.text.DateFormat;
021import java.text.FieldPosition;
022import java.text.Format;
023import java.text.ParseException;
024import java.text.ParsePosition;
025import java.text.SimpleDateFormat;
026import java.util.Calendar;
027import java.util.Date;
028import java.util.GregorianCalendar;
029import java.util.Locale;
030import java.util.TimeZone;
031
032/**
033 * FastDateFormat is a fast and thread-safe version of {@link java.text.SimpleDateFormat}.
034 *
035 * <p>
036 * To obtain an instance of FastDateFormat, use one of the static factory methods: {@link #getInstance(String, TimeZone, Locale)},
037 * {@link #getDateInstance(int, TimeZone, Locale)}, {@link #getTimeInstance(int, TimeZone, Locale)}, or {@link #getDateTimeInstance(int, int, TimeZone, Locale)}
038 * </p>
039 *
040 * <p>
041 * Since FastDateFormat is thread safe, you can use a static member instance:
042 * </p>
043 * {@code
044 *   private static final FastDateFormat DATE_FORMATTER = FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.SHORT);
045 * }
046 *
047 * <p>
048 * This class can be used as a direct replacement to {@link SimpleDateFormat} in most formatting and parsing situations. This class is especially useful in
049 * multi-threaded server environments. {@link SimpleDateFormat} is not thread-safe in any JDK version, nor will it be as Sun have closed the bug/RFE.
050 * </p>
051 *
052 * <p>
053 * Note on memory retention: unlike {@code new SimpleDateFormat(pattern)}, instances obtained from the static factory methods are held in a static cache keyed
054 * by (pattern, time zone, locale). The cache is bounded (it is flushed when it exceeds an internal limit) and can be flushed explicitly with
055 * {@link #clear()}, but each distinct key retains its instance for the lifetime of the JVM until then. Prefer fixed, application-defined patterns; do not
056 * pass unvalidated caller-supplied pattern, time zone, or locale values to the factory methods.
057 * </p>
058 *
059 * <p>
060 * All patterns are compatible with SimpleDateFormat (except time zones and some year patterns - see below).
061 * </p>
062 *
063 * <p>
064 * Since 3.2, FastDateFormat supports parsing as well as printing.
065 * </p>
066 *
067 * <p>
068 * Java 1.4 introduced a new pattern letter, {@code 'Z'}, to represent time zones in RFC822 format (for example, {@code +0800} or {@code -1100}). This pattern letter can
069 * be used here (on all JDK versions).
070 * </p>
071 *
072 * <p>
073 * The pattern {@code 'ZZ'} represents ISO 8601 extended format time zones (for example, {@code +08:00} or {@code -11:00}), printing {@code Z} for
074 * a zero offset. Three or more {@code 'Z'} letters also print colon-separated offsets, but print {@code +00:00} for a zero offset. These patterns differ
075 * from {@link SimpleDateFormat}.
076 * </p>
077 *
078 * <p>
079 * When parsing, {@code 'ZZ'} accepts {@code Z} or a colon-separated numeric offset. Three or more {@code 'Z'} letters accept colon-separated numeric
080 * offsets as well as the RFC822 offsets, GMT offsets, and localized time zone names accepted by a single {@code 'Z'}.
081 * </p>
082 *
083 * <p>
084 * Javadoc cites for the year pattern: <i>For formatting, if the number of pattern letters is 2, the year is truncated to 2 digits; otherwise it is interpreted
085 * as a number.</i> Starting with Java 1.7 a pattern of 'Y' or 'YYY' will be formatted as '2003', while it was '03' in former Java versions. FastDateFormat
086 * implements the behavior of Java 7.
087 * </p>
088 *
089 * @since 2.0
090 */
091public class FastDateFormat extends Format implements DateParser, DatePrinter {
092
093    /**
094     * Required for serialization support.
095     *
096     * @see java.io.Serializable
097     */
098    private static final long serialVersionUID = 2L;
099
100    /**
101     * FULL locale dependent date or time style.
102     */
103    public static final int FULL = DateFormat.FULL;
104
105    /**
106     * LONG locale dependent date or time style.
107     */
108    public static final int LONG = DateFormat.LONG;
109
110    /**
111     * MEDIUM locale dependent date or time style.
112     */
113    public static final int MEDIUM = DateFormat.MEDIUM;
114
115    /**
116     * SHORT locale dependent date or time style.
117     */
118    public static final int SHORT = DateFormat.SHORT;
119
120    private static final AbstractFormatCache<FastDateFormat> CACHE = new AbstractFormatCache<FastDateFormat>() {
121
122        @Override
123        protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
124            return new FastDateFormat(pattern, timeZone, locale);
125        }
126    };
127
128    /**
129     * Clears the caches.
130     * <p>
131     * Clears the static caches used by {@link FastDateFormat}: the (pattern, time zone, locale) to instance cache and the time zone display-name cache.
132     * Cached instances already obtained by callers remain valid; subsequent factory calls simply create and cache new instances. This can be used for
133     * operational relief if many distinct patterns, time zones, or locales have been used.
134     * </p>
135     */
136    static void clear() {
137        AbstractFormatCache.clear();
138        CACHE.clearInstance();
139        FastDatePrinter.clear();
140    }
141
142//    /**
143//     * Clears the static caches used by {@link FastDateFormat}: the (pattern, time zone, locale) to instance cache and the time zone display-name cache.
144//     * Cached instances already obtained by callers remain valid; subsequent factory calls simply create and cache new instances. This can be used for
145//     * operational relief if many distinct patterns, time zones, or locales have been used.
146//     *
147//     * @since 3.21.0
148//     */
149//    public static void clearCache() {
150//        clear();
151//        FastDatePrinter.clear();
152//    }
153
154    /**
155     * Gets a date formatter instance using the specified style in the default time zone and locale.
156     *
157     * @param style date style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
158     * @return A localized standard date formatter.
159     * @throws IllegalArgumentException Thrown if the Locale has no date pattern defined.
160     * @since 2.1
161     */
162    public static FastDateFormat getDateInstance(final int style) {
163        return CACHE.getDateInstance(style, null, null);
164    }
165
166    /**
167     * Gets a date formatter instance using the specified style and locale in the default time zone.
168     *
169     * @param style  date style: {@link #FULL}, LO{@link #FULL},{@link #MEDIUM}, or {@link #SHORT}.
170     * @param locale optional locale, overrides system locale.
171     * @return A localized standard date formatter.
172     * @throws IllegalArgumentException Thrown if the Locale has no date pattern defined.
173     * @since 2.1
174     */
175    public static FastDateFormat getDateInstance(final int style, final Locale locale) {
176        return CACHE.getDateInstance(style, null, locale);
177    }
178
179    /**
180     * Gets a date formatter instance using the specified style and time zone in the default locale.
181     *
182     * @param style    date style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
183     * @param timeZone optional time zone, overrides time zone of formatted date.
184     * @return A localized standard date formatter.
185     * @throws IllegalArgumentException Thrown if the Locale has no date pattern defined.
186     * @since 2.1
187     */
188    public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone) {
189        return CACHE.getDateInstance(style, timeZone, null);
190    }
191
192    /**
193     * Gets a date formatter instance using the specified style, time zone and locale.
194     *
195     * @param style    date style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
196     * @param timeZone optional time zone, overrides time zone of formatted date.
197     * @param locale   optional locale, overrides system locale.
198     * @return A localized standard date formatter.
199     * @throws IllegalArgumentException Thrown if the Locale has no date pattern defined.
200     */
201    public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone, final Locale locale) {
202        return CACHE.getDateInstance(style, timeZone, locale);
203    }
204
205    /**
206     * Gets a date/time formatter instance using the specified style in the default time zone and locale.
207     *
208     * @param dateStyle date style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
209     * @param timeStyle time style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
210     * @return A localized standard date/time formatter.
211     * @throws IllegalArgumentException Thrown if the Locale has no date/time pattern defined.
212     * @since 2.1
213     */
214    public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle) {
215        return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, null);
216    }
217
218    /**
219     * Gets a date/time formatter instance using the specified style and locale in the default time zone.
220     *
221     * @param dateStyle date style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
222     * @param timeStyle time style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
223     * @param locale    optional locale, overrides system locale.
224     * @return A localized standard date/time formatter.
225     * @throws IllegalArgumentException Thrown if the Locale has no date/time pattern defined.
226     * @since 2.1
227     */
228    public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final Locale locale) {
229        return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, locale);
230    }
231
232    /**
233     * Gets a date/time formatter instance using the specified style and time zone in the default locale.
234     *
235     * @param dateStyle date style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
236     * @param timeStyle time style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
237     * @param timeZone  optional time zone, overrides time zone of formatted date.
238     * @return A localized standard date/time formatter.
239     * @throws IllegalArgumentException Thrown if the Locale has no date/time pattern defined.
240     * @since 2.1
241     */
242    public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone) {
243        return getDateTimeInstance(dateStyle, timeStyle, timeZone, null);
244    }
245
246    /**
247     * Gets a date/time formatter instance using the specified style, time zone and locale.
248     *
249     * @param dateStyle date style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
250     * @param timeStyle time style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
251     * @param timeZone  optional time zone, overrides time zone of formatted date.
252     * @param locale    optional locale, overrides system locale.
253     * @return A localized standard date/time formatter.
254     * @throws IllegalArgumentException Thrown if the Locale has no date/time pattern defined.
255     */
256    public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
257        return CACHE.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
258    }
259
260    /**
261     * Gets a formatter instance using the default pattern in the default locale.
262     *
263     * @return A date/time formatter.
264     */
265    public static FastDateFormat getInstance() {
266        return CACHE.getInstance();
267    }
268
269    /**
270     * Gets a formatter instance using the specified pattern in the default locale and time zone.
271     *
272     * @param pattern {@link java.text.SimpleDateFormat} compatible pattern.
273     * @return A pattern based date/time formatter.
274     * @throws IllegalArgumentException Thrown if pattern is invalid.
275     */
276    public static FastDateFormat getInstance(final String pattern) {
277        return CACHE.getInstance(pattern, null, null);
278    }
279
280    /**
281     * Gets a formatter instance using the specified pattern and locale using the default time zone.
282     *
283     * @param pattern {@link java.text.SimpleDateFormat} compatible pattern.
284     * @param locale  optional locale, overrides system locale.
285     * @return A pattern based date/time formatter.
286     * @throws IllegalArgumentException Thrown if pattern is invalid.
287     */
288    public static FastDateFormat getInstance(final String pattern, final Locale locale) {
289        return CACHE.getInstance(pattern, null, locale);
290    }
291
292    /**
293     * Gets a formatter instance using the specified pattern and time zone.
294     *
295     * @param pattern  {@link java.text.SimpleDateFormat} compatible pattern.
296     * @param timeZone optional time zone, overrides time zone of formatted date.
297     * @return A pattern based date/time formatter.
298     * @throws IllegalArgumentException Thrown if pattern is invalid.
299     */
300    public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone) {
301        return CACHE.getInstance(pattern, timeZone, null);
302    }
303
304    /**
305     * Gets a formatter instance using the specified pattern, time zone and locale.
306     *
307     * @param pattern  {@link java.text.SimpleDateFormat} compatible pattern.
308     * @param timeZone optional time zone, overrides time zone of formatted date.
309     * @param locale   optional locale, overrides system locale.
310     * @return A pattern based date/time formatter.
311     * @throws IllegalArgumentException Thrown if pattern is invalid or {@code null}.
312     */
313    public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
314        return CACHE.getInstance(pattern, timeZone, locale);
315    }
316
317    /**
318     * Gets a time formatter instance using the specified style in the default time zone and locale.
319     *
320     * @param style time style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
321     * @return A localized standard time formatter.
322     * @throws IllegalArgumentException Thrown if the Locale has no time pattern defined.
323     * @since 2.1
324     */
325    public static FastDateFormat getTimeInstance(final int style) {
326        return CACHE.getTimeInstance(style, null, null);
327    }
328
329    /**
330     * Gets a time formatter instance using the specified style and locale in the default time zone.
331     *
332     * @param style  time style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
333     * @param locale optional locale, overrides system locale.
334     * @return A localized standard time formatter.
335     * @throws IllegalArgumentException Thrown if the Locale has no time pattern defined.
336     * @since 2.1
337     */
338    public static FastDateFormat getTimeInstance(final int style, final Locale locale) {
339        return CACHE.getTimeInstance(style, null, locale);
340    }
341
342    /**
343     * Gets a time formatter instance using the specified style and time zone in the default locale.
344     *
345     * @param style    time style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
346     * @param timeZone optional time zone, overrides time zone of formatted time.
347     * @return A localized standard time formatter.
348     * @throws IllegalArgumentException Thrown if the Locale has no time pattern defined.
349     * @since 2.1
350     */
351    public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone) {
352        return CACHE.getTimeInstance(style, timeZone, null);
353    }
354
355    /**
356     * Gets a time formatter instance using the specified style, time zone and locale.
357     *
358     * @param style    time style: {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, or {@link #SHORT}.
359     * @param timeZone optional time zone, overrides time zone of formatted time.
360     * @param locale   optional locale, overrides system locale.
361     * @return A localized standard time formatter.
362     * @throws IllegalArgumentException Thrown if the Locale has no time pattern defined.
363     */
364    public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone, final Locale locale) {
365        return CACHE.getTimeInstance(style, timeZone, locale);
366    }
367
368    /** Our fast printer. */
369    private final FastDatePrinter printer;
370
371    /** Our fast parser. */
372    private final FastDateParser parser;
373
374    /**
375     * Constructs a new FastDateFormat.
376     *
377     * @param pattern  {@link java.text.SimpleDateFormat} compatible pattern.
378     * @param timeZone non-null time zone to use.
379     * @param locale   non-null locale to use.
380     * @throws NullPointerException Thrown if pattern, timeZone, or locale is null.
381     */
382    protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale) {
383        this(pattern, timeZone, locale, null);
384    }
385
386    /**
387     * Constructs a new FastDateFormat.
388     *
389     * @param pattern      {@link java.text.SimpleDateFormat} compatible pattern.
390     * @param timeZone     non-null time zone to use.
391     * @param locale       non-null locale to use.
392     * @param centuryStart The start of the 100-year period to use as the "default century" for 2 digit year parsing. If centuryStart is null, defaults to now -
393     *                     80 years.
394     * @throws NullPointerException Thrown if pattern, timeZone, or locale is null.
395     */
396    protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) {
397        printer = new FastDatePrinter(pattern, timeZone, locale);
398        parser = new FastDateParser(pattern, timeZone, locale, centuryStart);
399    }
400
401    /**
402     * Performs the formatting by applying the rules to the specified calendar.
403     *
404     * @param calendar The calendar to format.
405     * @param buf      The buffer to format into.
406     * @return The specified string buffer.
407     * @deprecated Use {@link #format(Calendar, Appendable)}
408     */
409    @Deprecated
410    protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) {
411        return printer.format(calendar, buf);
412    }
413
414    /**
415     * Compares two objects for equality.
416     *
417     * @param obj The object to compare to.
418     * @return {@code true} if equal.
419     */
420    @Override
421    public boolean equals(final Object obj) {
422        if (!(obj instanceof FastDateFormat)) {
423            return false;
424        }
425        final FastDateFormat other = (FastDateFormat) obj;
426        // no need to check parser, as it has same invariants as printer
427        return printer.equals(other.printer);
428    }
429
430    /**
431     * Formats a {@link Calendar} object.
432     *
433     * @param calendar The calendar to format.
434     * @return The formatted string.
435     */
436    @Override
437    public String format(final Calendar calendar) {
438        return printer.format(calendar);
439    }
440
441    /**
442     * Formats a {@link Calendar} object into the supplied {@link StringBuffer}.
443     *
444     * @param calendar The calendar to format.
445     * @param buf      The buffer to format into.
446     * @return The specified string buffer.
447     * @since 3.5
448     */
449    @Override
450    public <B extends Appendable> B format(final Calendar calendar, final B buf) {
451        return printer.format(calendar, buf);
452    }
453
454    /**
455     * Formats a {@link Calendar} object into the supplied {@link StringBuffer}.
456     *
457     * @param calendar The calendar to format.
458     * @param buf      The buffer to format into.
459     * @return The specified string buffer.
460     * @deprecated Use {{@link #format(Calendar, Appendable)}.
461     */
462    @Deprecated
463    @Override
464    public StringBuffer format(final Calendar calendar, final StringBuffer buf) {
465        return printer.format(calendar, buf);
466    }
467
468    /**
469     * Formats a {@link Date} object using a {@link GregorianCalendar}.
470     *
471     * @param date The date to format.
472     * @return The formatted string.
473     */
474    @Override
475    public String format(final Date date) {
476        return printer.format(date);
477    }
478
479    /**
480     * Formats a {@link Date} object into the supplied {@link StringBuffer} using a {@link GregorianCalendar}.
481     *
482     * @param date The date to format.
483     * @param buf  The buffer to format into.
484     * @return The specified string buffer.
485     * @since 3.5
486     */
487    @Override
488    public <B extends Appendable> B format(final Date date, final B buf) {
489        return printer.format(date, buf);
490    }
491
492    /**
493     * Formats a {@link Date} object into the supplied {@link StringBuffer} using a {@link GregorianCalendar}.
494     *
495     * @param date The date to format.
496     * @param buf  The buffer to format into.
497     * @return The specified string buffer.
498     * @deprecated Use {{@link #format(Date, Appendable)}.
499     */
500    @Deprecated
501    @Override
502    public StringBuffer format(final Date date, final StringBuffer buf) {
503        return printer.format(date, buf);
504    }
505
506    /**
507     * Formats a millisecond {@code long} value.
508     *
509     * @param millis The millisecond value to format.
510     * @return The formatted string.
511     * @since 2.1
512     */
513    @Override
514    public String format(final long millis) {
515        return printer.format(millis);
516    }
517
518    /**
519     * Formats a millisecond {@code long} value into the supplied {@link StringBuffer}.
520     *
521     * @param millis The millisecond value to format.
522     * @param buf    The buffer to format into.
523     * @return The specified string buffer.
524     * @since 3.5
525     */
526    @Override
527    public <B extends Appendable> B format(final long millis, final B buf) {
528        return printer.format(millis, buf);
529    }
530
531    /**
532     * Formats a millisecond {@code long} value into the supplied {@link StringBuffer}.
533     *
534     * @param millis The millisecond value to format.
535     * @param buf    The buffer to format into.
536     * @return The specified string buffer.
537     * @since 2.1
538     * @deprecated Use {{@link #format(long, Appendable)}.
539     */
540    @Deprecated
541    @Override
542    public StringBuffer format(final long millis, final StringBuffer buf) {
543        return printer.format(millis, buf);
544    }
545
546    /**
547     * Formats a {@link Date}, {@link Calendar} or {@link Long} (milliseconds) object. This method is an implementation of
548     * {@link Format#format(Object, StringBuffer, FieldPosition)}
549     *
550     * @param obj        The object to format.
551     * @param toAppendTo The buffer to append to.
552     * @param pos        The position, ignored.
553     * @return The given buffer.
554     */
555    @Override
556    public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
557        return toAppendTo.append(printer.format(obj));
558    }
559
560    /**
561     * Gets the locale used by this formatter.
562     *
563     * @return The locale.
564     */
565    @Override
566    public Locale getLocale() {
567        return printer.getLocale();
568    }
569
570    /**
571     * Gets an estimate for the maximum string length that the formatter will produce.
572     *
573     * <p>
574     * The actual formatted length will almost always be less than or equal to this amount.
575     * </p>
576     *
577     * @return The maximum formatted length.
578     */
579    public int getMaxLengthEstimate() {
580        return printer.getMaxLengthEstimate();
581    }
582
583    /**
584     * Gets the pattern used by this formatter.
585     *
586     * @return The pattern, {@link java.text.SimpleDateFormat} compatible.
587     */
588    @Override
589    public String getPattern() {
590        return printer.getPattern();
591    }
592
593    /**
594     * Gets the time zone used by this formatter.
595     *
596     * <p>
597     * This zone is always used for {@link Date} formatting.
598     * </p>
599     *
600     * @return A copy of the time zone, changing it has no effect on this formatter.
601     */
602    @Override
603    public TimeZone getTimeZone() {
604        return printer.getTimeZone();
605    }
606
607    /**
608     * Returns a hash code compatible with equals.
609     *
610     * @return A hash code compatible with equals.
611     */
612    @Override
613    public int hashCode() {
614        return printer.hashCode();
615    }
616
617    /*
618     * (non-Javadoc)
619     *
620     * @see DateParser#parse(String)
621     */
622    @Override
623    public Date parse(final String source) throws ParseException {
624        return parser.parse(source);
625    }
626
627    /*
628     * (non-Javadoc)
629     *
630     * @see DateParser#parse(String, java.text.ParsePosition)
631     */
632    @Override
633    public Date parse(final String source, final ParsePosition pos) {
634        return parser.parse(source, pos);
635    }
636
637    /*
638     * (non-Javadoc)
639     *
640     * @see org.apache.commons.lang3.time.DateParser#parse(String, java.text.ParsePosition, java.util.Calendar)
641     */
642    @Override
643    public boolean parse(final String source, final ParsePosition pos, final Calendar calendar) {
644        return parser.parse(source, pos, calendar);
645    }
646
647    /*
648     * (non-Javadoc)
649     *
650     * @see java.text.Format#parseObject(String, java.text.ParsePosition)
651     */
652    @Override
653    public Object parseObject(final String source, final ParsePosition pos) {
654        return parser.parseObject(source, pos);
655    }
656
657    /**
658     * Gets a debugging string version of this formatter.
659     *
660     * @return A debug string.
661     */
662    @Override
663    public String toString() {
664        return "FastDateFormat[" + printer.getPattern() + "," + printer.getLocale() + "," + printer.getTimeZone().getID() + "]";
665    }
666}