/* * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch 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. */ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ package org.opensearch.common.joda; import org.opensearch.OpenSearchParseException; import org.opensearch.common.time.DateFormatter; import org.opensearch.common.time.DateFormatters; import org.opensearch.common.time.DateMathParser; import org.opensearch.common.time.FormatNames; import org.opensearch.test.OpenSearchTestCase; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.ISODateTimeFormat; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; import java.util.Locale; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; public class JavaJodaTimeDuellingTests extends OpenSearchTestCase { @Override protected boolean enableWarningsCheck() { return false; } public void testTimezoneParsing() { /** this testcase won't work in joda. See comment in {@link #testPartialTimeParsing()} * assertSameDateAs("2016-11-30T+01", "strict_date_optional_time", "strict_date_optional_time"); */ assertSameDateAs("2016-11-30T00+01", "strict_date_optional_time", "strict_date_optional_time"); assertSameDateAs("2016-11-30T00+0100", "strict_date_optional_time", "strict_date_optional_time"); assertSameDateAs("2016-11-30T00+01:00", "strict_date_optional_time", "strict_date_optional_time"); } public void testPartialTimeParsing() { /* This does not work in Joda as it reports 2016-11-30T01:00:00Z because StrictDateOptionalTime confuses +01 with an hour (which is a signed fixed length digit) assertSameDateAs("2016-11-30T+01", "strict_date_optional_time", "strict_date_optional_time"); ES java.time implementation does not suffer from this, but we intentionally not allow parsing timezone without an time part as it is not allowed in iso8601 */ assertJavaTimeParseException("2016-11-30T+01", "strict_date_optional_time"); assertSameDateAs("2016-11-30T12+01", "strict_date_optional_time", "strict_date_optional_time"); assertSameDateAs("2016-11-30T12:00+01", "strict_date_optional_time", "strict_date_optional_time"); assertSameDateAs("2016-11-30T12:00:00+01", "strict_date_optional_time", "strict_date_optional_time"); assertSameDateAs("2016-11-30T12:00:00.000+01", "strict_date_optional_time", "strict_date_optional_time"); // without timezone assertSameDateAs("2016-11-30T", "strict_date_optional_time", "strict_date_optional_time"); assertSameDateAs("2016-11-30T12", "strict_date_optional_time", "strict_date_optional_time"); assertSameDateAs("2016-11-30T12:00", "strict_date_optional_time", "strict_date_optional_time"); assertSameDateAs("2016-11-30T12:00:00", "strict_date_optional_time", "strict_date_optional_time"); assertSameDateAs("2016-11-30T12:00:00.000", "strict_date_optional_time", "strict_date_optional_time"); } // date_optional part of a parser names "strict_date_optional_time" or "date_optional"time // means that date part can be partially parsed. public void testPartialDateParsing() { assertSameDateAs("2001", "strict_date_optional_time_nanos", "strict_date_optional_time"); assertSameDateAs("2001-01", "strict_date_optional_time_nanos", "strict_date_optional_time"); assertSameDateAs("2001-01-01", "strict_date_optional_time_nanos", "strict_date_optional_time"); assertSameDate("2001", "strict_date_optional_time"); assertSameDate("2001-01", "strict_date_optional_time"); assertSameDate("2001-01-01", "strict_date_optional_time"); assertSameDate("2001", "date_optional_time"); assertSameDate("2001-01", "date_optional_time"); assertSameDate("2001-01-01", "date_optional_time"); assertSameDateAs("2001", "iso8601", "strict_date_optional_time"); assertSameDateAs("2001-01", "iso8601", "strict_date_optional_time"); assertSameDateAs("2001-01-01", "iso8601", "strict_date_optional_time"); assertSameDate("9999", "date_optional_time||epoch_second"); } public void testCompositeDateMathParsing() { // in all these examples the second pattern will be used assertDateMathEquals("2014-06-06T12:01:02.123", "yyyy-MM-dd'T'HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSS"); assertDateMathEquals("2014-06-06T12:01:02.123", "strictDateTimeNoMillis||yyyy-MM-dd'T'HH:mm:ss.SSS"); assertDateMathEquals("2014-06-06T12:01:02.123", "yyyy-MM-dd'T'HH:mm:ss+HH:MM||yyyy-MM-dd'T'HH:mm:ss.SSS"); } public void testExceptionWhenCompositeParsingFailsDateMath() { // both parsing failures should contain pattern and input text in exception // both patterns fail parsing the input text due to only 2 digits of millis. Hence full text was not parsed. String pattern = "yyyy-MM-dd'T'HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SS"; String text = "2014-06-06T12:01:02.123"; OpenSearchParseException e1 = expectThrows( OpenSearchParseException.class, () -> dateMathToMillis(text, DateFormatter.forPattern(pattern)) ); assertThat(e1.getMessage(), containsString(pattern)); assertThat(e1.getMessage(), containsString(text)); OpenSearchParseException e2 = expectThrows(OpenSearchParseException.class, () -> dateMathToMillis(text, Joda.forPattern(pattern))); assertThat(e2.getMessage(), containsString(pattern)); assertThat(e2.getMessage(), containsString(text)); } private long dateMathToMillis(String text, DateFormatter dateFormatter) { DateFormatter javaFormatter = dateFormatter.withLocale(randomLocale(random())); DateMathParser javaDateMath = javaFormatter.toDateMathParser(); return javaDateMath.parse(text, () -> 0, true, (ZoneId) null).toEpochMilli(); } // these parsers should allow both ',' and '.' as a decimal point public void testDecimalPointParsing() { assertSameDate("2001-01-01T00:00:00.123Z", "strict_date_optional_time"); assertSameDate("2001-01-01T00:00:00,123Z", "strict_date_optional_time"); assertSameDate("2001-01-01T00:00:00.123Z", "date_optional_time"); assertSameDate("2001-01-01T00:00:00,123Z", "date_optional_time"); // only java.time has nanos parsing, but the results for 3digits should be the same DateFormatter jodaFormatter = Joda.forPattern("strict_date_optional_time"); DateFormatter javaFormatter = DateFormatter.forPattern("strict_date_optional_time_nanos"); assertSameDate("2001-01-01T00:00:00.123Z", "strict_date_optional_time_nanos", jodaFormatter, javaFormatter); assertSameDate("2001-01-01T00:00:00,123Z", "strict_date_optional_time_nanos", jodaFormatter, javaFormatter); assertParseException("2001-01-01T00:00:00.123,456Z", "strict_date_optional_time"); assertParseException("2001-01-01T00:00:00.123,456Z", "date_optional_time"); // This should fail, but java is ok with this because the field has the same value // assertJavaTimeParseException("2001-01-01T00:00:00.123,123Z", "strict_date_optional_time_nanos"); } public void testIncompatiblePatterns() { // in joda 'y' means year, this is changed to 'u' in java.time. difference is in before era yeaers assertSameMillis("-0001-01-01", "yyyy-MM-dd", "8uuuu-MM-dd"); assertSameMillis("-1", "y", "8u"); // year-of-era in joda becomes 'y' in java.time assertSameMillis("2019-01-01", "YYYY-MM-dd", "8yyyy-MM-dd"); // in joda 'Z' was able to parse 'Z' zulu but in java it fails. You have to use 'X' to do that. assertSameMillis("2019-01-01T01:01:01.001Z", "YYYY-MM-dd'T'HH:mm:ss.SSSZ", "8yyyy-MM-dd'T'HH:mm:ss.SSSX"); assertSameMillis("2019-01-01T01:01:01.001+0000", "YYYY-MM-dd'T'HH:mm:ss.SSSZ", "8yyyy-MM-dd'T'HH:mm:ss.SSSZ"); // 'z' zoneId in joda prints UTC whereas joda prints 'Z' for zulu TemporalAccessor parse = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSz", Locale.getDefault()) .parse("2019-01-01T01:01:01.001+00:00"); String javaZoneId = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSz", Locale.getDefault()).format(parse); DateTime dateTime = DateTimeFormat.forPattern("YYYY-MM-dd'T'HH:mm:ss.SSSZ") .withOffsetParsed() .parseDateTime("2019-01-01T01:01:01.001+0000"); String jodaZoneId = DateTimeFormat.forPattern("YYYY-MM-dd'T'HH:mm:ss.SSSz").print(dateTime); assertThat(javaZoneId, equalTo("2019-01-01T01:01:01.001Z")); assertThat(jodaZoneId, equalTo("2019-01-01T01:01:01.001UTC")); } private void assertSameMillis(String input, String jodaFormat, String javaFormat) { DateFormatter jodaFormatter = Joda.forPattern(jodaFormat); DateFormatter javaFormatter = DateFormatter.forPattern(javaFormat); DateTime jodaDateTime = jodaFormatter.parseJoda(input); TemporalAccessor javaTimeAccessor = javaFormatter.parse(input); ZonedDateTime zonedDateTime = DateFormatters.from(javaTimeAccessor); String msg = String.format( Locale.ROOT, "Input [%s] JodaFormat [%s] JavaFormat [%s] Joda [%s], Java [%s]", input, jodaFormat, javaFormat, jodaDateTime, DateTimeFormatter.ISO_INSTANT.format(zonedDateTime.toInstant()) ); assertThat(msg, jodaDateTime.getMillis(), is(zonedDateTime.toInstant().toEpochMilli())); } public void testTimeZoneFormatting() { assertSameDate("2001-01-01T00:00:00Z", "date_time_no_millis"); // the following fail under java 8 but work under java 10, needs investigation assertSameDate("2001-01-01T00:00:00-0800", "date_time_no_millis"); assertSameDate("2001-01-01T00:00:00+1030", "date_time_no_millis"); assertSameDate("2001-01-01T00:00:00-08", "date_time_no_millis"); assertSameDate("2001-01-01T00:00:00+10:30", "date_time_no_millis"); // different timezone parsing styles require a different number of letters DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSXXX", Locale.ROOT); formatter.parse("20181126T121212.123Z"); formatter.parse("20181126T121212.123-08:30"); DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSXXXX", Locale.ROOT); formatter2.parse("20181126T121212.123+1030"); formatter2.parse("20181126T121212.123-0830"); // ... and can be combined, note that this is not an XOR, so one could append both timezones with this example DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSS[XXXX][XXX]", Locale.ROOT); formatter3.parse("20181126T121212.123Z"); formatter3.parse("20181126T121212.123-08:30"); formatter3.parse("20181126T121212.123+1030"); formatter3.parse("20181126T121212.123-0830"); } public void testCustomTimeFormats() { assertSameDate("2010 12 06 11:05:15", "yyyy dd MM HH:mm:ss"); assertSameDate("12/06", "dd/MM"); assertSameDate("Nov 24 01:29:01 -0800", "MMM dd HH:mm:ss Z"); } // this test requires tests to run with -Djava.locale.providers=COMPAT in order to work // public void testCustomLocales() { // // // also ensure that locale based dates are the same // assertSameDate("Di., 05 Dez. 2000 02:55:00 -0800", "E, d MMM yyyy HH:mm:ss Z", LocaleUtils.parse("de")); // assertSameDate("Mi., 06 Dez. 2000 02:55:00 -0800", "E, d MMM yyyy HH:mm:ss Z", LocaleUtils.parse("de")); // assertSameDate("Do., 07 Dez. 2000 00:00:00 -0800", "E, d MMM yyyy HH:mm:ss Z", LocaleUtils.parse("de")); // assertSameDate("Fr., 08 Dez. 2000 00:00:00 -0800", "E, d MMM yyyy HH:mm:ss Z", LocaleUtils.parse("de")); // // DateTime dateTimeNow = DateTime.now(DateTimeZone.UTC); // ZonedDateTime javaTimeNow = Instant.ofEpochMilli(dateTimeNow.getMillis()).atZone(ZoneOffset.UTC); // assertSamePrinterOutput("E, d MMM yyyy HH:mm:ss Z", LocaleUtils.parse("de"), javaTimeNow, dateTimeNow); // } public void testDuellingFormatsValidParsing() { assertSameDate("1522332219", "epoch_second"); assertSameDate("0", "epoch_second"); assertSameDate("1", "epoch_second"); assertSameDate("1522332219321", "epoch_millis"); assertSameDate("0", "epoch_millis"); assertSameDate("1", "epoch_millis"); assertSameDate("20181126", "basic_date"); assertSameDate("20181126T121212.123Z", "basic_date_time"); assertSameDate("20181126T121212.123+10:00", "basic_date_time"); assertSameDate("20181126T121212.123-0800", "basic_date_time"); assertSameDate("20181126T121212Z", "basic_date_time_no_millis"); assertSameDate("20181126T121212+01:00", "basic_date_time_no_millis"); assertSameDate("20181126T121212+0100", "basic_date_time_no_millis"); assertSameDate("2018363", "basic_ordinal_date"); assertSameDate("2018363T121212.1Z", "basic_ordinal_date_time"); assertSameDate("2018363T121212.123Z", "basic_ordinal_date_time"); assertSameDate("2018363T121212.123456789Z", "basic_ordinal_date_time"); assertSameDate("2018363T121212.123+0100", "basic_ordinal_date_time"); assertSameDate("2018363T121212.123+01:00", "basic_ordinal_date_time"); assertSameDate("2018363T121212Z", "basic_ordinal_date_time_no_millis"); assertSameDate("2018363T121212+0100", "basic_ordinal_date_time_no_millis"); assertSameDate("2018363T121212+01:00", "basic_ordinal_date_time_no_millis"); assertSameDate("121212.1Z", "basic_time"); assertSameDate("121212.123Z", "basic_time"); assertSameDate("121212.123456789Z", "basic_time"); assertSameDate("121212.1+0100", "basic_time"); assertSameDate("121212.123+0100", "basic_time"); assertSameDate("121212.123+01:00", "basic_time"); assertSameDate("121212Z", "basic_time_no_millis"); assertSameDate("121212+0100", "basic_time_no_millis"); assertSameDate("121212+01:00", "basic_time_no_millis"); assertSameDate("T121212.1Z", "basic_t_time"); assertSameDate("T121212.123Z", "basic_t_time"); assertSameDate("T121212.123456789Z", "basic_t_time"); assertSameDate("T121212.1+0100", "basic_t_time"); assertSameDate("T121212.123+0100", "basic_t_time"); assertSameDate("T121212.123+01:00", "basic_t_time"); assertSameDate("T121212Z", "basic_t_time_no_millis"); assertSameDate("T121212+0100", "basic_t_time_no_millis"); assertSameDate("T121212+01:00", "basic_t_time_no_millis"); assertSameDate("2018W313", "basic_week_date"); assertSameDate("1W313", "basic_week_date"); assertSameDate("18W313", "basic_week_date"); assertSameDate("2018W313T121212.1Z", "basic_week_date_time"); assertSameDate("2018W313T121212.123Z", "basic_week_date_time"); assertSameDate("2018W313T121212.123456789Z", "basic_week_date_time"); assertSameDate("2018W313T121212.123+0100", "basic_week_date_time"); assertSameDate("2018W313T121212.123+01:00", "basic_week_date_time"); assertSameDate("2018W313T121212Z", "basic_week_date_time_no_millis"); assertSameDate("2018W313T121212+0100", "basic_week_date_time_no_millis"); assertSameDate("2018W313T121212+01:00", "basic_week_date_time_no_millis"); assertSameDate("2018-12-31", "date"); assertSameDate("18-5-6", "date"); assertSameDate("10000-5-6", "date"); assertSameDate("2018-12-31T12", "date_hour"); assertSameDate("2018-12-31T8", "date_hour"); assertSameDate("2018-12-31T12:12", "date_hour_minute"); assertSameDate("2018-12-31T8:3", "date_hour_minute"); assertSameDate("2018-12-31T12:12:12", "date_hour_minute_second"); assertSameDate("2018-12-31T12:12:1", "date_hour_minute_second"); assertSameDate("2018-12-31T12:12:12.1", "date_hour_minute_second_fraction"); assertSameDate("2018-12-31T12:12:12.123", "date_hour_minute_second_fraction"); assertSameDate("2018-12-31T12:12:12.123456789", "date_hour_minute_second_fraction"); assertSameDate("2018-12-31T12:12:12.1", "date_hour_minute_second_millis"); assertSameDate("2018-12-31T12:12:12.123", "date_hour_minute_second_millis"); assertParseException("2018-12-31T12:12:12.123456789", "date_hour_minute_second_millis"); assertSameDate("2018-12-31T12:12:12.1", "date_hour_minute_second_millis"); assertSameDate("2018-12-31T12:12:12.1", "date_hour_minute_second_fraction"); assertSameDate("2018-05", "date_optional_time"); assertSameDate("2018-05-30", "date_optional_time"); assertSameDate("2018-05-30T20", "date_optional_time"); assertSameDate("2018-05-30T20:21", "date_optional_time"); assertSameDate("2018-05-30T20:21:23", "date_optional_time"); assertSameDate("2018-05-30T20:21:23.1", "date_optional_time"); assertSameDate("2018-05-30T20:21:23.123", "date_optional_time"); assertSameDate("2018-05-30T20:21:23.123456789", "date_optional_time"); assertSameDate("2018-05-30T20:21:23.123Z", "date_optional_time"); assertSameDate("2018-05-30T20:21:23.123456789Z", "date_optional_time"); assertSameDate("2018-05-30T20:21:23.1+0100", "date_optional_time"); assertSameDate("2018-05-30T20:21:23.123+0100", "date_optional_time"); assertSameDate("2018-05-30T20:21:23.1+01:00", "date_optional_time"); assertSameDate("2018-05-30T20:21:23.123+01:00", "date_optional_time"); assertSameDate("2018-12-1", "date_optional_time"); assertSameDate("2018-12-31T10:15:30", "date_optional_time"); assertSameDate("2018-12-31T10:15:3", "date_optional_time"); assertSameDate("2018-12-31T10:5:30", "date_optional_time"); assertSameDate("2018-12-31T1:15:30", "date_optional_time"); assertSameDate("2018-12-31T10:15:30.1Z", "date_time"); assertSameDate("2018-12-31T10:15:30.123Z", "date_time"); assertSameDate("2018-12-31T10:15:30.123456789Z", "date_time"); assertSameDate("2018-12-31T10:15:30.1+0100", "date_time"); assertSameDate("2018-12-31T10:15:30.123+0100", "date_time"); assertSameDate("2018-12-31T10:15:30.123+01:00", "date_time"); assertSameDate("2018-12-31T10:15:30.1+01:00", "date_time"); assertSameDate("2018-12-31T10:15:30.11Z", "date_time"); assertSameDate("2018-12-31T10:15:30.11+0100", "date_time"); assertSameDate("2018-12-31T10:15:30.11+01:00", "date_time"); assertSameDate("2018-12-31T10:15:3.1Z", "date_time"); assertSameDate("2018-12-31T10:15:3.123Z", "date_time"); assertSameDate("2018-12-31T10:15:3.123456789Z", "date_time"); assertSameDate("2018-12-31T10:15:3.1+0100", "date_time"); assertSameDate("2018-12-31T10:15:3.123+0100", "date_time"); assertSameDate("2018-12-31T10:15:3.123+01:00", "date_time"); assertSameDate("2018-12-31T10:15:3.1+01:00", "date_time"); assertSameDate("2018-12-31T10:15:30Z", "date_time_no_millis"); assertSameDate("2018-12-31T10:15:30+0100", "date_time_no_millis"); assertSameDate("2018-12-31T10:15:30+01:00", "date_time_no_millis"); assertSameDate("2018-12-31T10:5:30Z", "date_time_no_millis"); assertSameDate("2018-12-31T10:5:30+0100", "date_time_no_millis"); assertSameDate("2018-12-31T10:5:30+01:00", "date_time_no_millis"); assertSameDate("2018-12-31T10:15:3Z", "date_time_no_millis"); assertSameDate("2018-12-31T10:15:3+0100", "date_time_no_millis"); assertSameDate("2018-12-31T10:15:3+01:00", "date_time_no_millis"); assertSameDate("2018-12-31T1:15:30Z", "date_time_no_millis"); assertSameDate("2018-12-31T1:15:30+0100", "date_time_no_millis"); assertSameDate("2018-12-31T1:15:30+01:00", "date_time_no_millis"); assertSameDate("12", "hour"); assertSameDate("01", "hour"); assertSameDate("1", "hour"); assertSameDate("12:12", "hour_minute"); assertSameDate("12:01", "hour_minute"); assertSameDate("12:1", "hour_minute"); assertSameDate("12:12:12", "hour_minute_second"); assertSameDate("12:12:01", "hour_minute_second"); assertSameDate("12:12:1", "hour_minute_second"); assertSameDate("12:12:12.123", "hour_minute_second_fraction"); assertSameDate("12:12:12.123456789", "hour_minute_second_fraction"); assertSameDate("12:12:12.1", "hour_minute_second_fraction"); assertParseException("12:12:12", "hour_minute_second_fraction"); assertSameDate("12:12:12.123", "hour_minute_second_millis"); assertParseException("12:12:12.123456789", "hour_minute_second_millis"); assertSameDate("12:12:12.1", "hour_minute_second_millis"); assertParseException("12:12:12", "hour_minute_second_millis"); assertSameDate("2018-128", "ordinal_date"); assertSameDate("2018-1", "ordinal_date"); assertSameDate("2018-128T10:15:30.1Z", "ordinal_date_time"); assertSameDate("2018-128T10:15:30.123Z", "ordinal_date_time"); assertSameDate("2018-128T10:15:30.123456789Z", "ordinal_date_time"); assertSameDate("2018-128T10:15:30.123+0100", "ordinal_date_time"); assertSameDate("2018-128T10:15:30.123+01:00", "ordinal_date_time"); assertSameDate("2018-1T10:15:30.1Z", "ordinal_date_time"); assertSameDate("2018-1T10:15:30.123Z", "ordinal_date_time"); assertSameDate("2018-1T10:15:30.123456789Z", "ordinal_date_time"); assertSameDate("2018-1T10:15:30.123+0100", "ordinal_date_time"); assertSameDate("2018-1T10:15:30.123+01:00", "ordinal_date_time"); assertSameDate("2018-128T10:15:30Z", "ordinal_date_time_no_millis"); assertSameDate("2018-128T10:15:30+0100", "ordinal_date_time_no_millis"); assertSameDate("2018-128T10:15:30+01:00", "ordinal_date_time_no_millis"); assertSameDate("2018-1T10:15:30Z", "ordinal_date_time_no_millis"); assertSameDate("2018-1T10:15:30+0100", "ordinal_date_time_no_millis"); assertSameDate("2018-1T10:15:30+01:00", "ordinal_date_time_no_millis"); assertSameDate("10:15:30.1Z", "time"); assertSameDate("10:15:30.123Z", "time"); assertSameDate("10:15:30.123456789Z", "time"); assertSameDate("10:15:30.123+0100", "time"); assertSameDate("10:15:30.123+01:00", "time"); assertSameDate("1:15:30.1Z", "time"); assertSameDate("1:15:30.123Z", "time"); assertSameDate("1:15:30.123+0100", "time"); assertSameDate("1:15:30.123+01:00", "time"); assertSameDate("10:1:30.1Z", "time"); assertSameDate("10:1:30.123Z", "time"); assertSameDate("10:1:30.123+0100", "time"); assertSameDate("10:1:30.123+01:00", "time"); assertSameDate("10:15:3.1Z", "time"); assertSameDate("10:15:3.123Z", "time"); assertSameDate("10:15:3.123+0100", "time"); assertSameDate("10:15:3.123+01:00", "time"); assertParseException("10:15:3.1", "time"); assertParseException("10:15:3Z", "time"); assertSameDate("10:15:30Z", "time_no_millis"); assertSameDate("10:15:30+0100", "time_no_millis"); assertSameDate("10:15:30+01:00", "time_no_millis"); assertSameDate("01:15:30Z", "time_no_millis"); assertSameDate("01:15:30+0100", "time_no_millis"); assertSameDate("01:15:30+01:00", "time_no_millis"); assertSameDate("1:15:30Z", "time_no_millis"); assertSameDate("1:15:30+0100", "time_no_millis"); assertSameDate("1:15:30+01:00", "time_no_millis"); assertSameDate("10:5:30Z", "time_no_millis"); assertSameDate("10:5:30+0100", "time_no_millis"); assertSameDate("10:5:30+01:00", "time_no_millis"); assertSameDate("10:15:3Z", "time_no_millis"); assertSameDate("10:15:3+0100", "time_no_millis"); assertSameDate("10:15:3+01:00", "time_no_millis"); assertParseException("10:15:3", "time_no_millis"); assertSameDate("T10:15:30.1Z", "t_time"); assertSameDate("T10:15:30.123Z", "t_time"); assertSameDate("T10:15:30.123456789Z", "t_time"); assertSameDate("T10:15:30.1+0100", "t_time"); assertSameDate("T10:15:30.123+0100", "t_time"); assertSameDate("T10:15:30.123+01:00", "t_time"); assertSameDate("T10:15:30.1+01:00", "t_time"); assertSameDate("T1:15:30.123Z", "t_time"); assertSameDate("T1:15:30.123+0100", "t_time"); assertSameDate("T1:15:30.123+01:00", "t_time"); assertSameDate("T10:1:30.123Z", "t_time"); assertSameDate("T10:1:30.123+0100", "t_time"); assertSameDate("T10:1:30.123+01:00", "t_time"); assertSameDate("T10:15:3.123Z", "t_time"); assertSameDate("T10:15:3.123+0100", "t_time"); assertSameDate("T10:15:3.123+01:00", "t_time"); assertParseException("T10:15:3.1", "t_time"); assertParseException("T10:15:3Z", "t_time"); assertSameDate("T10:15:30Z", "t_time_no_millis"); assertSameDate("T10:15:30+0100", "t_time_no_millis"); assertSameDate("T10:15:30+01:00", "t_time_no_millis"); assertSameDate("T1:15:30Z", "t_time_no_millis"); assertSameDate("T1:15:30+0100", "t_time_no_millis"); assertSameDate("T1:15:30+01:00", "t_time_no_millis"); assertSameDate("T10:1:30Z", "t_time_no_millis"); assertSameDate("T10:1:30+0100", "t_time_no_millis"); assertSameDate("T10:1:30+01:00", "t_time_no_millis"); assertSameDate("T10:15:3Z", "t_time_no_millis"); assertSameDate("T10:15:3+0100", "t_time_no_millis"); assertSameDate("T10:15:3+01:00", "t_time_no_millis"); assertParseException("T10:15:3", "t_time_no_millis"); assertSameDate("2012-W48-6", "week_date"); assertSameDate("2012-W01-6", "week_date"); assertSameDate("2012-W1-6", "week_date"); // joda comes up with a different exception message here, so we have to adapt assertJodaParseException("2012-W1-8", "week_date", "Cannot parse \"2012-W1-8\": Value 8 for dayOfWeek must be in the range [1,7]"); assertJavaTimeParseException("2012-W1-8", "week_date"); assertSameDate("2012-W48-6T10:15:30.1Z", "week_date_time"); assertSameDate("2012-W48-6T10:15:30.123Z", "week_date_time"); assertSameDate("2012-W48-6T10:15:30.123456789Z", "week_date_time"); assertSameDate("2012-W48-6T10:15:30.1+0100", "week_date_time"); assertSameDate("2012-W48-6T10:15:30.123+0100", "week_date_time"); assertSameDate("2012-W48-6T10:15:30.1+01:00", "week_date_time"); assertSameDate("2012-W48-6T10:15:30.123+01:00", "week_date_time"); assertSameDate("2012-W1-6T10:15:30.1Z", "week_date_time"); assertSameDate("2012-W1-6T10:15:30.123Z", "week_date_time"); assertSameDate("2012-W1-6T10:15:30.1+0100", "week_date_time"); assertSameDate("2012-W1-6T10:15:30.123+0100", "week_date_time"); assertSameDate("2012-W1-6T10:15:30.1+01:00", "week_date_time"); assertSameDate("2012-W1-6T10:15:30.123+01:00", "week_date_time"); assertSameDate("2012-W48-6T10:15:30Z", "week_date_time_no_millis"); assertSameDate("2012-W48-6T10:15:30+0100", "week_date_time_no_millis"); assertSameDate("2012-W48-6T10:15:30+01:00", "week_date_time_no_millis"); assertSameDate("2012-W1-6T10:15:30Z", "week_date_time_no_millis"); assertSameDate("2012-W1-6T10:15:30+0100", "week_date_time_no_millis"); assertSameDate("2012-W1-6T10:15:30+01:00", "week_date_time_no_millis"); assertSameDate("2012", "year"); assertSameDate("1", "year"); assertSameDate("-2000", "year"); assertSameDate("2012-12", "yearMonth"); assertSameDate("1-1", "yearMonth"); assertSameDate("2012-12-31", "yearMonthDay"); assertSameDate("1-12-31", "yearMonthDay"); assertSameDate("2012-1-31", "yearMonthDay"); assertSameDate("2012-12-1", "yearMonthDay"); assertSameDate("2018", "weekyear"); assertSameDate("1", "weekyear"); assertSameDate("2017", "weekyear"); assertSameDate("2018-W29", "weekyear_week"); assertSameDate("2018-W1", "weekyear_week"); assertSameDate("2012-W31-5", "weekyear_week_day"); assertSameDate("2012-W1-1", "weekyear_week_day"); } public void testCompositeParsing() { // in all these examples the second pattern will be used assertSameDate("2014-06-06T12:01:02.123", "yyyy-MM-dd'T'HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSS"); assertSameDate("2014-06-06T12:01:02.123", "strictDateTimeNoMillis||yyyy-MM-dd'T'HH:mm:ss.SSS"); assertSameDate("2014-06-06T12:01:02.123", "yyyy-MM-dd'T'HH:mm:ss+HH:MM||yyyy-MM-dd'T'HH:mm:ss.SSS"); } public void testExceptionWhenCompositeParsingFails() { assertParseException("2014-06-06T12:01:02.123", "yyyy-MM-dd'T'HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SS"); } public void testDuelingStrictParsing() { assertSameDate("2018W313", "strict_basic_week_date"); assertParseException("18W313", "strict_basic_week_date"); assertSameDate("2018W313T121212.1Z", "strict_basic_week_date_time"); assertSameDate("2018W313T121212.123Z", "strict_basic_week_date_time"); assertSameDate("2018W313T121212.123456789Z", "strict_basic_week_date_time"); assertSameDate("2018W313T121212.1+0100", "strict_basic_week_date_time"); assertSameDate("2018W313T121212.123+0100", "strict_basic_week_date_time"); assertSameDate("2018W313T121212.1+01:00", "strict_basic_week_date_time"); assertSameDate("2018W313T121212.123+01:00", "strict_basic_week_date_time"); assertParseException("2018W313T12128.123Z", "strict_basic_week_date_time"); assertParseException("2018W313T12128.123456789Z", "strict_basic_week_date_time"); assertParseException("2018W313T81212.123Z", "strict_basic_week_date_time"); assertParseException("2018W313T12812.123Z", "strict_basic_week_date_time"); assertParseException("2018W313T12812.1Z", "strict_basic_week_date_time"); assertSameDate("2018W313T121212Z", "strict_basic_week_date_time_no_millis"); assertSameDate("2018W313T121212+0100", "strict_basic_week_date_time_no_millis"); assertSameDate("2018W313T121212+01:00", "strict_basic_week_date_time_no_millis"); assertParseException("2018W313T12128Z", "strict_basic_week_date_time_no_millis"); assertParseException("2018W313T12128+0100", "strict_basic_week_date_time_no_millis"); assertParseException("2018W313T12128+01:00", "strict_basic_week_date_time_no_millis"); assertParseException("2018W313T81212Z", "strict_basic_week_date_time_no_millis"); assertParseException("2018W313T81212+0100", "strict_basic_week_date_time_no_millis"); assertParseException("2018W313T81212+01:00", "strict_basic_week_date_time_no_millis"); assertParseException("2018W313T12812Z", "strict_basic_week_date_time_no_millis"); assertParseException("2018W313T12812+0100", "strict_basic_week_date_time_no_millis"); assertParseException("2018W313T12812+01:00", "strict_basic_week_date_time_no_millis"); assertSameDate("2018-12-31", "strict_date"); assertParseException("10000-12-31", "strict_date"); assertParseException("2018-8-31", "strict_date"); assertSameDate("2018-12-31T12", "strict_date_hour"); assertParseException("2018-12-31T8", "strict_date_hour"); assertSameDate("2018-12-31T12:12", "strict_date_hour_minute"); assertParseException("2018-12-31T8:3", "strict_date_hour_minute"); assertSameDate("2018-12-31T12:12:12", "strict_date_hour_minute_second"); assertParseException("2018-12-31T12:12:1", "strict_date_hour_minute_second"); assertSameDate("2018-12-31T12:12:12.1", "strict_date_hour_minute_second_fraction"); assertSameDate("2018-12-31T12:12:12.123", "strict_date_hour_minute_second_fraction"); assertSameDate("2018-12-31T12:12:12.123456789", "strict_date_hour_minute_second_fraction"); assertSameDate("2018-12-31T12:12:12.123", "strict_date_hour_minute_second_millis"); assertSameDate("2018-12-31T12:12:12.1", "strict_date_hour_minute_second_millis"); assertSameDate("2018-12-31T12:12:12.1", "strict_date_hour_minute_second_fraction"); assertParseException("2018-12-31T12:12:12", "strict_date_hour_minute_second_millis"); assertParseException("2018-12-31T12:12:12", "strict_date_hour_minute_second_fraction"); assertSameDate("2018-12-31", "strict_date_optional_time"); assertParseException("2018-12-1", "strict_date_optional_time"); assertParseException("2018-1-31", "strict_date_optional_time"); assertParseException("10000-01-31", "strict_date_optional_time"); assertSameDate("2010-01-05T02:00", "strict_date_optional_time"); assertSameDate("2018-12-31T10:15:30", "strict_date_optional_time"); assertSameDate("2018-12-31T10:15:30Z", "strict_date_optional_time"); assertSameDate("2018-12-31T10:15:30+0100", "strict_date_optional_time"); assertSameDate("2018-12-31T10:15:30+01:00", "strict_date_optional_time"); assertParseException("2018-12-31T10:15:3", "strict_date_optional_time"); assertParseException("2018-12-31T10:5:30", "strict_date_optional_time"); assertParseException("2018-12-31T9:15:30", "strict_date_optional_time"); assertSameDate("2015-01-04T00:00Z", "strict_date_optional_time"); assertSameDate("2018-12-31T10:15:30.1Z", "strict_date_time"); assertSameDate("2018-12-31T10:15:30.123Z", "strict_date_time"); assertSameDate("2018-12-31T10:15:30.123456789Z", "strict_date_time"); assertSameDate("2018-12-31T10:15:30.1+0100", "strict_date_time"); assertSameDate("2018-12-31T10:15:30.123+0100", "strict_date_time"); assertSameDate("2018-12-31T10:15:30.1+01:00", "strict_date_time"); assertSameDate("2018-12-31T10:15:30.123+01:00", "strict_date_time"); assertSameDate("2018-12-31T10:15:30.11Z", "strict_date_time"); assertSameDate("2018-12-31T10:15:30.11+0100", "strict_date_time"); assertSameDate("2018-12-31T10:15:30.11+01:00", "strict_date_time"); assertParseException("2018-12-31T10:15:3.123Z", "strict_date_time"); assertParseException("2018-12-31T10:5:30.123Z", "strict_date_time"); assertParseException("2018-12-31T1:15:30.123Z", "strict_date_time"); assertSameDate("2018-12-31T10:15:30Z", "strict_date_time_no_millis"); assertSameDate("2018-12-31T10:15:30+0100", "strict_date_time_no_millis"); assertSameDate("2018-12-31T10:15:30+01:00", "strict_date_time_no_millis"); assertParseException("2018-12-31T10:5:30Z", "strict_date_time_no_millis"); assertParseException("2018-12-31T10:15:3Z", "strict_date_time_no_millis"); assertParseException("2018-12-31T1:15:30Z", "strict_date_time_no_millis"); assertSameDate("12", "strict_hour"); assertSameDate("01", "strict_hour"); assertParseException("1", "strict_hour"); assertSameDate("12:12", "strict_hour_minute"); assertSameDate("12:01", "strict_hour_minute"); assertParseException("12:1", "strict_hour_minute"); assertSameDate("12:12:12", "strict_hour_minute_second"); assertSameDate("12:12:01", "strict_hour_minute_second"); assertParseException("12:12:1", "strict_hour_minute_second"); assertSameDate("12:12:12.123", "strict_hour_minute_second_fraction"); assertSameDate("12:12:12.123456789", "strict_hour_minute_second_fraction"); assertSameDate("12:12:12.1", "strict_hour_minute_second_fraction"); assertParseException("12:12:12", "strict_hour_minute_second_fraction"); assertSameDate("12:12:12.123", "strict_hour_minute_second_millis"); assertSameDate("12:12:12.1", "strict_hour_minute_second_millis"); assertParseException("12:12:12", "strict_hour_minute_second_millis"); assertSameDate("2018-128", "strict_ordinal_date"); assertParseException("2018-1", "strict_ordinal_date"); assertSameDate("2018-128T10:15:30.1Z", "strict_ordinal_date_time"); assertSameDate("2018-128T10:15:30.123Z", "strict_ordinal_date_time"); assertSameDate("2018-128T10:15:30.123456789Z", "strict_ordinal_date_time"); assertSameDate("2018-128T10:15:30.1+0100", "strict_ordinal_date_time"); assertSameDate("2018-128T10:15:30.123+0100", "strict_ordinal_date_time"); assertSameDate("2018-128T10:15:30.1+01:00", "strict_ordinal_date_time"); assertSameDate("2018-128T10:15:30.123+01:00", "strict_ordinal_date_time"); assertParseException("2018-1T10:15:30.123Z", "strict_ordinal_date_time"); assertSameDate("2018-128T10:15:30Z", "strict_ordinal_date_time_no_millis"); assertSameDate("2018-128T10:15:30+0100", "strict_ordinal_date_time_no_millis"); assertSameDate("2018-128T10:15:30+01:00", "strict_ordinal_date_time_no_millis"); assertParseException("2018-1T10:15:30Z", "strict_ordinal_date_time_no_millis"); assertSameDate("10:15:30.1Z", "strict_time"); assertSameDate("10:15:30.123Z", "strict_time"); assertSameDate("10:15:30.123456789Z", "strict_time"); assertSameDate("10:15:30.123+0100", "strict_time"); assertSameDate("10:15:30.123+01:00", "strict_time"); assertParseException("1:15:30.123Z", "strict_time"); assertParseException("10:1:30.123Z", "strict_time"); assertParseException("10:15:3.123Z", "strict_time"); assertParseException("10:15:3.1", "strict_time"); assertParseException("10:15:3Z", "strict_time"); assertSameDate("10:15:30Z", "strict_time_no_millis"); assertSameDate("10:15:30+0100", "strict_time_no_millis"); assertSameDate("10:15:30+01:00", "strict_time_no_millis"); assertSameDate("01:15:30Z", "strict_time_no_millis"); assertSameDate("01:15:30+0100", "strict_time_no_millis"); assertSameDate("01:15:30+01:00", "strict_time_no_millis"); assertParseException("1:15:30Z", "strict_time_no_millis"); assertParseException("10:5:30Z", "strict_time_no_millis"); assertParseException("10:15:3Z", "strict_time_no_millis"); assertParseException("10:15:3", "strict_time_no_millis"); assertSameDate("T10:15:30.1Z", "strict_t_time"); assertSameDate("T10:15:30.123Z", "strict_t_time"); assertSameDate("T10:15:30.123456789Z", "strict_t_time"); assertSameDate("T10:15:30.1+0100", "strict_t_time"); assertSameDate("T10:15:30.123+0100", "strict_t_time"); assertSameDate("T10:15:30.1+01:00", "strict_t_time"); assertSameDate("T10:15:30.123+01:00", "strict_t_time"); assertParseException("T1:15:30.123Z", "strict_t_time"); assertParseException("T10:1:30.123Z", "strict_t_time"); assertParseException("T10:15:3.123Z", "strict_t_time"); assertParseException("T10:15:3.1", "strict_t_time"); assertParseException("T10:15:3Z", "strict_t_time"); assertSameDate("T10:15:30Z", "strict_t_time_no_millis"); assertSameDate("T10:15:30+0100", "strict_t_time_no_millis"); assertSameDate("T10:15:30+01:00", "strict_t_time_no_millis"); assertParseException("T1:15:30Z", "strict_t_time_no_millis"); assertParseException("T10:1:30Z", "strict_t_time_no_millis"); assertParseException("T10:15:3Z", "strict_t_time_no_millis"); assertParseException("T10:15:3", "strict_t_time_no_millis"); assertSameDate("2012-W48-6", "strict_week_date"); assertSameDate("2012-W01-6", "strict_week_date"); assertParseException("2012-W1-6", "strict_week_date"); assertParseException("2012-W1-8", "strict_week_date"); assertSameDate("2012-W48-6", "strict_week_date"); assertSameDate("2012-W01-6", "strict_week_date"); assertParseException("2012-W1-6", "strict_week_date"); // joda comes up with a different exception message here, so we have to adapt assertJodaParseException( "2012-W01-8", "strict_week_date", "Cannot parse \"2012-W01-8\": Value 8 for dayOfWeek must be in the range [1,7]" ); assertJavaTimeParseException("2012-W01-8", "strict_week_date"); assertSameDate("2012-W48-6T10:15:30.1Z", "strict_week_date_time"); assertSameDate("2012-W48-6T10:15:30.123Z", "strict_week_date_time"); assertSameDate("2012-W48-6T10:15:30.123456789Z", "strict_week_date_time"); assertSameDate("2012-W48-6T10:15:30.1+0100", "strict_week_date_time"); assertSameDate("2012-W48-6T10:15:30.123+0100", "strict_week_date_time"); assertSameDate("2012-W48-6T10:15:30.1+01:00", "strict_week_date_time"); assertSameDate("2012-W48-6T10:15:30.123+01:00", "strict_week_date_time"); assertParseException("2012-W1-6T10:15:30.123Z", "strict_week_date_time"); assertSameDate("2012-W48-6T10:15:30Z", "strict_week_date_time_no_millis"); assertSameDate("2012-W48-6T10:15:30+0100", "strict_week_date_time_no_millis"); assertSameDate("2012-W48-6T10:15:30+01:00", "strict_week_date_time_no_millis"); assertParseException("2012-W1-6T10:15:30Z", "strict_week_date_time_no_millis"); assertSameDate("2012", "strict_year"); assertParseException("1", "strict_year"); assertSameDate("-2000", "strict_year"); assertSameDate("2012-12", "strict_year_month"); assertParseException("1-1", "strict_year_month"); assertSameDate("2012-12-31", "strict_year_month_day"); assertParseException("1-12-31", "strict_year_month_day"); assertParseException("2012-1-31", "strict_year_month_day"); assertParseException("2012-12-1", "strict_year_month_day"); assertSameDate("2018", "strict_weekyear"); assertParseException("1", "strict_weekyear"); assertSameDate("2018", "strict_weekyear"); assertSameDate("2017", "strict_weekyear"); assertParseException("1", "strict_weekyear"); assertSameDate("2018-W29", "strict_weekyear_week"); assertSameDate("2018-W01", "strict_weekyear_week"); assertParseException("2018-W1", "strict_weekyear_week"); assertSameDate("2012-W31-5", "strict_weekyear_week_day"); assertParseException("2012-W1-1", "strict_weekyear_week_day"); } public void testSamePrinterOutput() { int year = randomIntBetween(1970, 2030); int month = randomIntBetween(1, 12); int day = randomIntBetween(1, 28); int hour = randomIntBetween(0, 23); int minute = randomIntBetween(0, 59); int second = randomIntBetween(0, 59); ZonedDateTime javaDate = ZonedDateTime.of(year, month, day, hour, minute, second, 0, ZoneOffset.UTC); DateTime jodaDate = new DateTime(year, month, day, hour, minute, second, DateTimeZone.UTC); for (FormatNames format : FormatNames.values()) { if (format == FormatNames.ISO8601 || format == FormatNames.STRICT_DATE_OPTIONAL_TIME_NANOS) { // Nanos aren't supported by joda continue; } assertSamePrinterOutput(format.getSnakeCaseName(), javaDate, jodaDate); } } public void testSamePrinterOutputWithTimeZone() { String format = "strict_date_optional_time"; String dateInput = "2017-02-01T08:02:00.000-01:00"; DateFormatter javaFormatter = DateFormatter.forPattern(format); TemporalAccessor javaDate = javaFormatter.parse(dateInput); DateFormatter jodaFormatter = Joda.forPattern(format); DateTime dateTime = jodaFormatter.parseJoda(dateInput); String javaDateString = javaFormatter.withZone(ZoneOffset.ofHours(-1)).format(javaDate); String jodaDateString = jodaFormatter.withZone(ZoneOffset.ofHours(-1)).formatJoda(dateTime); String message = String.format( Locale.ROOT, "expected string representation to be equal for format [%s]: joda [%s], java [%s]", format, jodaDateString, javaDateString ); assertThat(message, javaDateString, is(jodaDateString)); } public void testDateFormatterWithLocale() { Locale locale = randomLocale(random()); String pattern = randomBoolean() ? "strict_date_optional_time||date_time" : "date_time||strict_date_optional_time"; DateFormatter formatter = DateFormatter.forPattern(pattern).withLocale(locale); assertThat(formatter.pattern(), is(pattern)); assertThat(formatter.locale(), is(locale)); } public void testSeveralTimeFormats() { { String format = "year_month_day||ordinal_date"; DateFormatter jodaFormatter = Joda.forPattern(format); DateFormatter javaFormatter = DateFormatter.forPattern(format); assertSameDate("2018-12-12", format, jodaFormatter, javaFormatter); assertSameDate("2018-128", format, jodaFormatter, javaFormatter); } { String format = "strictDateOptionalTime||dd-MM-yyyy"; DateFormatter jodaFormatter = Joda.forPattern(format); DateFormatter javaFormatter = DateFormatter.forPattern(format); assertSameDate("31-01-2014", format, jodaFormatter, javaFormatter); } } // the iso 8601 parser is available via Joda.forPattern(), so we have to test this slightly differently public void testIso8601Parsers() { String format = "iso8601"; org.joda.time.format.DateTimeFormatter isoFormatter = ISODateTimeFormat.dateTimeParser().withZone(DateTimeZone.UTC); JodaDateFormatter jodaFormatter = new JodaDateFormatter(format, isoFormatter, isoFormatter); DateFormatter javaFormatter = DateFormatter.forPattern(format); assertSameDate("2018-10-10", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10+0430", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11-08:00", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11Z", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11:12", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11:12+0100", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11:12.123", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11:12.123Z", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11:12.123+0000", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11:12,123", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11:12,123Z", format, jodaFormatter, javaFormatter); assertSameDate("2018-10-10T10:11:12,123+05:30", format, jodaFormatter, javaFormatter); } public void testParsingLocalDateFromYearOfEra() { // with strict resolving, YearOfEra expect an era, otherwise it won't resolve to a date assertSameDate("2018363", "yyyyDDD", Joda.forPattern("YYYYDDD"), DateFormatter.forPattern("uuuuDDD")); } public void testParsingMissingTimezone() { long millisJava = DateFormatter.forPattern("8yyyy-MM-dd HH:mm:ss").parseMillis("2018-02-18 17:47:17"); long millisJoda = DateFormatter.forPattern("yyyy-MM-dd HH:mm:ss").parseMillis("2018-02-18 17:47:17"); assertThat(millisJava, is(millisJoda)); } private void assertSamePrinterOutput(String format, ZonedDateTime javaDate, DateTime jodaDate) { DateFormatter dateFormatter = DateFormatter.forPattern(format); JodaDateFormatter jodaDateFormatter = Joda.forPattern(format); assertSamePrinterOutput(format, javaDate, jodaDate, dateFormatter, jodaDateFormatter); } private void assertSamePrinterOutput( String format, ZonedDateTime javaDate, DateTime jodaDate, DateFormatter dateFormatter, DateFormatter jodaDateFormatter ) { String javaTimeOut = dateFormatter.format(javaDate); String jodaTimeOut = jodaDateFormatter.formatJoda(jodaDate); assertThat(jodaDate.getMillis(), is(javaDate.toInstant().toEpochMilli())); String message = String.format( Locale.ROOT, "expected string representation to be equal for format [%s]: joda [%s], java [%s]", format, jodaTimeOut, javaTimeOut ); assertThat(message, javaTimeOut, is(jodaTimeOut)); } private void assertSameDate(String input, String format) { DateFormatter jodaFormatter = Joda.forPattern(format); DateFormatter javaFormatter = DateFormatter.forPattern(format); assertSameDate(input, format, jodaFormatter, javaFormatter); } private void assertSameDate(String input, String format, DateFormatter jodaFormatter, DateFormatter javaFormatter) { DateTime jodaDateTime = jodaFormatter.parseJoda(input); TemporalAccessor javaTimeAccessor = javaFormatter.parse(input); ZonedDateTime zonedDateTime = DateFormatters.from(javaTimeAccessor); String msg = String.format( Locale.ROOT, "Input [%s] Format [%s] Joda [%s], Java [%s]", input, format, jodaDateTime, DateTimeFormatter.ISO_INSTANT.format(zonedDateTime.toInstant()) ); assertThat(msg, jodaDateTime.getMillis(), is(zonedDateTime.toInstant().toEpochMilli())); } private void assertParseException(String input, String format) { assertJodaParseException(input, format, "Invalid format: \"" + input); assertJavaTimeParseException(input, format); } private void assertJodaParseException(String input, String format, String expectedMessage) { DateFormatter jodaFormatter = Joda.forPattern(format); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> jodaFormatter.parseJoda(input)); assertThat(e.getMessage(), containsString(expectedMessage)); } private void assertJavaTimeParseException(String input, String format) { DateFormatter javaTimeFormatter = DateFormatter.forPattern(format); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> javaTimeFormatter.parse(input)); assertThat(e.getMessage(), containsString(input)); assertThat(e.getMessage(), containsString(format)); } private void assertDateMathEquals(String text, String pattern) { long gotMillisJava = dateMathToMillis(text, DateFormatter.forPattern(pattern)); long gotMillisJoda = dateMathToMillis(text, Joda.forPattern(pattern)); assertEquals(gotMillisJoda, gotMillisJava); } private void assertSameDateAs(String input, String javaPattern, String jodaPattern) { DateFormatter javaFormatter = DateFormatter.forPattern(javaPattern); DateFormatter jodaFormatter = Joda.forPattern(jodaPattern); assertSameDate(input, javaPattern, jodaFormatter, javaFormatter); } }