View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.util.datetime;
18  
19  import java.io.Serializable;
20  import java.text.DateFormat;
21  import java.text.FieldPosition;
22  import java.text.ParseException;
23  import java.text.ParsePosition;
24  import java.util.Calendar;
25  import java.util.Date;
26  import java.util.Locale;
27  import java.util.TimeZone;
28  
29  /**
30   * This is a copy of Commons Lang's Fast Date Formatter.
31   */
32  public class FastDateFormat extends Format implements DatePrinter, DateParser, Serializable {
33  
34      /**
35       * FULL locale dependent date or time style.
36       */
37      public static final int FULL = DateFormat.FULL;
38      /**
39       * LONG locale dependent date or time style.
40       */
41      public static final int LONG = DateFormat.LONG;
42      /**
43       * MEDIUM locale dependent date or time style.
44       */
45      public static final int MEDIUM = DateFormat.MEDIUM;
46      /**
47       * SHORT locale dependent date or time style.
48       */
49      public static final int SHORT = DateFormat.SHORT;
50  
51      /**
52       * Required for serialization support.
53       *
54       * @see java.io.Serializable
55       */
56      private static final long serialVersionUID = 2L;
57  
58      private static final FormatCache<FastDateFormat> CACHE = new FormatCache<FastDateFormat>() {
59          @Override
60          protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
61              return new FastDateFormat(pattern, timeZone, locale);
62          }
63      };
64  
65      private final FastDatePrinter printer;
66      private final FastDateParser parser;
67  
68      // Constructor
69      // -----------------------------------------------------------------------
70      /**
71       * <p>
72       * Constructs a new FastDateFormat.
73       * </p>
74       *
75       * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
76       * @param timeZone non-null time zone to use
77       * @param locale non-null locale to use
78       * @throws NullPointerException if pattern, timeZone, or locale is null.
79       */
80      protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale) {
81          this(pattern, timeZone, locale, null);
82      }
83  
84      // Constructor
85      // -----------------------------------------------------------------------
86      /**
87       * <p>
88       * Constructs a new FastDateFormat.
89       * </p>
90       *
91       * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
92       * @param timeZone non-null time zone to use
93       * @param locale non-null locale to use
94       * @param centuryStart The start of the 100 year period to use as the "default century" for 2 digit year parsing.
95       *            If centuryStart is null, defaults to now - 80 years
96       * @throws NullPointerException if pattern, timeZone, or locale is null.
97       */
98      protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale,
99              final Date centuryStart) {
100         printer = new FastDatePrinter(pattern, timeZone, locale);
101         parser = new FastDateParser(pattern, timeZone, locale, centuryStart);
102     }
103 
104     // -----------------------------------------------------------------------
105     /**
106      * <p>
107      * Gets a formatter instance using the default pattern in the default locale.
108      * </p>
109      *
110      * @return a date/time formatter
111      */
112     public static FastDateFormat getInstance() {
113         return CACHE.getInstance();
114     }
115 
116     /**
117      * <p>
118      * Gets a formatter instance using the specified pattern in the default locale.
119      * </p>
120      *
121      * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
122      * @return a pattern based date/time formatter
123      * @throws IllegalArgumentException if pattern is invalid
124      */
125     public static FastDateFormat getInstance(final String pattern) {
126         return CACHE.getInstance(pattern, null, null);
127     }
128 
129     /**
130      * <p>
131      * Gets a formatter instance using the specified pattern and time zone.
132      * </p>
133      *
134      * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
135      * @param timeZone optional time zone, overrides time zone of formatted date
136      * @return a pattern based date/time formatter
137      * @throws IllegalArgumentException if pattern is invalid
138      */
139     public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone) {
140         return CACHE.getInstance(pattern, timeZone, null);
141     }
142 
143     /**
144      * <p>
145      * Gets a formatter instance using the specified pattern and locale.
146      * </p>
147      *
148      * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
149      * @param locale optional locale, overrides system locale
150      * @return a pattern based date/time formatter
151      * @throws IllegalArgumentException if pattern is invalid
152      */
153     public static FastDateFormat getInstance(final String pattern, final Locale locale) {
154         return CACHE.getInstance(pattern, null, locale);
155     }
156 
157     /**
158      * <p>
159      * Gets a formatter instance using the specified pattern, time zone and locale.
160      * </p>
161      *
162      * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
163      * @param timeZone optional time zone, overrides time zone of formatted date
164      * @param locale optional locale, overrides system locale
165      * @return a pattern based date/time formatter
166      * @throws IllegalArgumentException if pattern is invalid or {@code null}
167      */
168     public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
169         return CACHE.getInstance(pattern, timeZone, locale);
170     }
171 
172     // -----------------------------------------------------------------------
173     /**
174      * <p>
175      * Gets a date formatter instance using the specified style in the default time zone and locale.
176      * </p>
177      *
178      * @param style date style: FULL, LONG, MEDIUM, or SHORT
179      * @return a localized standard date formatter
180      * @throws IllegalArgumentException if the Locale has no date pattern defined
181      * @since 2.1
182      */
183     public static FastDateFormat getDateInstance(final int style) {
184         return CACHE.getDateInstance(style, null, null);
185     }
186 
187     /**
188      * <p>
189      * Gets a date formatter instance using the specified style and locale in the default time zone.
190      * </p>
191      *
192      * @param style date style: FULL, LONG, MEDIUM, or SHORT
193      * @param locale optional locale, overrides system locale
194      * @return a localized standard date formatter
195      * @throws IllegalArgumentException if the Locale has no date pattern defined
196      * @since 2.1
197      */
198     public static FastDateFormat getDateInstance(final int style, final Locale locale) {
199         return CACHE.getDateInstance(style, null, locale);
200     }
201 
202     /**
203      * <p>
204      * Gets a date formatter instance using the specified style and time zone in the default locale.
205      * </p>
206      *
207      * @param style date style: FULL, LONG, MEDIUM, or SHORT
208      * @param timeZone optional time zone, overrides time zone of formatted date
209      * @return a localized standard date formatter
210      * @throws IllegalArgumentException if the Locale has no date pattern defined
211      * @since 2.1
212      */
213     public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone) {
214         return CACHE.getDateInstance(style, timeZone, null);
215     }
216 
217     /**
218      * <p>
219      * Gets a date formatter instance using the specified style, time zone and locale.
220      * </p>
221      *
222      * @param style date style: FULL, LONG, MEDIUM, or SHORT
223      * @param timeZone optional time zone, overrides time zone of formatted date
224      * @param locale optional locale, overrides system locale
225      * @return a localized standard date formatter
226      * @throws IllegalArgumentException if the Locale has no date pattern defined
227      */
228     public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone, final Locale locale) {
229         return CACHE.getDateInstance(style, timeZone, locale);
230     }
231 
232     // -----------------------------------------------------------------------
233     /**
234      * <p>
235      * Gets a time formatter instance using the specified style in the default time zone and locale.
236      * </p>
237      *
238      * @param style time style: FULL, LONG, MEDIUM, or SHORT
239      * @return a localized standard time formatter
240      * @throws IllegalArgumentException if the Locale has no time pattern defined
241      * @since 2.1
242      */
243     public static FastDateFormat getTimeInstance(final int style) {
244         return CACHE.getTimeInstance(style, null, null);
245     }
246 
247     /**
248      * <p>
249      * Gets a time formatter instance using the specified style and locale in the default time zone.
250      * </p>
251      *
252      * @param style time style: FULL, LONG, MEDIUM, or SHORT
253      * @param locale optional locale, overrides system locale
254      * @return a localized standard time formatter
255      * @throws IllegalArgumentException if the Locale has no time pattern defined
256      * @since 2.1
257      */
258     public static FastDateFormat getTimeInstance(final int style, final Locale locale) {
259         return CACHE.getTimeInstance(style, null, locale);
260     }
261 
262     /**
263      * <p>
264      * Gets a time formatter instance using the specified style and time zone in the default locale.
265      * </p>
266      *
267      * @param style time style: FULL, LONG, MEDIUM, or SHORT
268      * @param timeZone optional time zone, overrides time zone of formatted time
269      * @return a localized standard time formatter
270      * @throws IllegalArgumentException if the Locale has no time pattern defined
271      * @since 2.1
272      */
273     public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone) {
274         return CACHE.getTimeInstance(style, timeZone, null);
275     }
276 
277     /**
278      * <p>
279      * Gets a time formatter instance using the specified style, time zone and locale.
280      * </p>
281      *
282      * @param style time style: FULL, LONG, MEDIUM, or SHORT
283      * @param timeZone optional time zone, overrides time zone of formatted time
284      * @param locale optional locale, overrides system locale
285      * @return a localized standard time formatter
286      * @throws IllegalArgumentException if the Locale has no time pattern defined
287      */
288     public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone, final Locale locale) {
289         return CACHE.getTimeInstance(style, timeZone, locale);
290     }
291 
292     // -----------------------------------------------------------------------
293     /**
294      * <p>
295      * Gets a date/time formatter instance using the specified style in the default time zone and locale.
296      * </p>
297      *
298      * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
299      * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
300      * @return a localized standard date/time formatter
301      * @throws IllegalArgumentException if the Locale has no date/time pattern defined
302      * @since 2.1
303      */
304     public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle) {
305         return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, null);
306     }
307 
308     /**
309      * <p>
310      * Gets a date/time formatter instance using the specified style and locale in the default time zone.
311      * </p>
312      *
313      * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
314      * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
315      * @param locale optional locale, overrides system locale
316      * @return a localized standard date/time formatter
317      * @throws IllegalArgumentException if the Locale has no date/time pattern defined
318      * @since 2.1
319      */
320     public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final Locale locale) {
321         return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, locale);
322     }
323 
324     /**
325      * <p>
326      * Gets a date/time formatter instance using the specified style and time zone in the default locale.
327      * </p>
328      *
329      * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
330      * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
331      * @param timeZone optional time zone, overrides time zone of formatted date
332      * @return a localized standard date/time formatter
333      * @throws IllegalArgumentException if the Locale has no date/time pattern defined
334      * @since 2.1
335      */
336     public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle,
337             final TimeZone timeZone) {
338         return getDateTimeInstance(dateStyle, timeStyle, timeZone, null);
339     }
340 
341     /**
342      * <p>
343      * Gets a date/time formatter instance using the specified style, time zone and locale.
344      * </p>
345      *
346      * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
347      * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
348      * @param timeZone optional time zone, overrides time zone of formatted date
349      * @param locale optional locale, overrides system locale
350      * @return a localized standard date/time formatter
351      * @throws IllegalArgumentException if the Locale has no date/time pattern defined
352      */
353     public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle,
354             final TimeZone timeZone, final Locale locale) {
355         return CACHE.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
356     }
357 
358     // Format methods
359     // -----------------------------------------------------------------------
360     /**
361      * <p>
362      * Formats a {@code Date}, {@code Calendar} or {@code Long} (milliseconds) object.
363      * </p>
364      *
365      * @param obj the object to format
366      * @param toAppendTo the buffer to append to
367      * @param pos the position - ignored
368      * @return the buffer passed in
369      */
370     @Override
371     public StringBuilder format(final Object obj, final StringBuilder toAppendTo, final FieldPosition pos) {
372         return printer.format(obj, toAppendTo, pos);
373     }
374 
375     /**
376      * <p>
377      * Formats a millisecond {@code long} value.
378      * </p>
379      *
380      * @param millis the millisecond value to format
381      * @return the formatted string
382      * @since 2.1
383      */
384     @Override
385     public String format(final long millis) {
386         return printer.format(millis);
387     }
388 
389     /**
390      * <p>
391      * Formats a {@code Date} object using a {@code GregorianCalendar}.
392      * </p>
393      *
394      * @param date the date to format
395      * @return the formatted string
396      */
397     @Override
398     public String format(final Date date) {
399         return printer.format(date);
400     }
401 
402     /**
403      * <p>
404      * Formats a {@code Calendar} object.
405      * </p>
406      *
407      * @param calendar the calendar to format
408      * @return the formatted string
409      */
410     @Override
411     public String format(final Calendar calendar) {
412         return printer.format(calendar);
413     }
414 
415     /**
416      * <p>
417      * Formats a millisecond {@code long} value into the supplied {@code StringBuilder}.
418      * </p>
419      *
420      * @param millis the millisecond value to format
421      * @param buf the buffer to format into
422      * @return the specified string buffer
423      * @since 2.1
424      */
425     @Override
426     public StringBuilder format(final long millis, final StringBuilder buf) {
427         return printer.format(millis, buf);
428     }
429 
430     /**
431      * <p>
432      * Formats a {@code Date} object into the supplied {@code StringBuilder} using a {@code GregorianCalendar}.
433      * </p>
434      *
435      * @param date the date to format
436      * @param buf the buffer to format into
437      * @return the specified string buffer
438      */
439     @Override
440     public StringBuilder format(final Date date, final StringBuilder buf) {
441         return printer.format(date, buf);
442     }
443 
444     /**
445      * <p>
446      * Formats a {@code Calendar} object into the supplied {@code StringBuilder}.
447      * </p>
448      *
449      * @param calendar the calendar to format
450      * @param buf the buffer to format into
451      * @return the specified string buffer
452      */
453     @Override
454     public StringBuilder format(final Calendar calendar, final StringBuilder buf) {
455         return printer.format(calendar, buf);
456     }
457 
458     // Parsing
459     // -----------------------------------------------------------------------
460 
461     /*
462      * (non-Javadoc)
463      * 
464      * @see DateParser#parse(java.lang.String)
465      */
466     @Override
467     public Date parse(final String source) throws ParseException {
468         return parser.parse(source);
469     }
470 
471     /*
472      * (non-Javadoc)
473      * 
474      * @see DateParser#parse(java.lang.String, java.text.ParsePosition)
475      */
476     @Override
477     public Date parse(final String source, final ParsePosition pos) {
478         return parser.parse(source, pos);
479     }
480 
481     /*
482      * (non-Javadoc)
483      * 
484      * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
485      */
486     @Override
487     public Object parseObject(final String source, final ParsePosition pos) {
488         return parser.parseObject(source, pos);
489     }
490 
491     // Accessors
492     // -----------------------------------------------------------------------
493     /**
494      * <p>
495      * Gets the pattern used by this formatter.
496      * </p>
497      *
498      * @return the pattern, {@link java.text.SimpleDateFormat} compatible
499      */
500     @Override
501     public String getPattern() {
502         return printer.getPattern();
503     }
504 
505     /**
506      * <p>
507      * Gets the time zone used by this formatter.
508      * </p>
509      *
510      * <p>
511      * This zone is always used for {@code Date} formatting.
512      * </p>
513      *
514      * @return the time zone
515      */
516     @Override
517     public TimeZone getTimeZone() {
518         return printer.getTimeZone();
519     }
520 
521     /**
522      * <p>
523      * Gets the locale used by this formatter.
524      * </p>
525      *
526      * @return the locale
527      */
528     @Override
529     public Locale getLocale() {
530         return printer.getLocale();
531     }
532 
533     /**
534      * <p>
535      * Gets an estimate for the maximum string length that the formatter will produce.
536      * </p>
537      *
538      * <p>
539      * The actual formatted length will almost always be less than or equal to this amount.
540      * </p>
541      *
542      * @return the maximum formatted length
543      */
544     public int getMaxLengthEstimate() {
545         return printer.getMaxLengthEstimate();
546     }
547 
548     public String toPattern() {
549         return printer.getPattern();
550     }
551 
552     // Basics
553     // -----------------------------------------------------------------------
554     /**
555      * <p>
556      * Compares two objects for equality.
557      * </p>
558      *
559      * @param obj the object to compare to
560      * @return {@code true} if equal
561      */
562     @Override
563     public boolean equals(final Object obj) {
564         if (!(obj instanceof FastDateFormat)) {
565             return false;
566         }
567         final FastDateFormat other = (FastDateFormat) obj;
568         // no need to check parser, as it has same invariants as printer
569         return printer.equals(other.printer);
570     }
571 
572     /**
573      * <p>
574      * Returns a hashcode compatible with equals.
575      * </p>
576      *
577      * @return a hashcode compatible with equals
578      */
579     @Override
580     public int hashCode() {
581         return printer.hashCode();
582     }
583 
584     /**
585      * <p>
586      * Gets a debugging string version of this formatter.
587      * </p>
588      *
589      * @return a debugging string
590      */
591     @Override
592     public String toString() {
593         return "FastDateFormat[" + printer.getPattern() + "," + printer.getLocale() + ","
594                 + printer.getTimeZone().getID() + "]";
595     }
596 
597     /**
598      * <p>
599      * Performs the formatting by applying the rules to the specified calendar.
600      * </p>
601      *
602      * @param calendar the calendar to format
603      * @param buf the buffer to format into
604      * @return the specified string buffer
605      */
606     protected StringBuilder applyRules(final Calendar calendar, final StringBuilder buf) {
607         return printer.applyRules(calendar, buf);
608     }
609 
610 }