This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-lang.git
commit bcdff98f02c3ef011187f2dbf7934a3ea3a48db5 Author: Gary Gregory <[email protected]> AuthorDate: Tue Oct 20 11:45:46 2020 -0400 Sort methods. --- .../commons/lang3/time/FastDateParserTest.java | 822 ++++++++++----------- 1 file changed, 411 insertions(+), 411 deletions(-) diff --git a/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java b/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java index 5a15ea3..817de7b 100644 --- a/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java +++ b/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java @@ -45,32 +45,101 @@ import org.junit.jupiter.api.Test; * @since 3.2 */ public class FastDateParserTest { + private 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; + 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 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 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"); - DateParser getInstance(final String format) { - return getInstance(format, TimeZone.getDefault(), Locale.getDefault()); + 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 { + try { + final Date expectedTime = sdf.parse(formattedDate); + final Date actualTime = fdf.parse(formattedDate); + assertEquals(expectedTime, actualTime, "locale : " + locale + " formattedDate : " + formattedDate + "\n"); + } catch (Exception e) { + fail("locale : " + locale + " formattedDate : " + formattedDate + " error : " + e + "\n", e); + } } 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); } @@ -93,6 +162,29 @@ public class FastDateParserTest { } @Test + public void java15BuggyLocaleTest() throws ParseException { + final String buggyLocaleName = "ff_LR_#Adlm"; + Locale buggyLocale = null; + for (final Locale locale : Locale.getAvailableLocales()) { + if (buggyLocaleName.equals(locale.toString())) { + buggyLocale = locale; + break; + } + } + if (buggyLocale == null) { + return; + } + testSingleLocale(buggyLocale); + } + + @Test + public void java15BuggyLocaleTestAll() throws ParseException { + for (final Locale locale : Locale.getAvailableLocales()) { + testSingleLocale(locale); + } + } + + @Test public void test_Equality_Hash() { final DateParser[] parsers= { getInstance(yMdHmsSZ, NEW_YORK, Locale.US), @@ -116,51 +208,31 @@ public class FastDateParserTest { } } - @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); + @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"; - 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")); + for (final Expected1806 trial : Expected1806.values()) { + final Calendar cal = initializeCalendar(trial.zone); - cal.setTimeZone(TimeZone.getTimeZone("GMT-3")); - cal.set(2003, Calendar.FEBRUARY, 10, 9, 0, 0); + final String message = trial.zone.getDisplayName()+";"; - assertEquals(cal.getTime(), fdf.parse("2003-02-10T09:00:00.000 -0300")); + DateParser parser = getInstance(formatStub+"X", trial.zone); + assertEquals(cal.getTime().getTime(), parser.parse(dateStub+trial.one).getTime()-trial.offset, message+trial.one); - cal.setTimeZone(TimeZone.getTimeZone("GMT+5")); - cal.set(2003, Calendar.FEBRUARY, 10, 15, 5, 6); + parser = getInstance(formatStub+"XX", trial.zone); + assertEquals(cal.getTime(), parser.parse(dateStub+trial.two), message+trial.two); - assertEquals(cal.getTime(), fdf.parse("2003-02-10T15:05:06.000 +0500")); + parser = getInstance(formatStub+"XXX", trial.zone); + assertEquals(cal.getTime(), parser.parse(dateStub+trial.three), message+trial.three); + } } @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")); + public void test1806Argument() { + assertThrows(IllegalArgumentException.class, () -> getInstance("XXXX")); } @Test @@ -198,126 +270,146 @@ public class FastDateParserTest { assertEquals(cal.getTime(), H.parse("2010-08-01 12:33:20")); } - private Calendar getEraStart(int year, final TimeZone zone, final Locale locale) { - final Calendar cal = Calendar.getInstance(zone, locale); - cal.clear(); + @Test + public void testDayNumberOfWeek() throws ParseException { + final DateParser parser = getInstance("u"); + final Calendar calendar = Calendar.getInstance(); - // 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; - } + calendar.setTime(parser.parse("1")); + assertEquals(Calendar.MONDAY, calendar.get(Calendar.DAY_OF_WEEK)); - 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; - } - } + 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 - // 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(); + public void testDayOf() throws ParseException { + final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US); + cal.clear(); + cal.set(2003, Calendar.FEBRUARY, 10); - final FastDateParser fdp= new FastDateParser(format, tz, locale, centuryStart); - validateSdfFormatFdpParseEquality(format, locale, tz, fdp, in, year, centuryStart); - } - } - } - } + final DateParser fdf = getInstance("W w F D y", NEW_YORK, Locale.US); + assertEquals(cal.getTime(), fdf.parse("3 7 2 41 03")); } - // 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); + public void testEquals() { + final DateParser parser1= getInstance(YMD_SLASH); + final DateParser parser2= getInstance(YMD_SLASH); - 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(); + assertEquals(parser1, parser2); + assertEquals(parser1.hashCode(), parser2.hashCode()); - final Date actual = fdp.parse("2000/02/10 "+tz.getDisplayName(locale)); - assertEquals(expected, actual, "tz:"+tz.getID()+" locale:"+locale.getDisplayName()); - } - } + assertNotEquals(parser1, new Object()); } - @Test - public void testLocales_Long_AD() throws Exception { - testLocales(LONG_FORMAT, false); - } + public void testJpLocales() throws ParseException { - @Test - public void testLocales_Long_BC() throws Exception { - testLocales(LONG_FORMAT, true); - } + 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); + + // If parsing fails, a ParseException will be thrown and the test will fail + checkParse(locale, cal, sdf, fdf); + } @Test - public void testLocales_Short_AD() throws Exception { - testLocales(SHORT_FORMAT, false); + public void testLANG_831() throws Exception { + testSdfAndFdp("M E", "3 Tue", true); } @Test - public void testLocales_Short_BC() throws Exception { - testLocales(SHORT_FORMAT, true); + public void testLANG_832() throws Exception { + testSdfAndFdp("'d'd", "d3", false); // OK + testSdfAndFdp("'d'd'", "d3", true); // should fail (unterminated quote) } @Test - public void testLocales_LongNoEra_AD() throws Exception { - testLocales(LONG_FORMAT_NOERA, false); + public void testLang1121() throws ParseException { + final TimeZone kst = TimeZone.getTimeZone("KST"); + final DateParser fdp = getInstance("yyyyMMdd", kst, Locale.KOREA); + + assertThrows(ParseException.class, () -> fdp.parse("2015")); + + // 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 testLocales_LongNoEra_BC() throws Exception { - testLocales(LONG_FORMAT_NOERA, true); + public void testLang1380() throws ParseException { + final Calendar expected = Calendar.getInstance(GMT, Locale.FRANCE); + expected.clear(); + expected.set(2014, Calendar.APRIL, 14); + + final DateParser fdp = getInstance("dd MMM yyyy", GMT, Locale.FRANCE); + assertEquals(expected.getTime(), fdp.parse("14 avril 2014")); + assertEquals(expected.getTime(), fdp.parse("14 avr. 2014")); + assertEquals(expected.getTime(), fdp.parse("14 avr 2014")); } @Test - public void testLocales_ShortNoEra_AD() throws Exception { - testLocales(SHORT_FORMAT_NOERA, false); + 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 testLocales_ShortNoEra_BC() throws Exception { - testLocales(SHORT_FORMAT_NOERA, true); + 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 { @@ -343,150 +435,43 @@ public class FastDateParserTest { } @Test - public void testJpLocales() throws ParseException { - - 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); - - // If parsing fails, a ParseException will be thrown and the test will fail - checkParse(locale, cal, sdf, fdf); - } - - 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 { - try { - final Date expectedTime = sdf.parse(formattedDate); - final Date actualTime = fdf.parse(formattedDate); - assertEquals(expectedTime, actualTime, "locale : " + locale + " formattedDate : " + formattedDate + "\n"); - } catch (Exception e) { - fail("locale : " + locale + " formattedDate : " + formattedDate + " error : " + e + "\n", e); - } + public void testLocales_Long_AD() throws Exception { + testLocales(LONG_FORMAT, false); } @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")); + public void testLocales_Long_BC() throws Exception { + testLocales(LONG_FORMAT, true); } @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'")); + public void testLocales_LongNoEra_AD() throws Exception { + testLocales(LONG_FORMAT_NOERA, false); } @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); + public void testLocales_LongNoEra_BC() throws Exception { + testLocales(LONG_FORMAT_NOERA, true); } @Test - public void testLANG_832() throws Exception { - testSdfAndFdp("'d'd", "d3", false); // OK - testSdfAndFdp("'d'd'", "d3", true); // should fail (unterminated quote) + public void testLocales_Short_AD() throws Exception { + testLocales(SHORT_FORMAT, false); } @Test - public void testLANG_831() throws Exception { - testSdfAndFdp("M E", "3 Tue", true); - } - - 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); - assertFalse(shouldFail, "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); - assertFalse(shouldFail, "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 - assertEquals((f == null), (s == null), "Should both or neither throw Exceptions"); - assertEquals(dsdf, dfdp, "Parsed dates should be equal"); + public void testLocales_Short_BC() throws Exception { + testLocales(SHORT_FORMAT, true); } @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")); + public void testLocales_ShortNoEra_AD() throws Exception { + testLocales(SHORT_FORMAT_NOERA, false); } - /** - * 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")); + public void testLocales_ShortNoEra_BC() throws Exception { + testLocales(SHORT_FORMAT_NOERA, true); } /** @@ -520,226 +505,241 @@ public class FastDateParserTest { } @Test - public void testLang303() throws ParseException { - DateParser parser = getInstance(YMD_SLASH); - final Calendar cal = Calendar.getInstance(); - cal.set(2004, Calendar.DECEMBER, 31); + 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); - final Date date = parser.parse("2004/11/31"); + DateParser fdf = getInstance("yyyy GGGG MMMM dddd aaaa EEEE HHHH mmmm ssss SSSS ZZZZ", NEW_YORK, Locale.US); - parser = SerializationUtils.deserialize(SerializationUtils.serialize((Serializable) parser)); - assertEquals(date, parser.parse("2004/11/31")); + 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 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")); + public void testParseNumerics() throws ParseException { + final Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US); cal.clear(); - cal.set(2009, Calendar.OCTOBER, 16, 8, 42, 16); + cal.set(2003, Calendar.FEBRUARY, 10, 15, 33, 20); + cal.set(Calendar.MILLISECOND, 989); - assertEquals(cal.getTime(), parser.parse("2009-10-16T16:42:16.000Z")); + final DateParser fdf = getInstance("yyyyMMddHHmmssSSS", NEW_YORK, Locale.US); + assertEquals(cal.getTime(), fdf.parse("20030210153320989")); } @Test - public void testEquals() { - final DateParser parser1= getInstance(YMD_SLASH); - final DateParser parser2= getInstance(YMD_SLASH); - - assertEquals(parser1, parser2); - assertEquals(parser1.hashCode(), parser2.hashCode()); - - assertNotEquals(parser1, new Object()); - } + public void testParseOffset() { + final DateParser parser = getInstance(YMD_SLASH); + final Date date = parser.parse("Today is 2015/07/04", new ParsePosition(9)); - @Test - public void testToStringContainsName() { - final DateParser parser= getInstance(YMD_SLASH); - assertTrue(parser.toString().startsWith("FastDate")); + final Calendar cal = Calendar.getInstance(); + cal.clear(); + cal.set(2015, Calendar.JULY, 4); + assertEquals(cal.getTime(), date); } @Test - public void testPatternMatches() { - final DateParser parser= getInstance(yMdHmsSZ); - assertEquals(yMdHmsSZ, parser.getPattern()); - } + // 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(); - @Test - public void testLocaleMatches() { - final DateParser parser= getInstance(yMdHmsSZ, SWEDEN); - assertEquals(SWEDEN, parser.getLocale()); - } + cal.set(Calendar.MONTH, 1); + cal.set(Calendar.DAY_OF_MONTH, 10); + final Date in= cal.getTime(); - @Test - public void testTimeZoneMatches() { - final DateParser parser= getInstance(yMdHmsSZ, REYKJAVIK); - assertEquals(REYKJAVIK, parser.getTimeZone()); + final FastDateParser fdp= new FastDateParser(format, tz, locale, centuryStart); + validateSdfFormatFdpParseEquality(format, locale, tz, fdp, in, year, centuryStart); + } + } + } + } } @Test - public void testLang996() throws ParseException { - final Calendar expected = Calendar.getInstance(NEW_YORK, Locale.US); - expected.clear(); - expected.set(2014, Calendar.MAY, 14); + 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 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")); - } + final DateParser fdf = getInstance(yMdHmsSZ, NEW_YORK, Locale.US); - @Test - public void test1806Argument() { - assertThrows(IllegalArgumentException.class, () -> getInstance("XXXX")); - } + 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")); - 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; - } + cal.setTimeZone(TimeZone.getTimeZone("GMT-3")); + cal.set(2003, Calendar.FEBRUARY, 10, 9, 0, 0); - private enum Expected1806 { - India(INDIA, "+05", "+0530", "+05:30", true), - Greenwich(GMT, "Z", "Z", "Z", false), - NewYork(NEW_YORK, "-05", "-0500", "-05:00", false); + assertEquals(cal.getTime(), fdf.parse("2003-02-10T09:00:00.000 -0300")); - 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; - } + cal.setTimeZone(TimeZone.getTimeZone("GMT+5")); + cal.set(2003, Calendar.FEBRUARY, 10, 15, 5, 6); - final TimeZone zone; - final String one; - final String two; - final String three; - final long offset; + assertEquals(cal.getTime(), fdf.parse("2003-02-10T15:05:06.000 +0500")); } @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"; + public void testPatternMatches() { + final DateParser parser= getInstance(yMdHmsSZ); + assertEquals(yMdHmsSZ, parser.getPattern()); + } - for (final Expected1806 trial : Expected1806.values()) { - final Calendar cal = initializeCalendar(trial.zone); + @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 String message = trial.zone.getDisplayName()+";"; + final DateParser fdf = getInstance("''yyyyMMdd'A''B'HHmmssSSS''", NEW_YORK, Locale.US); + assertEquals(cal.getTime(), fdf.parse("'20030210A'B153320989'")); + } - DateParser parser = getInstance(formatStub+"X", trial.zone); - assertEquals(cal.getTime().getTime(), parser.parse(dateStub+trial.one).getTime()-trial.offset, message+trial.one); + 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; - parser = getInstance(formatStub+"XX", trial.zone); - assertEquals(cal.getTime(), parser.parse(dateStub+trial.two), message+trial.two); + try { + final SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US); + sdf.setTimeZone(NEW_YORK); + dsdf = sdf.parse(date); + assertFalse(shouldFail, "Expected SDF failure, but got " + dsdf + " for ["+format+", "+date+"]"); + } catch (final Exception e) { + s = e; + if (!shouldFail) { + throw e; + } + } - parser = getInstance(formatStub+"XXX", trial.zone); - assertEquals(cal.getTime(), parser.parse(dateStub+trial.three), message+trial.three); + try { + final DateParser fdp = getInstance(format, NEW_YORK, Locale.US); + dfdp = fdp.parse(date); + assertFalse(shouldFail, "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 + assertEquals((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 testLang1121() throws ParseException { - final TimeZone kst = TimeZone.getTimeZone("KST"); - final DateParser fdp = getInstance("yyyyMMdd", kst, Locale.KOREA); - - assertThrows(ParseException.class, () -> fdp.parse("2015")); - - // Wed Apr 29 00:00:00 KST 2015 - Date actual = fdp.parse("20150429"); - final Calendar cal = Calendar.getInstance(kst, Locale.KOREA); + public void testShortDateStyleWithLocales() throws ParseException { + DateParser fdf = getDateInstance(FastDateFormat.SHORT, Locale.US); + final Calendar cal = Calendar.getInstance(); 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"); + cal.set(2004, Calendar.FEBRUARY, 3); + assertEquals(cal.getTime(), fdf.parse("2/3/04")); - // Thu Mar 16 00:00:00 KST 81724 - actual = fdp.parse("20150429113100"); - assertEquals(expected, actual); + fdf = getDateInstance(FastDateFormat.SHORT, SWEDEN); + assertEquals(cal.getTime(), fdf.parse("2004-02-03")); } - @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(); + private void testSingleLocale(final Locale locale) throws ParseException { + final Calendar cal = Calendar.getInstance(GMT); cal.clear(); - cal.set(2015, Calendar.JULY, 4); - assertEquals(cal.getTime(), date); + cal.set(2003, Calendar.FEBRUARY, 10); + final SimpleDateFormat sdf = new SimpleDateFormat(LONG_FORMAT, locale); + final String formattedDate = sdf.format(cal.getTime()); + sdf.parse(formattedDate); + sdf.parse(formattedDate.toUpperCase(locale)); + sdf.parse(formattedDate.toLowerCase(locale)); } @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)); + 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 - calendar.setTime(parser.parse("7")); - assertEquals(Calendar.SUNDAY, calendar.get(Calendar.DAY_OF_WEEK)); + // 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 testLang1380() throws ParseException { - final Calendar expected = Calendar.getInstance(GMT, Locale.FRANCE); - expected.clear(); - expected.set(2014, Calendar.APRIL, 14); - - final DateParser fdp = getInstance("dd MMM yyyy", GMT, Locale.FRANCE); - assertEquals(expected.getTime(), fdp.parse("14 avril 2014")); - assertEquals(expected.getTime(), fdp.parse("14 avr. 2014")); - assertEquals(expected.getTime(), fdp.parse("14 avr 2014")); + public void testTimeZoneMatches() { + final DateParser parser= getInstance(yMdHmsSZ, REYKJAVIK); + assertEquals(REYKJAVIK, parser.getTimeZone()); } @Test - public void java15BuggyLocaleTestAll() throws ParseException { - for (final Locale locale : Locale.getAvailableLocales()) { - testSingleLocale(locale); - } + 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 java15BuggyLocaleTest() throws ParseException { - final String buggyLocaleName = "ff_LR_#Adlm"; - Locale buggyLocale = null; + public void testTzParses() throws Exception { + // Check that all Locales can parse the time formats we use for (final Locale locale : Locale.getAvailableLocales()) { - if (buggyLocaleName.equals(locale.toString())) { - buggyLocale = locale; - break; + 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()); } } - if (buggyLocale == null) { - return; - } - testSingleLocale(buggyLocale); } - private void testSingleLocale(final Locale locale) throws ParseException { - final Calendar cal = Calendar.getInstance(GMT); - cal.clear(); - cal.set(2003, Calendar.FEBRUARY, 10); - final SimpleDateFormat sdf = new SimpleDateFormat(LONG_FORMAT, locale); - final String formattedDate = sdf.format(cal.getTime()); - sdf.parse(formattedDate); - sdf.parse(formattedDate.toUpperCase(locale)); - sdf.parse(formattedDate.toLowerCase(locale)); + 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; + } + } } }
