This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/2.x by this push:
     new f9766bb3b7 Removed unused `FastDateParser` (LOG4J2-3672, #1848)
f9766bb3b7 is described below

commit f9766bb3b7cf7a914c3ae36358aa053ee088b097
Author: Volkan Yazıcı <[email protected]>
AuthorDate: Thu Nov 2 18:28:44 2023 +0100

    Removed unused `FastDateParser` (LOG4J2-3672, #1848)
---
 .../core/util/datetime/FastDateParserTest.java     | 724 ---------------
 log4j-core/pom.xml                                 |  15 +
 .../log4j/core/util/datetime/DateParser.java       | 131 ---
 .../log4j/core/util/datetime/FastDateFormat.java   |  53 +-
 .../log4j/core/util/datetime/FastDateParser.java   | 992 ---------------------
 .../logging/log4j/core/util/datetime/Format.java   |  12 -
 src/changelog/.2.x.x/remove_FastDateParser.xml     |   9 +
 src/site/_release-notes/_2.x.x.adoc                |   4 +
 8 files changed, 30 insertions(+), 1910 deletions(-)

diff --git 
a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParserTest.java
 
b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParserTest.java
deleted file mode 100644
index 1859435941..0000000000
--- 
a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/datetime/FastDateParserTest.java
+++ /dev/null
@@ -1,724 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core.util.datetime;
-
-import java.io.Serializable;
-import java.text.ParseException;
-import java.text.ParsePosition;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-
-import org.apache.commons.lang3.LocaleUtils;
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-
-/**
- * Unit tests {@link org.apache.commons.lang3.time.FastDateParser}.
- *
- * Copied from Apache Commons Lang 3 on 2016-11-16.
- */
-public class FastDateParserTest {
-    private static enum Expected1806 {
-        India(INDIA, "+05", "+0530", "+05:30", true),
-        Greenwich(GMT, "Z", "Z", "Z", false),
-        NewYork(NEW_YORK, "-05", "-0500", "-05:00", false);
-
-        final TimeZone zone;
-
-        final String one;
-        final String two;
-        final String three;
-        final long offset;
-        private Expected1806(final TimeZone zone, final String one, final 
String two, final String three, final boolean hasHalfHourOffset) {
-            this.zone = zone;
-            this.one = one;
-            this.two = two;
-            this.three = three;
-            this.offset = hasHalfHourOffset ?30*60*1000 :0;
-        }
-    }
-    private static final String SHORT_FORMAT_NOERA = "y/M/d/h/a/m/s/E";
-    private static final String LONG_FORMAT_NOERA = 
"yyyy/MMMM/dddd/hhhh/mmmm/ss/aaaa/EEEE";
-    private static final String SHORT_FORMAT = "G/" + SHORT_FORMAT_NOERA;
-
-    private static final String LONG_FORMAT = "GGGG/" + LONG_FORMAT_NOERA;
-    private static final String yMdHmsSZ = "yyyy-MM-dd'T'HH:mm:ss.SSS Z";
-    private static final String DMY_DOT = "dd.MM.yyyy";
-    private static final String YMD_SLASH = "yyyy/MM/dd";
-    private static final String MDY_DASH = "MM-DD-yyyy";
-
-    private static final String MDY_SLASH = "MM/DD/yyyy";
-    private static final TimeZone REYKJAVIK = 
TimeZone.getTimeZone("Atlantic/Reykjavik");
-    private static final TimeZone NEW_YORK = 
TimeZone.getTimeZone("America/New_York");
-    private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
-
-    private static final TimeZone INDIA = 
TimeZone.getTimeZone("Asia/Calcutta");
-
-    private static final Locale SWEDEN = new Locale("sv", "SE");
-
-    private static Calendar initializeCalendar(final TimeZone tz) {
-        final Calendar cal = Calendar.getInstance(tz);
-        cal.set(Calendar.YEAR, 2001);
-        cal.set(Calendar.MONTH, 1); // not daylight savings
-        cal.set(Calendar.DAY_OF_MONTH, 4);
-        cal.set(Calendar.HOUR_OF_DAY, 12);
-        cal.set(Calendar.MINUTE, 8);
-        cal.set(Calendar.SECOND, 56);
-        cal.set(Calendar.MILLISECOND, 235);
-        return cal;
-    }
-
-    private void checkParse(final Locale locale, final Calendar cal, final 
SimpleDateFormat sdf, final DateParser fdf) throws ParseException {
-        final String formattedDate= sdf.format(cal.getTime());
-        checkParse(locale, sdf, fdf, formattedDate);
-        checkParse(locale, sdf, fdf, formattedDate.toLowerCase(locale));
-        checkParse(locale, sdf, fdf, formattedDate.toUpperCase(locale));
-    }
-
-    private void checkParse(final Locale locale, final SimpleDateFormat sdf, 
final DateParser fdf, final String formattedDate) throws ParseException {
-        final Date expectedTime = sdf.parse(formattedDate);
-        final Date actualTime = fdf.parse(formattedDate);
-        assertEquals(expectedTime, actualTime, locale.toString() + " " + 
formattedDate + "\n");
-    }
-
-    private DateParser getDateInstance(final int dateStyle, final Locale 
locale) {
-        return 
getInstance(FormatCache.getPatternForStyle(Integer.valueOf(dateStyle), null, 
locale), TimeZone.getDefault(), Locale.getDefault());
-    }
-
-    private Calendar getEraStart(int year, final TimeZone zone, final Locale 
locale) {
-        final Calendar cal = Calendar.getInstance(zone, locale);
-        cal.clear();
-
-        // 
http://docs.oracle.com/javase/6/docs/technotes/guides/intl/calendar.doc.html
-        if (locale.equals(FastDateParser.JAPANESE_IMPERIAL)) {
-            if(year < 1868) {
-                cal.set(Calendar.ERA, 0);
-                cal.set(Calendar.YEAR, 1868-year);
-            }
-        }
-        else {
-            if (year < 0) {
-                cal.set(Calendar.ERA, GregorianCalendar.BC);
-                year= -year;
-            }
-            cal.set(Calendar.YEAR, year/100 * 100);
-        }
-        return cal;
-    }
-
-    DateParser getInstance(final String format) {
-        return getInstance(format, TimeZone.getDefault(), Locale.getDefault());
-    }
-
-    private DateParser getInstance(final String format, final Locale locale) {
-        return getInstance(format, TimeZone.getDefault(), locale);
-    }
-
-    private DateParser getInstance(final String format, final TimeZone 
timeZone) {
-        return getInstance(format, timeZone, Locale.getDefault());
-    }
-
-    /**
-     * Override this method in derived tests to change the construction of 
instances
-     *
-     * @param format the format string to use
-     * @param timeZone the time zone to use
-     * @param locale the locale to use
-     *
-     * @return the DateParser instance to use for testing
-     */
-    protected DateParser getInstance(final String format, final TimeZone 
timeZone, final Locale locale) {
-        return new FastDateParser(format, timeZone, locale, null);
-    }
-
-    @Test
-    public void test_Equality_Hash() {
-        final DateParser[] parsers= {
-            getInstance(yMdHmsSZ, NEW_YORK, Locale.US),
-            getInstance(DMY_DOT, NEW_YORK, Locale.US),
-            getInstance(YMD_SLASH, NEW_YORK, Locale.US),
-            getInstance(MDY_DASH, NEW_YORK, Locale.US),
-            getInstance(MDY_SLASH, NEW_YORK, Locale.US),
-            getInstance(MDY_SLASH, REYKJAVIK, Locale.US),
-            getInstance(MDY_SLASH, REYKJAVIK, SWEDEN)
-        };
-
-        final Map<DateParser,Integer> map= new HashMap<>();
-        int i= 0;
-        for(final DateParser parser:parsers) {
-            map.put(parser, Integer.valueOf(i++));
-        }
-
-        i= 0;
-        for(final DateParser parser:parsers) {
-            assertEquals(i++, map.get(parser).intValue());
-        }
-    }
-
-    @Test
-    public void test1806() throws ParseException {
-        final String formatStub = "yyyy-MM-dd'T'HH:mm:ss.SSS";
-        final String dateStub = "2001-02-04T12:08:56.235";
-
-        for (final Expected1806 trial : Expected1806.values()) {
-            final Calendar cal = initializeCalendar(trial.zone);
-
-            final String message = trial.zone.getDisplayName()+";";
-
-            DateParser parser = getInstance(formatStub+"X", trial.zone);
-            assertEquals(cal.getTime().getTime(), parser.parse(dateStub + 
trial.one).getTime() - trial.offset,
-                    message + trial.one);
-
-            parser = getInstance(formatStub+"XX", trial.zone);
-            assertEquals(cal.getTime(), parser.parse(dateStub + trial.two), 
message + trial.two);
-
-            parser = getInstance(formatStub+"XXX", trial.zone);
-            assertEquals(cal.getTime(), parser.parse(dateStub + trial.three), 
message + trial.three);
-        }
-    }
-
-    @Test
-    public void test1806Argument() {
-        assertThrows(IllegalArgumentException.class, () -> 
getInstance("XXXX"));
-    }
-
-
-    @Test
-    public void testAmPm() throws ParseException {
-        final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
-        cal.clear();
-
-        final DateParser h = getInstance("yyyy-MM-dd hh a mm:ss", NEW_YORK, 
Locale.US);
-        final DateParser K = getInstance("yyyy-MM-dd KK a mm:ss", NEW_YORK, 
Locale.US);
-        final DateParser k = getInstance("yyyy-MM-dd kk:mm:ss", NEW_YORK, 
Locale.US);
-        final DateParser H = getInstance("yyyy-MM-dd HH:mm:ss", NEW_YORK, 
Locale.US);
-
-        cal.set(2010, Calendar.AUGUST, 1, 0, 33, 20);
-        assertEquals(cal.getTime(), h.parse("2010-08-01 12 AM 33:20"));
-        assertEquals(cal.getTime(), K.parse("2010-08-01 0 AM 33:20"));
-        assertEquals(cal.getTime(), k.parse("2010-08-01 00:33:20"));
-        assertEquals(cal.getTime(), H.parse("2010-08-01 00:33:20"));
-
-        cal.set(2010, Calendar.AUGUST, 1, 3, 33, 20);
-        assertEquals(cal.getTime(), h.parse("2010-08-01 3 AM 33:20"));
-        assertEquals(cal.getTime(), K.parse("2010-08-01 3 AM 33:20"));
-        assertEquals(cal.getTime(), k.parse("2010-08-01 03:33:20"));
-        assertEquals(cal.getTime(), H.parse("2010-08-01 03:33:20"));
-
-        cal.set(2010, Calendar.AUGUST, 1, 15, 33, 20);
-        assertEquals(cal.getTime(), h.parse("2010-08-01 3 PM 33:20"));
-        assertEquals(cal.getTime(), K.parse("2010-08-01 3 PM 33:20"));
-        assertEquals(cal.getTime(), k.parse("2010-08-01 15:33:20"));
-        assertEquals(cal.getTime(), H.parse("2010-08-01 15:33:20"));
-
-        cal.set(2010, Calendar.AUGUST, 1, 12, 33, 20);
-        assertEquals(cal.getTime(), h.parse("2010-08-01 12 PM 33:20"));
-        assertEquals(cal.getTime(), K.parse("2010-08-01 0 PM 33:20"));
-        assertEquals(cal.getTime(), k.parse("2010-08-01 12:33:20"));
-        assertEquals(cal.getTime(), H.parse("2010-08-01 12:33:20"));
-    }
-
-    @Test
-    public void testDayNumberOfWeek() throws ParseException {
-        final DateParser parser = getInstance("u");
-        final Calendar calendar = Calendar.getInstance();
-
-        calendar.setTime(parser.parse("1"));
-        assertEquals(Calendar.MONDAY, calendar.get(Calendar.DAY_OF_WEEK));
-
-        calendar.setTime(parser.parse("6"));
-        assertEquals(Calendar.SATURDAY, calendar.get(Calendar.DAY_OF_WEEK));
-
-        calendar.setTime(parser.parse("7"));
-        assertEquals(Calendar.SUNDAY, calendar.get(Calendar.DAY_OF_WEEK));
-    }
-
-    @Test
-    public void testDayOf() throws ParseException {
-        final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
-        cal.clear();
-        cal.set(2003, Calendar.FEBRUARY, 10);
-
-        final DateParser fdf = getInstance("W w F D y", NEW_YORK, Locale.US);
-        assertEquals(cal.getTime(), fdf.parse("3 7 2 41 03"));
-    }
-
-    @Test
-    public void testEquals() {
-        final DateParser parser1= getInstance(YMD_SLASH);
-        final DateParser parser2= getInstance(YMD_SLASH);
-
-        assertEquals(parser1, parser2);
-        assertEquals(parser1.hashCode(), parser2.hashCode());
-
-        assertFalse(parser1.equals(new Object()));
-    }
-
-    @Test
-    public void testJpLocales() {
-
-        final Calendar cal= Calendar.getInstance(GMT);
-        cal.clear();
-        cal.set(2003, Calendar.FEBRUARY, 10);
-        cal.set(Calendar.ERA, GregorianCalendar.BC);
-
-        final Locale locale = LocaleUtils.toLocale("zh"); {
-            // ja_JP_JP cannot handle dates before 1868 properly
-
-            final SimpleDateFormat sdf = new SimpleDateFormat(LONG_FORMAT, 
locale);
-            final DateParser fdf = getInstance(LONG_FORMAT, locale);
-
-            try {
-                checkParse(locale, cal, sdf, fdf);
-            } catch(final ParseException ex) {
-                fail("Locale " + locale + " failed with " + LONG_FORMAT + "\n" 
+ trimMessage(ex.toString()));
-            }
-        }
-    }
-
-    @Test
-    public void testLANG_831() throws Exception {
-        testSdfAndFdp("M E","3  Tue", true);
-    }
-
-    @Test
-    public void testLANG_832() throws Exception {
-        testSdfAndFdp("'d'd" ,"d3", false); // OK
-        testSdfAndFdp("'d'd'","d3", true); // should fail (unterminated quote)
-    }
-
-    @Test
-    public void testLang1121() throws ParseException {
-        final TimeZone kst = TimeZone.getTimeZone("Asia/Seoul");
-        final DateParser fdp = getInstance("yyyyMMdd", kst, Locale.KOREA);
-
-        try {
-            fdp.parse("2015");
-            fail("expected parse exception");
-        } catch (final ParseException pe) {
-            // expected parse exception
-        }
-
-        // Wed Apr 29 00:00:00 KST 2015
-        Date actual = fdp.parse("20150429");
-        final Calendar cal = Calendar.getInstance(kst, Locale.KOREA);
-        cal.clear();
-        cal.set(2015, 3, 29);
-        Date expected = cal.getTime();
-        assertEquals(expected, actual);
-
-        final SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd", 
Locale.KOREA);
-        df.setTimeZone(kst);
-        expected = df.parse("20150429113100");
-
-        // Thu Mar 16 00:00:00 KST 81724
-        actual = fdp.parse("20150429113100");
-        assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testLang303() throws ParseException {
-        DateParser parser = getInstance(YMD_SLASH);
-        final Calendar cal = Calendar.getInstance();
-        cal.set(2004, Calendar.DECEMBER, 31);
-
-        final Date date = parser.parse("2004/11/31");
-
-        parser = 
SerializationUtils.deserialize(SerializationUtils.serialize((Serializable) 
parser));
-        assertEquals(date, parser.parse("2004/11/31"));
-    }
-
-    @Test
-    public void testLang538() throws ParseException {
-        final DateParser parser = getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", 
GMT);
-
-        final Calendar cal = 
Calendar.getInstance(TimeZone.getTimeZone("GMT-8"));
-        cal.clear();
-        cal.set(2009, Calendar.OCTOBER, 16, 8, 42, 16);
-
-        assertEquals(cal.getTime(), parser.parse("2009-10-16T16:42:16.000Z"));
-    }
-
-    @Test
-    public void testLang996() throws ParseException {
-        final Calendar expected = Calendar.getInstance(NEW_YORK, Locale.US);
-        expected.clear();
-        expected.set(2014, Calendar.MAY, 14);
-
-        final DateParser fdp = getInstance("ddMMMyyyy", NEW_YORK, Locale.US);
-        assertEquals(expected.getTime(), fdp.parse("14may2014"));
-        assertEquals(expected.getTime(), fdp.parse("14MAY2014"));
-        assertEquals(expected.getTime(), fdp.parse("14May2014"));
-    }
-
-    @Test
-    public void testLocaleMatches() {
-        final DateParser parser= getInstance(yMdHmsSZ, SWEDEN);
-        assertEquals(SWEDEN, parser.getLocale());
-    }
-
-    private void testLocales(final String format, final boolean eraBC) throws 
Exception {
-
-        final Calendar cal= Calendar.getInstance(GMT);
-        cal.clear();
-        cal.set(2003, Calendar.FEBRUARY, 10);
-        if (eraBC) {
-            cal.set(Calendar.ERA, GregorianCalendar.BC);
-        }
-
-        for(final Locale locale : Locale.getAvailableLocales() ) {
-            // ja_JP_JP cannot handle dates before 1868 properly
-            if (eraBC && locale.equals(FastDateParser.JAPANESE_IMPERIAL)) {
-                continue;
-            }
-            final SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
-            final DateParser fdf = getInstance(format, locale);
-
-            try {
-                checkParse(locale, cal, sdf, fdf);
-            } catch(final ParseException ex) {
-                fail("Locale " + locale + " failed with " + format + " era " + 
(eraBC ? "BC" : "AD") + "\n"
-                        + trimMessage(ex.toString()));
-            }
-        }
-    }
-
-    @Test
-    public void testLocales_Long_AD() throws Exception {
-        testLocales(LONG_FORMAT, false);
-    }
-
-    @Test
-    public void testLocales_Long_BC() throws Exception {
-        testLocales(LONG_FORMAT, true);
-    }
-
-    @Test
-    public void testLocales_LongNoEra_AD() throws Exception {
-        testLocales(LONG_FORMAT_NOERA, false);
-    }
-
-    @Test
-    public void testLocales_LongNoEra_BC() throws Exception {
-        testLocales(LONG_FORMAT_NOERA, true);
-    }
-
-    @Test
-    public void testLocales_Short_AD() throws Exception {
-        testLocales(SHORT_FORMAT, false);
-    }
-
-    @Test
-    public void testLocales_Short_BC() throws Exception {
-        testLocales(SHORT_FORMAT, true);
-    }
-
-    @Test
-    public void testLocales_ShortNoEra_AD() throws Exception {
-        testLocales(SHORT_FORMAT_NOERA, false);
-    }
-
-    @Test
-    public void testLocales_ShortNoEra_BC() throws Exception {
-        testLocales(SHORT_FORMAT_NOERA, true);
-    }
-
-    /**
-     * Tests that pre-1000AD years get padded with yyyy
-     * @throws ParseException so we don't have to catch it
-     */
-    @Test
-    public void testLowYearPadding() throws ParseException {
-        final DateParser parser = getInstance(YMD_SLASH);
-        final Calendar cal = Calendar.getInstance();
-        cal.clear();
-
-        cal.set(1, Calendar.JANUARY, 1);
-        assertEquals(cal.getTime(), parser.parse("0001/01/01"));
-        cal.set(10, Calendar.JANUARY, 1);
-        assertEquals(cal.getTime(), parser.parse("0010/01/01"));
-        cal.set(100, Calendar.JANUARY, 1);
-        assertEquals(cal.getTime(), parser.parse("0100/01/01"));
-        cal.set(999, Calendar.JANUARY, 1);
-        assertEquals(cal.getTime(), parser.parse("0999/01/01"));
-    }
-
-    @Test
-    public void testMilleniumBug() throws ParseException {
-        final DateParser parser = getInstance(DMY_DOT);
-        final Calendar cal = Calendar.getInstance();
-        cal.clear();
-
-        cal.set(1000, Calendar.JANUARY, 1);
-        assertEquals(cal.getTime(), parser.parse("01.01.1000"));
-    }
-
-    @Test
-    public void testParseLongShort() throws ParseException {
-        final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
-        cal.clear();
-        cal.set(2003, Calendar.FEBRUARY, 10, 15, 33, 20);
-        cal.set(Calendar.MILLISECOND, 989);
-        cal.setTimeZone(NEW_YORK);
-
-        DateParser fdf = getInstance("yyyy GGGG MMMM dddd aaaa EEEE HHHH mmmm 
ssss SSSS ZZZZ", NEW_YORK, Locale.US);
-
-        assertEquals(cal.getTime(), fdf.parse("2003 AD February 0010 PM Monday 
0015 0033 0020 0989 GMT-05:00"));
-        cal.set(Calendar.ERA, GregorianCalendar.BC);
-
-        final Date parse = fdf.parse("2003 BC February 0010 PM Saturday 0015 
0033 0020 0989 GMT-05:00");
-                assertEquals(cal.getTime(), parse);
-
-        fdf = getInstance("y G M d a E H m s S Z", NEW_YORK, Locale.US);
-        assertEquals(cal.getTime(), fdf.parse("03 BC 2 10 PM Sat 15 33 20 989 
-0500"));
-
-        cal.set(Calendar.ERA, GregorianCalendar.AD);
-        assertEquals(cal.getTime(), fdf.parse("03 AD 2 10 PM Saturday 15 33 20 
989 -0500"));
-    }
-
-    @Test
-    public void testParseNumerics() throws ParseException {
-        final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
-        cal.clear();
-        cal.set(2003, Calendar.FEBRUARY, 10, 15, 33, 20);
-        cal.set(Calendar.MILLISECOND, 989);
-
-        final DateParser fdf = getInstance("yyyyMMddHHmmssSSS", NEW_YORK, 
Locale.US);
-        assertEquals(cal.getTime(), fdf.parse("20030210153320989"));
-    }
-
-    @Test
-    public void testParseOffset() {
-        final DateParser parser = getInstance(YMD_SLASH);
-        final Date date = parser.parse("Today is 2015/07/04", new 
ParsePosition(9));
-
-        final Calendar cal = Calendar.getInstance();
-        cal.clear();
-        cal.set(2015, Calendar.JULY, 4);
-        assertEquals(cal.getTime(), date);
-    }
-
-    @Test
-    // Check that all Locales can parse the formats we use
-    public void testParses() throws Exception {
-        for(final String format : new String[]{LONG_FORMAT, SHORT_FORMAT}) {
-            for(final Locale locale : Locale.getAvailableLocales()) {
-                for(final TimeZone tz :  new TimeZone[]{NEW_YORK, REYKJAVIK, 
GMT}) {
-                     for(final int year : new int[]{2003, 1940, 1868, 1867, 1, 
-1, -1940}) {
-                        final Calendar cal= getEraStart(year, tz, locale);
-                        final Date centuryStart= cal.getTime();
-
-                        cal.set(Calendar.MONTH, 1);
-                        cal.set(Calendar.DAY_OF_MONTH, 10);
-                        final Date in= cal.getTime();
-
-                        final FastDateParser fdp= new FastDateParser(format, 
tz, locale, centuryStart);
-                        validateSdfFormatFdpParseEquality(format, locale, tz, 
fdp, in, year, centuryStart);
-                    }
-                }
-            }
-        }
-    }
-
-    @Test
-    public void testParseZone() throws ParseException {
-        final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
-        cal.clear();
-        cal.set(2003, Calendar.JULY, 10, 16, 33, 20);
-
-        final DateParser fdf = getInstance(yMdHmsSZ, NEW_YORK, Locale.US);
-
-        assertEquals(cal.getTime(), fdf.parse("2003-07-10T15:33:20.000 
-0500"));
-        assertEquals(cal.getTime(), fdf.parse("2003-07-10T15:33:20.000 
GMT-05:00"));
-        assertEquals(cal.getTime(), fdf.parse("2003-07-10T16:33:20.000 Eastern 
Daylight Time"));
-        assertEquals(cal.getTime(), fdf.parse("2003-07-10T16:33:20.000 EDT"));
-
-        cal.setTimeZone(TimeZone.getTimeZone("GMT-3"));
-        cal.set(2003, Calendar.FEBRUARY, 10, 9, 0, 0);
-
-        assertEquals(cal.getTime(), fdf.parse("2003-02-10T09:00:00.000 
-0300"));
-
-        cal.setTimeZone(TimeZone.getTimeZone("GMT+5"));
-        cal.set(2003, Calendar.FEBRUARY, 10, 15, 5, 6);
-
-        assertEquals(cal.getTime(), fdf.parse("2003-02-10T15:05:06.000 
+0500"));
-    }
-
-    @Test
-    public void testPatternMatches() {
-        final DateParser parser= getInstance(yMdHmsSZ);
-        assertEquals(yMdHmsSZ, parser.getPattern());
-    }
-
-    @Test
-    public void testQuotes() throws ParseException {
-        final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
-        cal.clear();
-        cal.set(2003, Calendar.FEBRUARY, 10, 15, 33, 20);
-        cal.set(Calendar.MILLISECOND, 989);
-
-        final DateParser fdf = getInstance("''yyyyMMdd'A''B'HHmmssSSS''", 
NEW_YORK, Locale.US);
-        assertEquals(cal.getTime(), fdf.parse("'20030210A'B153320989'"));
-    }
-
-    private void testSdfAndFdp(final String format, final String date, final 
boolean shouldFail)
-            throws Exception {
-        Date dfdp = null;
-        Date dsdf = null;
-        Throwable f = null;
-        Throwable s = null;
-
-        try {
-            final SimpleDateFormat sdf = new SimpleDateFormat(format, 
Locale.US);
-            sdf.setTimeZone(NEW_YORK);
-            dsdf = sdf.parse(date);
-            if (shouldFail) {
-                fail("Expected SDF failure, but got " + dsdf + " for [" + 
format + "," + date + "]");
-            }
-        } catch (final Exception e) {
-            s = e;
-            if (!shouldFail) {
-                throw e;
-            }
-        }
-
-        try {
-            final DateParser fdp = getInstance(format, NEW_YORK, Locale.US);
-            dfdp = fdp.parse(date);
-            if (shouldFail) {
-                fail("Expected FDF failure, but got " + dfdp + " for [" + 
format + "," + date + "]");
-            }
-        } catch (final Exception e) {
-            f = e;
-            if (!shouldFail) {
-                throw e;
-            }
-        }
-        // SDF and FDF should produce equivalent results
-        assertTrue((f == null) == (s == null), "Should both or neither throw 
Exceptions");
-        assertEquals(dsdf, dfdp, "Parsed dates should be equal");
-    }
-
-    /**
-     * Test case for {@link FastDateParser#FastDateParser(String, TimeZone, 
Locale)}.
-     * @throws ParseException so we don't have to catch it
-     */
-    @Test
-    public void testShortDateStyleWithLocales() throws ParseException {
-        DateParser fdf = getDateInstance(FastDateFormat.SHORT, Locale.US);
-        final Calendar cal = Calendar.getInstance();
-        cal.clear();
-
-        cal.set(2004, Calendar.FEBRUARY, 3);
-        assertEquals(cal.getTime(), fdf.parse("2/3/04"));
-
-        fdf = getDateInstance(FastDateFormat.SHORT, SWEDEN);
-        assertEquals(cal.getTime(), fdf.parse("2004-02-03"));
-    }
-
-    @Test
-    public void testSpecialCharacters() throws Exception {
-        testSdfAndFdp("q" ,"", true); // bad pattern character (at present)
-        testSdfAndFdp("Q" ,"", true); // bad pattern character
-        testSdfAndFdp("$" ,"$", false); // OK
-        testSdfAndFdp("?.d" ,"?.12", false); // OK
-        testSdfAndFdp("''yyyyMMdd'A''B'HHmmssSSS''", "'20030210A'B153320989'", 
false); // OK
-        testSdfAndFdp("''''yyyyMMdd'A''B'HHmmssSSS''", 
"''20030210A'B153320989'", false); // OK
-        testSdfAndFdp("'$\\Ed'" ,"$\\Ed", false); // OK
-
-        // quoted charaters are case sensitive
-        testSdfAndFdp("'QED'", "QED", false);
-        testSdfAndFdp("'QED'", "qed", true);
-        // case sensitive after insensitive Month field
-        testSdfAndFdp("yyyy-MM-dd 'QED'", "2003-02-10 QED", false);
-        testSdfAndFdp("yyyy-MM-dd 'QED'", "2003-02-10 qed", true);
-    }
-
-    @Test
-    public void testTimeZoneMatches() {
-        final DateParser parser= getInstance(yMdHmsSZ, REYKJAVIK);
-        assertEquals(REYKJAVIK, parser.getTimeZone());
-    }
-
-    @Test
-    public void testToStringContainsName() {
-        final DateParser parser= getInstance(YMD_SLASH);
-        assertTrue(parser.toString().startsWith("FastDate"));
-    }
-
-    // we cannot use historic dates to test timezone parsing, some timezones 
have second offsets
-    // as well as hours and minutes which makes the z formats a low fidelity 
round trip
-    @Test
-    public void testTzParses() throws Exception {
-        // Check that all Locales can parse the time formats we use
-        for(final Locale locale : Locale.getAvailableLocales()) {
-            final FastDateParser fdp= new FastDateParser("yyyy/MM/dd z", 
TimeZone.getDefault(), locale);
-
-            for(final TimeZone tz :  new TimeZone[]{NEW_YORK, REYKJAVIK, GMT}) 
{
-                final Calendar cal= Calendar.getInstance(tz, locale);
-                cal.clear();
-                cal.set(Calendar.YEAR, 2000);
-                cal.set(Calendar.MONTH, 1);
-                cal.set(Calendar.DAY_OF_MONTH, 10);
-                final Date expected= cal.getTime();
-
-                final Date actual = fdp.parse("2000/02/10 
"+tz.getDisplayName(locale));
-                assertEquals(expected, actual, "tz:" + tz.getID() + " locale:" 
+ locale.getDisplayName());
-            }
-        }
-    }
-
-    private String trimMessage(final String msg) {
-        if (msg.length() < 100) {
-            return msg;
-        }
-        final int gmt = msg.indexOf("(GMT");
-        if (gmt > 0) {
-            return msg.substring(0, gmt+4)+"...)";
-        }
-        return msg.substring(0, 100)+"...";
-    }
-
-    private void validateSdfFormatFdpParseEquality(final String format, final 
Locale locale, final TimeZone tz, final DateParser fdp, final Date in, final 
int year, final Date cs) throws ParseException {
-        final SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
-        sdf.setTimeZone(tz);
-        if (format.equals(SHORT_FORMAT)) {
-            sdf.set2DigitYearStart( cs );
-        }
-        final String fmt = sdf.format(in);
-        try {
-            final Date out = fdp.parse(fmt);
-            assertEquals(in, out, locale.toString() + " " + in + " " + format 
+ " " + tz.getID());
-        } catch (final ParseException pe) {
-            if (year >= 1868 || !locale.getCountry().equals("JP")) {// LANG-978
-                throw pe;
-            }
-        }
-    }
-}
diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml
index 7202eef410..2f8f8c3689 100644
--- a/log4j-core/pom.xml
+++ b/log4j-core/pom.xml
@@ -296,6 +296,21 @@
         </executions>
       </plugin>
 
+      <!-- Remove this override after `2.22.0` release!
+           In `2.22.0`, we have removed *unused* `FastDateParser` due to 
LOG4J2-3672 and #1848.
+           Though `bnd-baseline-m-p` doesn't allow such breaking changes in 
non-major version upgrades.
+           Hence, we suppress it until `2.22.0` gets released. -->
+      <plugin>
+        <groupId>biz.aQute.bnd</groupId>
+        <artifactId>bnd-baseline-maven-plugin</artifactId>
+        <configuration>
+          <diffpackages>
+            
<diffpackage>!org.apache.logging.log4j.core.util.datetime</diffpackage>
+            <diffpackage>*</diffpackage>
+          </diffpackages>
+        </configuration>
+      </plugin>
+
     </plugins>
   </build>
 </project>
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/DateParser.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/DateParser.java
deleted file mode 100644
index 5d42fafdc2..0000000000
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/DateParser.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core.util.datetime;
-
-import java.text.ParseException;
-import java.text.ParsePosition;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
-
-/**
- * DateParser is the "missing" interface for the parsing methods of
- * {@link java.text.DateFormat}. You can obtain an object implementing this
- * interface by using one of the FastDateFormat factory methods.
- * <p>
- * Warning: Since binary compatible methods may be added to this interface in 
any
- * release, developers are not expected to implement this interface.
- *
- * <p>
- * Copied and modified from <a 
href="https://commons.apache.org/proper/commons-lang/";>Apache Commons Lang</a>.
- * </p>
- *
- * @since Apache Commons Lang 3.2
- */
-public interface DateParser {
-
-    /**
-     * Equivalent to DateFormat.parse(String).
-     *
-     * See {@link java.text.DateFormat#parse(String)} for more information.
-     * @param source A <code>String</code> whose beginning should be parsed.
-     * @return A <code>Date</code> parsed from the string
-     * @throws ParseException if the beginning of the specified string cannot 
be parsed.
-     */
-    Date parse(String source) throws ParseException;
-
-    /**
-     * Equivalent to DateFormat.parse(String, ParsePosition).
-     *
-     * See {@link java.text.DateFormat#parse(String, ParsePosition)} for more 
information.
-     *
-     * @param source A <code>String</code>, part of which should be parsed.
-     * @param pos A <code>ParsePosition</code> object with index and error 
index information
-     * as described above.
-     * @return A <code>Date</code> parsed from the string. In case of error, 
returns null.
-     * @throws NullPointerException if text or pos is null.
-     */
-    Date parse(String source, ParsePosition pos);
-
-    /**
-     * Parses a formatted date string according to the format.  Updates the 
Calendar with parsed fields.
-     * Upon success, the ParsePosition index is updated to indicate how much 
of the source text was consumed.
-     * Not all source text needs to be consumed.  Upon parse failure, 
ParsePosition error index is updated to
-     * the offset of the source text which does not match the supplied format.
-     *
-     * @param source The text to parse.
-     * @param pos On input, the position in the source to start parsing, on 
output, updated position.
-     * @param calendar The calendar into which to set parsed fields.
-     * @return true, if source has been parsed (pos parsePosition is updated); 
otherwise false (and pos errorIndex is updated)
-     * @throws IllegalArgumentException when Calendar has been set to be not 
lenient, and a parsed field is
-     * out of range.
-     *
-     * @since 3.5
-     */
-    boolean parse(String source, ParsePosition pos, Calendar calendar);
-
-    // Accessors
-    //-----------------------------------------------------------------------
-    /**
-     * <p>Gets the pattern used by this parser.</p>
-     *
-     * @return the pattern, {@link java.text.SimpleDateFormat} compatible
-     */
-    String getPattern();
-
-    /**
-     * <p>
-     * Gets the time zone used by this parser.
-     * </p>
-     *
-     * <p>
-     * The default {@link TimeZone} used to create a {@link Date} when the 
{@link TimeZone} is not specified by
-     * the format pattern.
-     * </p>
-     *
-     * @return the time zone
-     */
-    TimeZone getTimeZone();
-
-    /**
-     * <p>Gets the locale used by this parser.</p>
-     *
-     * @return the locale
-     */
-    Locale getLocale();
-
-    /**
-     * Parses text from a string to produce a Date.
-     *
-     * @param source A <code>String</code> whose beginning should be parsed.
-     * @return a <code>java.util.Date</code> object
-     * @throws ParseException if the beginning of the specified string cannot 
be parsed.
-     * @see java.text.DateFormat#parseObject(String)
-     */
-    Object parseObject(String source) throws ParseException;
-
-    /**
-     * Parses a date/time string according to the given parse position.
-     *
-     * @param source A <code>String</code> whose beginning should be parsed.
-     * @param pos the parse position
-     * @return a <code>java.util.Date</code> object
-     * @see java.text.DateFormat#parseObject(String, ParsePosition)
-     */
-    Object parseObject(String source, ParsePosition pos);
-}
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateFormat.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateFormat.java
index 9381b4d171..914a6dfff6 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateFormat.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateFormat.java
@@ -18,8 +18,6 @@ package org.apache.logging.log4j.core.util.datetime;
 
 import java.text.DateFormat;
 import java.text.FieldPosition;
-import java.text.ParseException;
-import java.text.ParsePosition;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
@@ -72,15 +70,7 @@ import java.util.TimeZone;
  *
  * @since Apache Commons Lang 2.0
  */
-public class FastDateFormat extends Format implements DateParser, DatePrinter {
-
-    /**
-     * Required for serialization support.
-     *
-     * @see java.io.Serializable
-     */
-    @SuppressWarnings("unused")
-    private static final long serialVersionUID = 2L;
+public class FastDateFormat extends Format implements DatePrinter {
 
     /**
      * FULL locale dependent date or time style.
@@ -110,7 +100,6 @@ public class FastDateFormat extends Format implements 
DateParser, DatePrinter {
     };
 
     private final FastDatePrinter printer;
-    private final FastDateParser parser;
 
     //-----------------------------------------------------------------------
     /**
@@ -399,7 +388,6 @@ public class FastDateFormat extends Format implements 
DateParser, DatePrinter {
      */
     protected FastDateFormat(final String pattern, final TimeZone timeZone, 
final Locale locale, final Date centuryStart) {
         printer= new FastDatePrinter(pattern, timeZone, locale);
-        parser= new FastDateParser(pattern, timeZone, locale, centuryStart);
     }
 
     // Format methods
@@ -495,43 +483,6 @@ public class FastDateFormat extends Format implements 
DateParser, DatePrinter {
         return printer.format(calendar, buf);
     }
 
-    // Parsing
-    //-----------------------------------------------------------------------
-
-
-    /* (non-Javadoc)
-     * @see DateParser#parse(java.lang.String)
-     */
-    @Override
-    public Date parse(final String source) throws ParseException {
-        return parser.parse(source);
-    }
-
-    /* (non-Javadoc)
-     * @see DateParser#parse(java.lang.String, java.text.ParsePosition)
-     */
-    @Override
-    public Date parse(final String source, final ParsePosition pos) {
-        return parser.parse(source, pos);
-    }
-
-    /*
-     * (non-Javadoc)
-     * @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String, 
java.text.ParsePosition, java.util.Calendar)
-     */
-    @Override
-    public boolean parse(final String source, final ParsePosition pos, final 
Calendar calendar) {
-        return parser.parse(source, pos, calendar);
-    }
-
-    /* (non-Javadoc)
-     * @see java.text.Format#parseObject(java.lang.String, 
java.text.ParsePosition)
-     */
-    @Override
-    public Object parseObject(final String source, final ParsePosition pos) {
-        return parser.parseObject(source, pos);
-    }
-
     // Accessors
     //-----------------------------------------------------------------------
     /**
@@ -589,7 +540,7 @@ public class FastDateFormat extends Format implements 
DateParser, DatePrinter {
      */
     @Override
     public boolean equals(final Object obj) {
-        if (obj instanceof FastDateFormat == false) {
+        if (!(obj instanceof FastDateFormat)) {
             return false;
         }
         final FastDateFormat other = (FastDateFormat) obj;
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateParser.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateParser.java
deleted file mode 100644
index 0b7f4b4cdc..0000000000
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/FastDateParser.java
+++ /dev/null
@@ -1,992 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core.util.datetime;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.Serializable;
-import java.text.DateFormatSymbols;
-import java.text.ParseException;
-import java.text.ParsePosition;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TimeZone;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.logging.log4j.core.util.Integers;
-
-import static org.apache.logging.log4j.util.Strings.toRootUpperCase;
-
-/**
- * <p>FastDateParser is a fast and thread-safe version of
- * {@link java.text.SimpleDateFormat}.</p>
- *
- * <p>To obtain a proxy to a FastDateParser, use {@link 
FastDateFormat#getInstance(String, TimeZone, Locale)}
- * or another variation of the factory methods of {@link FastDateFormat}.</p>
- *
- * <p>Since FastDateParser is thread safe, you can use a static member 
instance:</p>
- * <code>
- *     private static final DateParser DATE_PARSER = 
FastDateFormat.getInstance("yyyy-MM-dd");
- * </code>
- *
- * <p>This class can be used as a direct replacement for
- * <code>SimpleDateFormat</code> in most parsing situations.
- * This class is especially useful in multi-threaded server environments.
- * <code>SimpleDateFormat</code> is not thread-safe in any JDK version,
- * nor will it be as Sun has closed the
- * <a href="https://bugs.openjdk.org/browse/JDK-4228335";>bug</a>/RFE.
- * </p>
- *
- * <p>Only parsing is supported by this class, but all patterns are compatible 
with
- * SimpleDateFormat.</p>
- *
- * <p>The class operates in lenient mode, so for example a time of 90 minutes 
is treated as 1 hour 30 minutes.</p>
- *
- * <p>Timing tests indicate this class is as about as fast as SimpleDateFormat
- * in single thread applications and about 25% faster in multi-thread 
applications.</p>
- *
- * <p>
- * Copied and modified from <a 
href="https://commons.apache.org/proper/commons-lang/";>Apache Commons Lang</a>.
- * </p>
- *
- * @since Apache Commons Lang 3.2
- * @see FastDatePrinter
- */
-public class FastDateParser implements DateParser, Serializable {
-
-    /**
-     * Required for serialization support.
-     *
-     * @see java.io.Serializable
-     */
-    private static final long serialVersionUID = 3L;
-
-    static final Locale JAPANESE_IMPERIAL = new Locale("ja","JP","JP");
-
-    // defining fields
-    private final String pattern;
-    private final TimeZone timeZone;
-    private final Locale locale;
-    private final int century;
-    private final int startYear;
-
-    // derived fields
-    private transient List<StrategyAndWidth> patterns;
-
-    // comparator used to sort regex alternatives
-    // alternatives should be ordered longer first, and shorter last. 
('february' before 'feb')
-    // all entries must be lowercase by locale.
-    private static final Comparator<String> LONGER_FIRST_LOWERCASE = (left, 
right) -> right.compareTo(left);
-
-    /**
-     * <p>Constructs a new FastDateParser.</p>
-     *
-     * Use {@link FastDateFormat#getInstance(String, TimeZone, Locale)} or 
another variation of the
-     * factory methods of {@link FastDateFormat} to get a cached 
FastDateParser instance.
-     *
-     * @param pattern non-null {@link java.text.SimpleDateFormat} compatible
-     *  pattern
-     * @param timeZone non-null time zone to use
-     * @param locale non-null locale
-     */
-    protected FastDateParser(final String pattern, final TimeZone timeZone, 
final Locale locale) {
-        this(pattern, timeZone, locale, null);
-    }
-
-    /**
-     * <p>Constructs a new FastDateParser.</p>
-     *
-     * @param pattern non-null {@link java.text.SimpleDateFormat} compatible
-     *  pattern
-     * @param timeZone non-null time zone to use
-     * @param locale non-null locale
-     * @param centuryStart The start of the century for 2 digit year parsing
-     *
-     * @since 3.5
-     */
-    protected FastDateParser(final String pattern, final TimeZone timeZone, 
final Locale locale, final Date centuryStart) {
-        this.pattern = pattern;
-        this.timeZone = timeZone;
-        this.locale = locale;
-
-        final Calendar definingCalendar = Calendar.getInstance(timeZone, 
locale);
-
-        int centuryStartYear;
-        if(centuryStart!=null) {
-            definingCalendar.setTime(centuryStart);
-            centuryStartYear= definingCalendar.get(Calendar.YEAR);
-        }
-        else if(locale.equals(JAPANESE_IMPERIAL)) {
-            centuryStartYear= 0;
-        }
-        else {
-            // from 80 years ago to 20 years from now
-            definingCalendar.setTime(new Date());
-            centuryStartYear= definingCalendar.get(Calendar.YEAR)-80;
-        }
-        century= centuryStartYear / 100 * 100;
-        startYear= centuryStartYear - century;
-
-        init(definingCalendar);
-    }
-
-    /**
-     * Initialize derived fields from defining fields.
-     * This is called from constructor and from readObject (de-serialization)
-     *
-     * @param definingCalendar the {@link java.util.Calendar} instance used to 
initialize this FastDateParser
-     */
-    private void init(final Calendar definingCalendar) {
-        patterns = new ArrayList<>();
-
-        final StrategyParser fm = new StrategyParser(definingCalendar);
-        for(;;) {
-            final StrategyAndWidth field = fm.getNextStrategy();
-            if(field==null) {
-                break;
-            }
-            patterns.add(field);
-        }
-    }
-
-    // helper classes to parse the format string
-    //-----------------------------------------------------------------------
-
-    /**
-     * Holds strategy and field width
-     */
-    private static class StrategyAndWidth {
-        final Strategy strategy;
-        final int width;
-
-        StrategyAndWidth(final Strategy strategy, final int width) {
-            this.strategy = strategy;
-            this.width = width;
-        }
-
-        int getMaxWidth(final ListIterator<StrategyAndWidth> lt) {
-            if(!strategy.isNumber() || !lt.hasNext()) {
-                return 0;
-            }
-            final Strategy nextStrategy = lt.next().strategy;
-            lt.previous();
-            return nextStrategy.isNumber() ?width :0;
-       }
-    }
-
-    /**
-     * Parse format into Strategies
-     */
-    private class StrategyParser {
-        final private Calendar definingCalendar;
-        private int currentIdx;
-
-        StrategyParser(final Calendar definingCalendar) {
-            this.definingCalendar = definingCalendar;
-        }
-
-        StrategyAndWidth getNextStrategy() {
-            if (currentIdx >= pattern.length()) {
-                return null;
-            }
-
-            final char c = pattern.charAt(currentIdx);
-            if (isFormatLetter(c)) {
-                return letterPattern(c);
-            }
-            return literal();
-        }
-
-        private StrategyAndWidth letterPattern(final char c) {
-            final int begin = currentIdx;
-            while (++currentIdx < pattern.length()) {
-                if (pattern.charAt(currentIdx) != c) {
-                    break;
-                }
-            }
-
-            final int width = currentIdx - begin;
-            return new StrategyAndWidth(getStrategy(c, width, 
definingCalendar), width);
-        }
-
-        private StrategyAndWidth literal() {
-            boolean activeQuote = false;
-
-            final StringBuilder sb = new StringBuilder();
-            while (currentIdx < pattern.length()) {
-                final char c = pattern.charAt(currentIdx);
-                if (!activeQuote && isFormatLetter(c)) {
-                    break;
-                } else if (c == '\'' && (++currentIdx == pattern.length() || 
pattern.charAt(currentIdx) != '\'')) {
-                    activeQuote = !activeQuote;
-                    continue;
-                }
-                ++currentIdx;
-                sb.append(c);
-            }
-
-            if (activeQuote) {
-                throw new IllegalArgumentException("Unterminated quote");
-            }
-
-            final String formatField = sb.toString();
-            return new StrategyAndWidth(new CopyQuotedStrategy(formatField), 
formatField.length());
-        }
-    }
-
-    private static boolean isFormatLetter(final char c) {
-        return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';
-    }
-
-    // Accessors
-    //-----------------------------------------------------------------------
-    /* (non-Javadoc)
-     * @see org.apache.commons.lang3.time.DateParser#getPattern()
-     */
-    @Override
-    public String getPattern() {
-        return pattern;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.commons.lang3.time.DateParser#getTimeZone()
-     */
-    @Override
-    public TimeZone getTimeZone() {
-        return timeZone;
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.commons.lang3.time.DateParser#getLocale()
-     */
-    @Override
-    public Locale getLocale() {
-        return locale;
-    }
-
-
-    // Basics
-    //-----------------------------------------------------------------------
-    /**
-     * <p>Compare another object for equality with this object.</p>
-     *
-     * @param obj  the object to compare to
-     * @return <code>true</code>if equal to this instance
-     */
-    @Override
-    public boolean equals(final Object obj) {
-        if (!(obj instanceof FastDateParser)) {
-            return false;
-        }
-        final FastDateParser other = (FastDateParser) obj;
-        return pattern.equals(other.pattern)
-            && timeZone.equals(other.timeZone)
-            && locale.equals(other.locale);
-    }
-
-    /**
-     * <p>Return a hash code compatible with equals.</p>
-     *
-     * @return a hash code compatible with equals
-     */
-    @Override
-    public int hashCode() {
-        return pattern.hashCode() + 13 * (timeZone.hashCode() + 13 * 
locale.hashCode());
-    }
-
-    /**
-     * <p>Get a string version of this formatter.</p>
-     *
-     * @return a debugging string
-     */
-    @Override
-    public String toString() {
-        return "FastDateParser[" + pattern + "," + locale + "," + 
timeZone.getID() + "]";
-    }
-
-    // Serializing
-    //-----------------------------------------------------------------------
-    /**
-     * Create the object after serialization. This implementation 
reinitializes the
-     * transient properties.
-     *
-     * @param in ObjectInputStream from which the object is being deserialized.
-     * @throws IOException if there is an IO issue.
-     * @throws ClassNotFoundException if a class cannot be found.
-     */
-    private void readObject(final ObjectInputStream in) throws IOException, 
ClassNotFoundException {
-        in.defaultReadObject();
-
-        final Calendar definingCalendar = Calendar.getInstance(timeZone, 
locale);
-        init(definingCalendar);
-    }
-
-    /* (non-Javadoc)
-     * @see 
org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String)
-     */
-    @Override
-    public Object parseObject(final String source) throws ParseException {
-        return parse(source);
-    }
-
-    /* (non-Javadoc)
-     * @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String)
-     */
-    @Override
-    public Date parse(final String source) throws ParseException {
-        final ParsePosition pp = new ParsePosition(0);
-        final Date date= parse(source, pp);
-        if (date == null) {
-            // Add a note re supported date range
-            if (locale.equals(JAPANESE_IMPERIAL)) {
-                throw new ParseException(
-                        "(The " +locale + " locale does not support dates 
before 1868 AD)\n" +
-                                "Unparseable date: \""+source, 
pp.getErrorIndex());
-            }
-            throw new ParseException("Unparseable date: "+source, 
pp.getErrorIndex());
-        }
-        return date;
-    }
-
-    /* (non-Javadoc)
-     * @see 
org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String, 
java.text.ParsePosition)
-     */
-    @Override
-    public Object parseObject(final String source, final ParsePosition pos) {
-        return parse(source, pos);
-    }
-
-    /**
-     * This implementation updates the ParsePosition if the parse succeeds.
-     * However, it sets the error index to the position before the failed 
field unlike
-     * the method {@link java.text.SimpleDateFormat#parse(String, 
ParsePosition)} which sets
-     * the error index to after the failed field.
-     * <p>
-     * To determine if the parse has succeeded, the caller must check if the 
current parse position
-     * given by {@link ParsePosition#getIndex()} has been updated. If the 
input buffer has been fully
-     * parsed, then the index will point to just after the end of the input 
buffer.
-     *
-     * @see <a 
href="https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/time/DateParser.html#parse-java.lang.String-java.text.ParsePosition-";>
-     *     org.apache.commons.lang3.time.DateParser#parse(String, 
ParsePosition)</a>
-     */
-    @Override
-    public Date parse(final String source, final ParsePosition pos) {
-        // timing tests indicate getting new instance is 19% faster than 
cloning
-        final Calendar cal= Calendar.getInstance(timeZone, locale);
-        cal.clear();
-
-        return parse(source, pos, cal) ? cal.getTime() : null;
-    }
-
-    /**
-     * Parse a formatted date string according to the format.  Updates the 
Calendar with parsed fields.
-     * Upon success, the ParsePosition index is updated to indicate how much 
of the source text was consumed.
-     * Not all source text needs to be consumed.  Upon parse failure, 
ParsePosition error index is updated to
-     * the offset of the source text which does not match the supplied format.
-     *
-     * @param source The text to parse.
-     * @param pos On input, the position in the source to start parsing, on 
output, updated position.
-     * @param calendar The calendar into which to set parsed fields.
-     * @return true, if source has been parsed (pos parsePosition is updated); 
otherwise false (and pos errorIndex is updated)
-     * @throws IllegalArgumentException when Calendar has been set to be not 
lenient, and a parsed field is
-     * out of range.
-     */
-    @Override
-    public boolean parse(final String source, final ParsePosition pos, final 
Calendar calendar) {
-        final ListIterator<StrategyAndWidth> lt = patterns.listIterator();
-        while (lt.hasNext()) {
-            final StrategyAndWidth strategyAndWidth = lt.next();
-            final int maxWidth = strategyAndWidth.getMaxWidth(lt);
-            if (!strategyAndWidth.strategy.parse(this, calendar, source, pos, 
maxWidth)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    // Support for strategies
-    //-----------------------------------------------------------------------
-
-    private static StringBuilder simpleQuote(final StringBuilder sb, final 
String value) {
-        for (int i = 0; i < value.length(); ++i) {
-            final char c = value.charAt(i);
-            switch (c) {
-            case '\\':
-            case '^':
-            case '$':
-            case '.':
-            case '|':
-            case '?':
-            case '*':
-            case '+':
-            case '(':
-            case ')':
-            case '[':
-            case '{':
-                sb.append('\\');
-            default:
-                sb.append(c);
-            }
-        }
-        return sb;
-    }
-
-    /**
-     * Get the short and long values displayed for a field
-     * @param cal The calendar to obtain the short and long values
-     * @param locale The locale of display names
-     * @param field The field of interest
-     * @param regex The regular expression to build
-     * @return The map of string display names to field values
-     */
-    private static Map<String, Integer> appendDisplayNames(final Calendar cal, 
final Locale locale, final int field, final StringBuilder regex) {
-        final Map<String, Integer> values = new HashMap<>();
-
-        final Map<String, Integer> displayNames = cal.getDisplayNames(field, 
Calendar.ALL_STYLES, locale);
-        final TreeSet<String> sorted = new TreeSet<>(LONGER_FIRST_LOWERCASE);
-        for (final Map.Entry<String, Integer> displayName : 
displayNames.entrySet()) {
-            final String key = displayName.getKey().toLowerCase(locale);
-            if (sorted.add(key)) {
-                values.put(key, displayName.getValue());
-            }
-        }
-        for (final String symbol : sorted) {
-            simpleQuote(regex, symbol).append('|');
-        }
-        return values;
-    }
-
-    /**
-     * Adjust dates to be within appropriate century
-     * @param twoDigitYear The year to adjust
-     * @return A value between centuryStart(inclusive) to 
centuryStart+100(exclusive)
-     */
-    private int adjustYear(final int twoDigitYear) {
-        final int trial = century + twoDigitYear;
-        return twoDigitYear >= startYear ? trial : trial + 100;
-    }
-
-    /**
-     * A strategy to parse a single field from the parsing pattern
-     */
-    private static abstract class Strategy {
-        /**
-         * Is this field a number?
-         * The default implementation returns false.
-         *
-         * @return true, if field is a number
-         */
-        boolean isNumber() {
-            return false;
-        }
-
-        abstract boolean parse(FastDateParser parser, Calendar calendar, 
String source, ParsePosition pos, int maxWidth);
-    }
-
-    /**
-     * A strategy to parse a single field from the parsing pattern
-     */
-    private static abstract class PatternStrategy extends Strategy {
-
-        private Pattern pattern;
-
-        void createPattern(final StringBuilder regex) {
-            createPattern(regex.toString());
-        }
-
-        void createPattern(final String regex) {
-            this.pattern = Pattern.compile(regex);
-        }
-
-        /**
-         * Is this field a number?
-         * The default implementation returns false.
-         *
-         * @return true, if field is a number
-         */
-        @Override
-        boolean isNumber() {
-            return false;
-        }
-
-        @Override
-        boolean parse(final FastDateParser parser, final Calendar calendar, 
final String source, final ParsePosition pos, final int maxWidth) {
-            final Matcher matcher = 
pattern.matcher(source.substring(pos.getIndex()));
-            if (!matcher.lookingAt()) {
-                pos.setErrorIndex(pos.getIndex());
-                return false;
-            }
-            pos.setIndex(pos.getIndex() + matcher.end(1));
-            setCalendar(parser, calendar, matcher.group(1));
-            return true;
-        }
-
-        abstract void setCalendar(FastDateParser parser, Calendar cal, String 
value);
-    }
-
-    /**
-     * Obtain a Strategy given a field from a SimpleDateFormat pattern
-     * @param formatField A sub-sequence of the SimpleDateFormat pattern
-     * @param definingCalendar The calendar to obtain the short and long values
-     * @return The Strategy that will handle parsing for the field
-     */
-    private Strategy getStrategy(final char f, final int width, final Calendar 
definingCalendar) {
-        switch(f) {
-        default:
-            throw new IllegalArgumentException("Format '"+f+"' not supported");
-        case 'D':
-            return DAY_OF_YEAR_STRATEGY;
-        case 'E':
-            return getLocaleSpecificStrategy(Calendar.DAY_OF_WEEK, 
definingCalendar);
-        case 'F':
-            return DAY_OF_WEEK_IN_MONTH_STRATEGY;
-        case 'G':
-            return getLocaleSpecificStrategy(Calendar.ERA, definingCalendar);
-        case 'H':  // Hour in day (0-23)
-            return HOUR_OF_DAY_STRATEGY;
-        case 'K':  // Hour in am/pm (0-11)
-            return HOUR_STRATEGY;
-        case 'M':
-            return width >= 3 ? getLocaleSpecificStrategy(Calendar.MONTH, 
definingCalendar) : NUMBER_MONTH_STRATEGY;
-        case 'S':
-            return MILLISECOND_STRATEGY;
-        case 'W':
-            return WEEK_OF_MONTH_STRATEGY;
-        case 'a':
-            return getLocaleSpecificStrategy(Calendar.AM_PM, definingCalendar);
-        case 'd':
-            return DAY_OF_MONTH_STRATEGY;
-        case 'h':  // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0
-            return HOUR12_STRATEGY;
-        case 'k':  // Hour in day (1-24), i.e. midnight is 24, not 0
-            return HOUR24_OF_DAY_STRATEGY;
-        case 'm':
-            return MINUTE_STRATEGY;
-        case 's':
-            return SECOND_STRATEGY;
-        case 'u':
-            return DAY_OF_WEEK_STRATEGY;
-        case 'w':
-            return WEEK_OF_YEAR_STRATEGY;
-        case 'y':
-        case 'Y':
-            return width > 2 ? LITERAL_YEAR_STRATEGY : 
ABBREVIATED_YEAR_STRATEGY;
-        case 'X':
-            return ISO8601TimeZoneStrategy.getStrategy(width);
-        case 'Z':
-            if (width==2) {
-                return ISO8601TimeZoneStrategy.ISO_8601_3_STRATEGY;
-            }
-            //$FALL-THROUGH$
-        case 'z':
-            return getLocaleSpecificStrategy(Calendar.ZONE_OFFSET, 
definingCalendar);
-        }
-    }
-
-    @SuppressWarnings("unchecked") // OK because we are creating an array with 
no entries
-    private static final ConcurrentMap<Locale, Strategy>[] caches = new 
ConcurrentMap[Calendar.FIELD_COUNT];
-
-    /**
-     * Get a cache of Strategies for a particular field
-     * @param field The Calendar field
-     * @return a cache of Locale to Strategy
-     */
-    private static ConcurrentMap<Locale, Strategy> getCache(final int field) {
-        synchronized (caches) {
-            if (caches[field] == null) {
-                caches[field] = new ConcurrentHashMap<>(3);
-            }
-            return caches[field];
-        }
-    }
-
-    /**
-     * Construct a Strategy that parses a Text field
-     * @param field The Calendar field
-     * @param definingCalendar The calendar to obtain the short and long values
-     * @return a TextStrategy for the field and Locale
-     */
-    private Strategy getLocaleSpecificStrategy(final int field, final Calendar 
definingCalendar) {
-        final ConcurrentMap<Locale, Strategy> cache = getCache(field);
-        Strategy strategy = cache.get(locale);
-        if (strategy == null) {
-            strategy = field == Calendar.ZONE_OFFSET
-                    ? new TimeZoneStrategy(locale)
-                    : new CaseInsensitiveTextStrategy(field, definingCalendar, 
locale);
-            final Strategy inCache = cache.putIfAbsent(locale, strategy);
-            if (inCache != null) {
-                return inCache;
-            }
-        }
-        return strategy;
-    }
-
-    /**
-     * A strategy that copies the static or quoted field in the parsing pattern
-     */
-    private static class CopyQuotedStrategy extends Strategy {
-
-        final private String formatField;
-
-        /**
-         * Construct a Strategy that ensures the formatField has literal text
-         * @param formatField The literal text to match
-         */
-        CopyQuotedStrategy(final String formatField) {
-            this.formatField = formatField;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        boolean isNumber() {
-            return false;
-        }
-
-        @Override
-        boolean parse(final FastDateParser parser, final Calendar calendar, 
final String source, final ParsePosition pos, final int maxWidth) {
-            for (int idx = 0; idx < formatField.length(); ++idx) {
-                final int sIdx = idx + pos.getIndex();
-                if (sIdx == source.length()) {
-                    pos.setErrorIndex(sIdx);
-                    return false;
-                }
-                if (formatField.charAt(idx) != source.charAt(sIdx)) {
-                    pos.setErrorIndex(sIdx);
-                    return false;
-                }
-            }
-            pos.setIndex(formatField.length() + pos.getIndex());
-            return true;
-        }
-    }
-
-    /**
-     * A strategy that handles a text field in the parsing pattern
-     */
-     private static class CaseInsensitiveTextStrategy extends PatternStrategy {
-        private final int field;
-        final Locale locale;
-        private final Map<String, Integer> lKeyValues;
-
-        /**
-         * Construct a Strategy that parses a Text field
-         * @param field  The Calendar field
-         * @param definingCalendar  The Calendar to use
-         * @param locale  The Locale to use
-         */
-        CaseInsensitiveTextStrategy(final int field, final Calendar 
definingCalendar, final Locale locale) {
-            this.field = field;
-            this.locale = locale;
-
-            final StringBuilder regex = new StringBuilder();
-            regex.append("((?iu)");
-            lKeyValues = appendDisplayNames(definingCalendar, locale, field, 
regex);
-            regex.setLength(regex.length()-1);
-            regex.append(")");
-            createPattern(regex);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        void setCalendar(final FastDateParser parser, final Calendar cal, 
final String value) {
-            final Integer iVal = lKeyValues.get(value.toLowerCase(locale));
-            cal.set(field, iVal.intValue());
-        }
-    }
-
-
-    /**
-     * A strategy that handles a number field in the parsing pattern
-     */
-    private static class NumberStrategy extends Strategy {
-        private final int field;
-
-        /**
-         * Construct a Strategy that parses a Number field
-         * @param field The Calendar field
-         */
-        NumberStrategy(final int field) {
-             this.field= field;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        boolean isNumber() {
-            return true;
-        }
-
-        @Override
-        boolean parse(final FastDateParser parser, final Calendar calendar, 
final String source, final ParsePosition pos, final int maxWidth) {
-            int idx = pos.getIndex();
-            int last = source.length();
-
-            if (maxWidth == 0) {
-                // if no maxWidth, strip leading white space
-                for (; idx < last; ++idx) {
-                    final char c = source.charAt(idx);
-                    if (!Character.isWhitespace(c)) {
-                        break;
-                    }
-                }
-                pos.setIndex(idx);
-            } else {
-                final int end = idx + maxWidth;
-                if (last > end) {
-                    last = end;
-                }
-            }
-
-            for (; idx < last; ++idx) {
-                final char c = source.charAt(idx);
-                if (!Character.isDigit(c)) {
-                    break;
-                }
-            }
-
-            if (pos.getIndex() == idx) {
-                pos.setErrorIndex(idx);
-                return false;
-            }
-
-            final int value = 
Integers.parseInt(source.substring(pos.getIndex(), idx));
-            pos.setIndex(idx);
-
-            calendar.set(field, modify(parser, value));
-            return true;
-        }
-
-        /**
-         * Make any modifications to parsed integer
-         * @param parser The parser
-         * @param iValue The parsed integer
-         * @return The modified value
-         */
-        int modify(final FastDateParser parser, final int iValue) {
-            return iValue;
-        }
-
-    }
-
-    private static final Strategy ABBREVIATED_YEAR_STRATEGY = new 
NumberStrategy(Calendar.YEAR) {
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        int modify(final FastDateParser parser, final int iValue) {
-            return iValue < 100 ? parser.adjustYear(iValue) : iValue;
-        }
-    };
-
-    /**
-     * A strategy that handles a timezone field in the parsing pattern
-     */
-    static class TimeZoneStrategy extends PatternStrategy {
-        private static final String RFC_822_TIME_ZONE = "[+-]\\d{4}";
-        private static final String GMT_OPTION= "GMT[+-]\\d{1,2}:\\d{2}";
-
-        private final Locale locale;
-        private final Map<String, TzInfo> tzNames= new HashMap<>();
-
-        private static class TzInfo {
-            TimeZone zone;
-            int dstOffset;
-
-            TzInfo(final TimeZone tz, final boolean useDst) {
-                zone = tz;
-                dstOffset = useDst ?tz.getDSTSavings() :0;
-            }
-        }
-
-        /**
-         * Index of zone id
-         */
-        private static final int ID = 0;
-
-        /**
-         * Construct a Strategy that parses a TimeZone
-         * @param locale The Locale
-         */
-        TimeZoneStrategy(final Locale locale) {
-            this.locale = locale;
-
-            final StringBuilder sb = new StringBuilder();
-            sb.append("((?iu)" + RFC_822_TIME_ZONE + "|" + GMT_OPTION );
-
-            final Set<String> sorted = new TreeSet<>(LONGER_FIRST_LOWERCASE);
-
-            final String[][] zones = 
DateFormatSymbols.getInstance(locale).getZoneStrings();
-            for (final String[] zoneNames : zones) {
-                // offset 0 is the time zone ID and is not localized
-                final String tzId = zoneNames[ID];
-                if (tzId.equalsIgnoreCase("GMT")) {
-                    continue;
-                }
-                final TimeZone tz = TimeZone.getTimeZone(tzId);
-                // offset 1 is long standard name
-                // offset 2 is short standard name
-                final TzInfo standard = new TzInfo(tz, false);
-                TzInfo tzInfo = standard;
-                for (int i = 1; i < zoneNames.length; ++i) {
-                    switch (i) {
-                    case 3: // offset 3 is long daylight savings (or 
summertime) name
-                            // offset 4 is the short summertime name
-                        tzInfo = new TzInfo(tz, true);
-                        break;
-                    case 5: // offset 5 starts additional names, probably 
standard time
-                        tzInfo = standard;
-                        break;
-                    }
-                    if (zoneNames[i] != null) {
-                        final String key = zoneNames[i].toLowerCase(locale);
-                        // ignore the data associated with duplicates supplied 
in
-                        // the additional names
-                        if (sorted.add(key)) {
-                            tzNames.put(key, tzInfo);
-                        }
-                    }
-                }
-            }
-            // order the regex alternatives with longer strings first, greedy
-            // match will ensure longest string will be consumed
-            for (final String zoneName : sorted) {
-                simpleQuote(sb.append('|'), zoneName);
-            }
-            sb.append(")");
-            createPattern(sb);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        void setCalendar(final FastDateParser parser, final Calendar cal, 
final String value) {
-            if (value.charAt(0) == '+' || value.charAt(0) == '-') {
-                final TimeZone tz = TimeZone.getTimeZone("GMT" + value);
-                cal.setTimeZone(tz);
-            } else if (value.regionMatches(true, 0, "GMT", 0, 3)) {
-                final TimeZone tz = 
TimeZone.getTimeZone(toRootUpperCase(value));
-                cal.setTimeZone(tz);
-            } else {
-                final TzInfo tzInfo = tzNames.get(value.toLowerCase(locale));
-                cal.set(Calendar.DST_OFFSET, tzInfo.dstOffset);
-                cal.set(Calendar.ZONE_OFFSET, tzInfo.zone.getRawOffset());
-            }
-        }
-    }
-
-    private static class ISO8601TimeZoneStrategy extends PatternStrategy {
-        // Z, +hh, -hh, +hhmm, -hhmm, +hh:mm or -hh:mm
-
-        /**
-         * Construct a Strategy that parses a TimeZone
-         * @param pattern The Pattern
-         */
-        ISO8601TimeZoneStrategy(final String pattern) {
-            createPattern(pattern);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        void setCalendar(final FastDateParser parser, final Calendar cal, 
final String value) {
-            if (value.equals("Z")) {
-                cal.setTimeZone(TimeZone.getTimeZone("UTC"));
-            } else {
-                cal.setTimeZone(TimeZone.getTimeZone("GMT" + value));
-            }
-        }
-
-        private static final Strategy ISO_8601_1_STRATEGY = new 
ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}))");
-        private static final Strategy ISO_8601_2_STRATEGY = new 
ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}\\d{2}))");
-        private static final Strategy ISO_8601_3_STRATEGY = new 
ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::)\\d{2}))");
-
-        /**
-         * Factory method for ISO8601TimeZoneStrategies.
-         *
-         * @param tokenLen a token indicating the length of the TimeZone 
String to be formatted.
-         * @return a ISO8601TimeZoneStrategy that can format TimeZone String 
of length {@code tokenLen}. If no such
-         *          strategy exists, an IllegalArgumentException will be 
thrown.
-         */
-        static Strategy getStrategy(final int tokenLen) {
-            switch(tokenLen) {
-            case 1:
-                return ISO_8601_1_STRATEGY;
-            case 2:
-                return ISO_8601_2_STRATEGY;
-            case 3:
-                return ISO_8601_3_STRATEGY;
-            default:
-                throw new IllegalArgumentException("invalid number of X");
-            }
-        }
-    }
-
-    private static final Strategy NUMBER_MONTH_STRATEGY = new 
NumberStrategy(Calendar.MONTH) {
-        @Override
-        int modify(final FastDateParser parser, final int iValue) {
-            return iValue-1;
-        }
-    };
-    private static final Strategy LITERAL_YEAR_STRATEGY = new 
NumberStrategy(Calendar.YEAR);
-    private static final Strategy WEEK_OF_YEAR_STRATEGY = new 
NumberStrategy(Calendar.WEEK_OF_YEAR);
-    private static final Strategy WEEK_OF_MONTH_STRATEGY = new 
NumberStrategy(Calendar.WEEK_OF_MONTH);
-    private static final Strategy DAY_OF_YEAR_STRATEGY = new 
NumberStrategy(Calendar.DAY_OF_YEAR);
-    private static final Strategy DAY_OF_MONTH_STRATEGY = new 
NumberStrategy(Calendar.DAY_OF_MONTH);
-    private static final Strategy DAY_OF_WEEK_STRATEGY = new 
NumberStrategy(Calendar.DAY_OF_WEEK) {
-        @Override
-        int modify(final FastDateParser parser, final int iValue) {
-            return iValue != 7 ? iValue + 1 : Calendar.SUNDAY;
-        }
-    };
-    private static final Strategy DAY_OF_WEEK_IN_MONTH_STRATEGY = new 
NumberStrategy(Calendar.DAY_OF_WEEK_IN_MONTH);
-    private static final Strategy HOUR_OF_DAY_STRATEGY = new 
NumberStrategy(Calendar.HOUR_OF_DAY);
-    private static final Strategy HOUR24_OF_DAY_STRATEGY = new 
NumberStrategy(Calendar.HOUR_OF_DAY) {
-        @Override
-        int modify(final FastDateParser parser, final int iValue) {
-            return iValue == 24 ? 0 : iValue;
-        }
-    };
-    private static final Strategy HOUR12_STRATEGY = new 
NumberStrategy(Calendar.HOUR) {
-        @Override
-        int modify(final FastDateParser parser, final int iValue) {
-            return iValue == 12 ? 0 : iValue;
-        }
-    };
-    private static final Strategy HOUR_STRATEGY = new 
NumberStrategy(Calendar.HOUR);
-    private static final Strategy MINUTE_STRATEGY = new 
NumberStrategy(Calendar.MINUTE);
-    private static final Strategy SECOND_STRATEGY = new 
NumberStrategy(Calendar.SECOND);
-    private static final Strategy MILLISECOND_STRATEGY = new 
NumberStrategy(Calendar.MILLISECOND);
-}
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/Format.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/Format.java
index b81059b151..414ba9c4dc 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/Format.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/datetime/Format.java
@@ -17,8 +17,6 @@
 package org.apache.logging.log4j.core.util.datetime;
 
 import java.text.FieldPosition;
-import java.text.ParseException;
-import java.text.ParsePosition;
 
 /**
  * The basic methods for performing date formatting.
@@ -31,14 +29,4 @@ public abstract class Format {
 
     public abstract StringBuilder format(Object obj, StringBuilder toAppendTo, 
FieldPosition pos);
 
-    public abstract Object parseObject (String source, ParsePosition pos);
-
-    public Object parseObject(final String source) throws ParseException {
-        final ParsePosition pos = new ParsePosition(0);
-        final Object result = parseObject(source, pos);
-        if (pos.getIndex() == 0) {
-            throw new ParseException("Format.parseObject(String) failed", 
pos.getErrorIndex());
-        }
-        return result;
-    }
 }
diff --git a/src/changelog/.2.x.x/remove_FastDateParser.xml 
b/src/changelog/.2.x.x/remove_FastDateParser.xml
new file mode 100644
index 0000000000..f3b2f4f424
--- /dev/null
+++ b/src/changelog/.2.x.x/remove_FastDateParser.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns="http://logging.apache.org/log4j/changelog";
+       xsi:schemaLocation="http://logging.apache.org/log4j/changelog 
https://logging.apache.org/log4j/changelog-0.1.2.xsd";
+       type="removed">
+  <issue id="LOG4J2-3672" 
link="https://issues.apache.org/jira/browse/LOG4J2-3672"/>
+  <issue id="1848" link="https://github.com/apache/logging-log4j2/pull/1848"/>
+  <description format="asciidoc">Removed unused `FastDateParser` which was 
causing unnecessary heap overhead</description>
+</entry>
diff --git a/src/site/_release-notes/_2.x.x.adoc 
b/src/site/_release-notes/_2.x.x.adoc
index cc91f1be77..56f75c4852 100644
--- a/src/site/_release-notes/_2.x.x.adoc
+++ b/src/site/_release-notes/_2.x.x.adoc
@@ -64,6 +64,10 @@ The module name of four bridges (`log4j-slf4j-impl`, 
`log4j-slf4j2-impl`, `log4j
 * Update `uk.org.webcompere:system-stubs-core` to version `2.0.3` 
(https://github.com/apache/logging-log4j2/pull/1892[1892])
 * Update Spring Framework from version 5.3.29 to 5.3.30;
 
+=== Removed
+
+* Removed unused `FastDateParser` which was causing unnecessary heap overhead 
(https://issues.apache.org/jira/browse/LOG4J2-3672[LOG4J2-3672], 
https://github.com/apache/logging-log4j2/pull/1848[1848])
+
 === Fixed
 
 * Export missing OSGi & JPMS modules in `log4j-layout-template-json` and 
`log4j-1.2-api` (https://github.com/apache/logging-log4j2/issues/1895[1895])

Reply via email to