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