diff --git a/src/changes/changes.xml b/src/changes/changes.xml index d75b9c635..a7320dfc7 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -22,6 +22,8 @@ + Unit test FastDatePrinterTimeZonesTest needs a timezone set + DateUtilsTest.testLang530 fails for some timezones DateUtilsTest.testLang530 fails for some timezones TypeUtils.ParameterizedType#equals doesn't work with wildcard types Add rotate(string, int) method to StringUtils diff --git a/src/main/java/org/apache/commons/lang3/time/DateFormatUtils.java b/src/main/java/org/apache/commons/lang3/time/DateFormatUtils.java index 4315e4742..17cd6e60a 100644 --- a/src/main/java/org/apache/commons/lang3/time/DateFormatUtils.java +++ b/src/main/java/org/apache/commons/lang3/time/DateFormatUtils.java @@ -43,6 +43,7 @@ public class DateFormatUtils { /** * ISO 8601 formatter for date-time without time zone. * The format used is {@code yyyy-MM-dd'T'HH:mm:ss}. + * This format uses the default TimeZone in effect at the time of loading DateFormatUtils class. */ public static final FastDateFormat ISO_DATETIME_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss"); @@ -50,6 +51,7 @@ public class DateFormatUtils { /** * ISO 8601 formatter for date-time with time zone. * The format used is {@code yyyy-MM-dd'T'HH:mm:ssZZ}. + * This format uses the default TimeZone in effect at the time of loading DateFormatUtils class. */ public static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ"); @@ -57,6 +59,7 @@ public class DateFormatUtils { /** * ISO 8601 formatter for date without time zone. * The format used is {@code yyyy-MM-dd}. + * This format uses the default TimeZone in effect at the time of loading DateFormatUtils class. */ public static final FastDateFormat ISO_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd"); @@ -66,6 +69,7 @@ public class DateFormatUtils { * The format used is {@code yyyy-MM-ddZZ}. * This pattern does not comply with the formal ISO 8601 specification * as the standard does not allow a time zone without a time. + * This format uses the default TimeZone in effect at the time of loading DateFormatUtils class. */ public static final FastDateFormat ISO_DATE_TIME_ZONE_FORMAT = FastDateFormat.getInstance("yyyy-MM-ddZZ"); @@ -73,6 +77,7 @@ public class DateFormatUtils { /** * ISO 8601 formatter for time without time zone. * The format used is {@code 'T'HH:mm:ss}. + * This format uses the default TimeZone in effect at the time of loading DateFormatUtils class. */ public static final FastDateFormat ISO_TIME_FORMAT = FastDateFormat.getInstance("'T'HH:mm:ss"); @@ -80,6 +85,7 @@ public class DateFormatUtils { /** * ISO 8601 formatter for time with time zone. * The format used is {@code 'T'HH:mm:ssZZ}. + * This format uses the default TimeZone in effect at the time of loading DateFormatUtils class. */ public static final FastDateFormat ISO_TIME_TIME_ZONE_FORMAT = FastDateFormat.getInstance("'T'HH:mm:ssZZ"); @@ -89,6 +95,7 @@ public class DateFormatUtils { * The format used is {@code HH:mm:ss}. * This pattern does not comply with the formal ISO 8601 specification * as the standard requires the 'T' prefix for times. + * This format uses the default TimeZone in effect at the time of loading DateFormatUtils class. */ public static final FastDateFormat ISO_TIME_NO_T_FORMAT = FastDateFormat.getInstance("HH:mm:ss"); @@ -98,6 +105,7 @@ public class DateFormatUtils { * The format used is {@code HH:mm:ssZZ}. * This pattern does not comply with the formal ISO 8601 specification * as the standard requires the 'T' prefix for times. + * This format uses the default TimeZone in effect at the time of loading DateFormatUtils class. */ public static final FastDateFormat ISO_TIME_NO_T_TIME_ZONE_FORMAT = FastDateFormat.getInstance("HH:mm:ssZZ"); @@ -105,6 +113,7 @@ public class DateFormatUtils { /** * SMTP (and probably other) date headers. * The format used is {@code EEE, dd MMM yyyy HH:mm:ss Z} in US locale. + * This format uses the default TimeZone in effect at the time of loading DateFormatUtils class. */ public static final FastDateFormat SMTP_DATETIME_FORMAT = FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US); diff --git a/src/main/java/org/apache/commons/lang3/time/DatePrinter.java b/src/main/java/org/apache/commons/lang3/time/DatePrinter.java index d1bfb91b9..68086285d 100644 --- a/src/main/java/org/apache/commons/lang3/time/DatePrinter.java +++ b/src/main/java/org/apache/commons/lang3/time/DatePrinter.java @@ -49,8 +49,11 @@ public interface DatePrinter { /** *

Formats a {@code Calendar} object.

+ * The TimeZone set on the Calendar is only used to adjust the time offset. + * The TimeZone specified during the construction of the Parser will determine the TimeZone + * used in the formatted string. * - * @param calendar the calendar to format + * @param calendar the calendar to format. * @return the formatted string */ String format(Calendar calendar); @@ -76,8 +79,10 @@ public interface DatePrinter { StringBuffer format(Date date, StringBuffer buf); /** - *

Formats a {@code Calendar} object into the - * supplied {@code StringBuffer}.

+ *

Formats a {@code Calendar} object into the supplied {@code StringBuffer}.

+ * The TimeZone set on the Calendar is only used to adjust the time offset. + * The TimeZone specified during the construction of the Parser will determine the TimeZone + * used in the formatted string. * * @param calendar the calendar to format * @param buf the buffer to format into diff --git a/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java b/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java index ac73646a9..4a20333ae 100644 --- a/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java +++ b/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java @@ -477,7 +477,8 @@ public class FastDatePrinter implements DatePrinter, Serializable { */ @Override public StringBuffer format(final Calendar calendar, final StringBuffer buf) { - return applyRules(calendar, buf); + // do not pass in calendar directly, this will cause TimeZone of FastDatePrinter to be ignored + return format(calendar.getTime(), buf); } /** diff --git a/src/test/java/org/apache/commons/lang3/time/DateFormatUtilsTest.java b/src/test/java/org/apache/commons/lang3/time/DateFormatUtilsTest.java index 5a1d69fa0..425ec6c50 100644 --- a/src/test/java/org/apache/commons/lang3/time/DateFormatUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/time/DateFormatUtilsTest.java @@ -108,132 +108,75 @@ public class DateFormatUtilsTest { assertEquals ("2005-01-01T12:00:00", DateFormatUtils.formatUTC(c.getTime().getTime(), DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), Locale.US)); } + + private void assertFormats(String expectedValue, String pattern, TimeZone timeZone, Calendar cal) { + assertEquals(expectedValue, DateFormatUtils.format(cal.getTime(), pattern, timeZone)); + assertEquals(expectedValue, DateFormatUtils.format(cal.getTime().getTime(), pattern, timeZone)); + assertEquals(expectedValue, DateFormatUtils.format(cal, pattern, timeZone)); + } + + private Calendar createFebruaryTestDate(final TimeZone timeZone) { + final Calendar cal = Calendar.getInstance(timeZone); + cal.set(2002, Calendar.FEBRUARY, 23, 9, 11, 12); + return cal; + } + + private Calendar createJuneTestDate(final TimeZone timeZone) { + final Calendar cal = Calendar.getInstance(timeZone); + cal.set(2003, Calendar.JUNE, 8, 10, 11, 12); + return cal; + } + + private void testGmtMinus3(String expectedValue, String pattern) { + final TimeZone timeZone = TimeZone.getTimeZone("GMT-3"); + assertFormats(expectedValue, pattern, timeZone, createFebruaryTestDate(timeZone)); + } + + private void testUTC(String expectedValue, String pattern) { + final TimeZone timeZone = TimeZone.getTimeZone("UTC"); + assertFormats(expectedValue, pattern, timeZone, createFebruaryTestDate(timeZone)); + } @Test public void testDateTimeISO() throws Exception { - final TimeZone timeZone = TimeZone.getTimeZone("GMT-3"); - final Calendar cal = Calendar.getInstance(timeZone); - cal.set(2002, Calendar.FEBRUARY, 23, 9, 11, 12); - String text = DateFormatUtils.format(cal.getTime(), - DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), timeZone); - assertEquals("2002-02-23T09:11:12", text); - text = DateFormatUtils.format(cal.getTime().getTime(), - DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), timeZone); - assertEquals("2002-02-23T09:11:12", text); - text = DateFormatUtils.ISO_DATETIME_FORMAT.format(cal); - assertEquals("2002-02-23T09:11:12", text); - - text = DateFormatUtils.format(cal.getTime(), - DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), timeZone); - assertEquals("2002-02-23T09:11:12-03:00", text); - text = DateFormatUtils.format(cal.getTime().getTime(), - DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), timeZone); - assertEquals("2002-02-23T09:11:12-03:00", text); - text = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(cal); - assertEquals("2002-02-23T09:11:12-03:00", text); - - Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - utcCal.set(2002, Calendar.FEBRUARY, 23, 9, 11, 12); - utcCal.set(Calendar.MILLISECOND, 0); - text = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(utcCal); - assertEquals("2002-02-23T09:11:12Z", text); - Date date = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.parse(text); - assertEquals(utcCal.getTime(), date); + testGmtMinus3("2002-02-23T09:11:12", DateFormatUtils.ISO_DATETIME_FORMAT.getPattern()); + testGmtMinus3("2002-02-23T09:11:12-03:00", DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern()); + testUTC("2002-02-23T09:11:12Z", DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern()); } @Test public void testDateISO(){ - final TimeZone timeZone = TimeZone.getTimeZone("GMT-3"); - final Calendar cal = Calendar.getInstance(timeZone); - cal.set(2002, Calendar.FEBRUARY, 23, 10, 11, 12); - String text = DateFormatUtils.format(cal.getTime(), - DateFormatUtils.ISO_DATE_FORMAT.getPattern(), timeZone); - assertEquals("2002-02-23", text); - text = DateFormatUtils.format(cal.getTime().getTime(), - DateFormatUtils.ISO_DATE_FORMAT.getPattern(), timeZone); - assertEquals("2002-02-23", text); - text = DateFormatUtils.ISO_DATE_FORMAT.format(cal); - assertEquals("2002-02-23", text); - - text = DateFormatUtils.format(cal.getTime(), - DateFormatUtils.ISO_DATE_TIME_ZONE_FORMAT.getPattern(), timeZone); - assertEquals("2002-02-23-03:00", text); - text = DateFormatUtils.format(cal.getTime().getTime(), - DateFormatUtils.ISO_DATE_TIME_ZONE_FORMAT.getPattern(), timeZone); - assertEquals("2002-02-23-03:00", text); - text = DateFormatUtils.ISO_DATE_TIME_ZONE_FORMAT.format(cal); - assertEquals("2002-02-23-03:00", text); + testGmtMinus3("2002-02-23", DateFormatUtils.ISO_DATE_FORMAT.getPattern()); + testGmtMinus3("2002-02-23-03:00", DateFormatUtils.ISO_DATE_TIME_ZONE_FORMAT.getPattern()); + testUTC("2002-02-23Z", DateFormatUtils.ISO_DATE_TIME_ZONE_FORMAT.getPattern()); } @Test public void testTimeISO(){ - final TimeZone timeZone = TimeZone.getTimeZone("GMT-3"); - final Calendar cal = Calendar.getInstance(timeZone); - cal.set(2002, Calendar.FEBRUARY, 23, 10, 11, 12); - String text = DateFormatUtils.format(cal.getTime(), - DateFormatUtils.ISO_TIME_FORMAT.getPattern(), timeZone); - assertEquals("T10:11:12", text); - text = DateFormatUtils.format(cal.getTime().getTime(), - DateFormatUtils.ISO_TIME_FORMAT.getPattern(), timeZone); - assertEquals("T10:11:12", text); - text = DateFormatUtils.ISO_TIME_FORMAT.format(cal); - assertEquals("T10:11:12", text); - - text = DateFormatUtils.format(cal.getTime(), - DateFormatUtils.ISO_TIME_TIME_ZONE_FORMAT.getPattern(), timeZone); - assertEquals("T10:11:12-03:00", text); - text = DateFormatUtils.format(cal.getTime().getTime(), - DateFormatUtils.ISO_TIME_TIME_ZONE_FORMAT.getPattern(), timeZone); - assertEquals("T10:11:12-03:00", text); - text = DateFormatUtils.ISO_TIME_TIME_ZONE_FORMAT.format(cal); - assertEquals("T10:11:12-03:00", text); + testGmtMinus3("T09:11:12", DateFormatUtils.ISO_TIME_FORMAT.getPattern()); + testGmtMinus3("T09:11:12-03:00", DateFormatUtils.ISO_TIME_TIME_ZONE_FORMAT.getPattern()); + testUTC("T09:11:12Z", DateFormatUtils.ISO_TIME_TIME_ZONE_FORMAT.getPattern()); } @Test public void testTimeNoTISO(){ - final TimeZone timeZone = TimeZone.getTimeZone("GMT-3"); - final Calendar cal = Calendar.getInstance(timeZone); - cal.set(2002, Calendar.FEBRUARY, 23, 10, 11, 12); - String text = DateFormatUtils.format(cal.getTime(), - DateFormatUtils.ISO_TIME_NO_T_FORMAT.getPattern(), timeZone); - assertEquals("10:11:12", text); - text = DateFormatUtils.format(cal.getTime().getTime(), - DateFormatUtils.ISO_TIME_NO_T_FORMAT.getPattern(), timeZone); - assertEquals("10:11:12", text); - text = DateFormatUtils.ISO_TIME_NO_T_FORMAT.format(cal); - assertEquals("10:11:12", text); - - text = DateFormatUtils.format(cal.getTime(), - DateFormatUtils.ISO_TIME_NO_T_TIME_ZONE_FORMAT.getPattern(), timeZone); - assertEquals("10:11:12-03:00", text); - text = DateFormatUtils.format(cal.getTime().getTime(), - DateFormatUtils.ISO_TIME_NO_T_TIME_ZONE_FORMAT.getPattern(), timeZone); - assertEquals("10:11:12-03:00", text); - text = DateFormatUtils.ISO_TIME_NO_T_TIME_ZONE_FORMAT.format(cal); - assertEquals("10:11:12-03:00", text); + testGmtMinus3("09:11:12", DateFormatUtils.ISO_TIME_NO_T_FORMAT.getPattern()); + testGmtMinus3("09:11:12-03:00", DateFormatUtils.ISO_TIME_NO_T_TIME_ZONE_FORMAT.getPattern()); + testUTC("09:11:12Z", DateFormatUtils.ISO_TIME_NO_T_TIME_ZONE_FORMAT.getPattern()); } @Test public void testSMTP(){ - final TimeZone timeZone = TimeZone.getTimeZone("GMT-3"); - final Calendar cal = Calendar.getInstance(timeZone); - cal.set(2003, Calendar.JUNE, 8, 10, 11, 12); - String text = DateFormatUtils.format(cal.getTime(), - DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), timeZone, - DateFormatUtils.SMTP_DATETIME_FORMAT.getLocale()); - assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text); - text = DateFormatUtils.format(cal.getTime().getTime(), - DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), timeZone, - DateFormatUtils.SMTP_DATETIME_FORMAT.getLocale()); - assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text); - text = DateFormatUtils.SMTP_DATETIME_FORMAT.format(cal); - assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text); + TimeZone timeZone = TimeZone.getTimeZone("GMT-3"); + Calendar june = createJuneTestDate(timeZone); - // format UTC - text = DateFormatUtils.formatUTC(cal.getTime().getTime(), - DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), - DateFormatUtils.SMTP_DATETIME_FORMAT.getLocale()); - assertEquals("Sun, 08 Jun 2003 13:11:12 +0000", text); + assertFormats("Sun, 08 Jun 2003 10:11:12 -0300", DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), + timeZone, june); + + timeZone = TimeZone.getTimeZone("UTC"); + june = createJuneTestDate(timeZone); + assertFormats("Sun, 08 Jun 2003 10:11:12 +0000", DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), + timeZone, june); } /* @@ -285,4 +228,46 @@ public class DateFormatUtilsTest { TimeZone.setDefault(save); } } + + /** + * According to LANG-916 (https://issues.apache.org/jira/browse/LANG-916), + * the format method did contain a bug: it did not use the TimeZone data. + * + * This method test that the bug is fixed. + */ + @Test + public void testLang916() throws Exception { + + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Paris")); + cal.clear(); + cal.set(2009, 9, 16, 8, 42, 16); + + // Long. + { + String value = DateFormatUtils.format(cal.getTimeInMillis(), DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), TimeZone.getTimeZone("Europe/Paris")); + assertEquals("long", "2009-10-16T08:42:16+02:00", value); + } + { + String value = DateFormatUtils.format(cal.getTimeInMillis(), DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), TimeZone.getTimeZone("Asia/Kolkata")); + assertEquals("long", "2009-10-16T12:12:16+05:30", value); + } + { + String value = DateFormatUtils.format(cal.getTimeInMillis(), DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), TimeZone.getTimeZone("Europe/London")); + assertEquals("long", "2009-10-16T07:42:16+01:00", value); + } + + // Calendar. + { + String value = DateFormatUtils.format(cal, DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), TimeZone.getTimeZone("Europe/Paris")); + assertEquals("calendar", "2009-10-16T08:42:16+02:00", value); + } + { + String value = DateFormatUtils.format(cal, DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), TimeZone.getTimeZone("Asia/Kolkata")); + assertEquals("calendar", "2009-10-16T12:12:16+05:30", value); + } + { + String value = DateFormatUtils.format(cal, DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), TimeZone.getTimeZone("Europe/London")); + assertEquals("calendar", "2009-10-16T07:42:16+01:00", value); + } + } } diff --git a/src/test/java/org/apache/commons/lang3/time/DurationFormatUtilsTest.java b/src/test/java/org/apache/commons/lang3/time/DurationFormatUtilsTest.java index 15456428a..6941f42f2 100644 --- a/src/test/java/org/apache/commons/lang3/time/DurationFormatUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/time/DurationFormatUtilsTest.java @@ -266,7 +266,7 @@ public class DurationFormatUtilsTest { cal.set(Calendar.MILLISECOND, 1); String text; // repeat a test from testDateTimeISO to compare extended and not extended. - text = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(cal); + text = DateFormatUtils.format(cal, DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern(), timeZone); assertEquals("2002-02-23T09:11:12-03:00", text); // test fixture is the same as above, but now with extended format. text = DurationFormatUtils.formatPeriod(base.getTime().getTime(), cal.getTime().getTime(), diff --git a/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java b/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java index f8b4930dc..5aaa67024 100644 --- a/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java +++ b/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java @@ -214,7 +214,7 @@ public class FastDatePrinterTest { final DatePrinter format = getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("GMT")); assertEquals("dateTime", "2009-10-16T16:42:16.000Z", format.format(cal.getTime())); - assertEquals("dateTime", "2009-10-16T08:42:16.000Z", format.format(cal)); + assertEquals("dateTime", "2009-10-16T16:42:16.000Z", format.format(cal)); } @Test @@ -339,4 +339,32 @@ public class FastDatePrinterTest { assertEquals("0002", getInstance("dddd", SWEDEN).format(cal)); assertEquals("00002", getInstance("ddddd", SWEDEN).format(cal)); } + + /** + * According to LANG-916 (https://issues.apache.org/jira/browse/LANG-916), + * the format method did contain a bug: it did not use the TimeZone data. + * + * This method test that the bug is fixed. + */ + @Test + public void testLang916() throws Exception { + + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Paris")); + cal.clear(); + cal.set(2009, 9, 16, 8, 42, 16); + + // calendar fast. + { + String value = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss Z", TimeZone.getTimeZone("Europe/Paris")).format(cal); + assertEquals("calendar", "2009-10-16T08:42:16 +0200", value); + } + { + String value = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss Z", TimeZone.getTimeZone("Asia/Kolkata")).format(cal); + assertEquals("calendar", "2009-10-16T12:12:16 +0530", value); + } + { + String value = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss Z", TimeZone.getTimeZone("Europe/London")).format(cal); + assertEquals("calendar", "2009-10-16T07:42:16 +0100", value); + } + } } diff --git a/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTimeZonesTest.java b/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTimeZonesTest.java index 34ff2f516..3ae5f5625 100644 --- a/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTimeZonesTest.java +++ b/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTimeZonesTest.java @@ -57,7 +57,7 @@ public class FastDatePrinterTimeZonesTest { final SimpleDateFormat sdf = new SimpleDateFormat(PATTERN); sdf.setTimeZone(timeZone); final String expectedValue = sdf.format(cal.getTime()); - final String actualValue = FastDateFormat.getInstance(PATTERN).format(cal); + final String actualValue = FastDateFormat.getInstance(PATTERN, this.timeZone).format(cal); assertEquals(expectedValue, actualValue); }