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 }