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