LANG-1116: DateUtilsTest.testLang530 fails for some timezones

This commit is contained in:
Chas Honton 2015-04-30 16:19:38 -07:00
parent cb83f7cb31
commit bea1ae92aa
4 changed files with 55 additions and 31 deletions

View File

@ -22,6 +22,7 @@
<body> <body>
<release version="3.5" date="tba" description="tba"> <release version="3.5" date="tba" description="tba">
<action issue="LANG-1116" type="fix" dev="chas" due-to="Aaron Sheldon">DateUtilsTest.testLang530 fails for some timezones</action>
<action issue="LANG-1114" type="fix" dev="britter" due-to="Andy Coates">TypeUtils.ParameterizedType#equals doesn't work with wildcard types</action> <action issue="LANG-1114" type="fix" dev="britter" due-to="Andy Coates">TypeUtils.ParameterizedType#equals doesn't work with wildcard types</action>
<action issue="LANG-1119" type="add" dev="britter" due-to="Loic Guibert">Add rotate(string, int) method to StringUtils</action> <action issue="LANG-1119" type="add" dev="britter" due-to="Loic Guibert">Add rotate(string, int) method to StringUtils</action>
<action issue="LANG-1118" type="fix" dev="britter" due-to="Loic Guibert">StringUtils.repeat('z', -1) throws NegativeArraySizeException</action> <action issue="LANG-1118" type="fix" dev="britter" due-to="Loic Guibert">StringUtils.repeat('z', -1) throws NegativeArraySizeException</action>

View File

@ -18,12 +18,12 @@ package org.apache.commons.lang3.time;
import java.text.ParseException; import java.text.ParseException;
import java.text.ParsePosition; import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.Locale; import java.util.Locale;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@ -366,37 +366,21 @@ public class DateUtils {
throw new IllegalArgumentException("Date and Patterns must not be null"); throw new IllegalArgumentException("Date and Patterns must not be null");
} }
SimpleDateFormat parser; final TimeZone tz = TimeZone.getDefault();
if (locale == null) { final Locale lcl = locale==null ?Locale.getDefault() : locale;
parser = new SimpleDateFormat();
} else {
parser = new SimpleDateFormat("", locale);
}
parser.setLenient(lenient);
final ParsePosition pos = new ParsePosition(0); final ParsePosition pos = new ParsePosition(0);
for (final String parsePattern : parsePatterns) { for (final String parsePattern : parsePatterns) {
FastDateParser fdp = new FastDateParser(parsePattern, tz, lcl, null, lenient);
String pattern = parsePattern; try {
Date date = fdp.parse(str, pos);
// LANG-530 - need to make sure 'ZZ' output doesn't get passed to SimpleDateFormat if (pos.getIndex() == str.length()) {
if (parsePattern.endsWith("ZZ")) {
pattern = pattern.substring(0, pattern.length() - 1);
}
parser.applyPattern(pattern);
pos.setIndex(0);
String str2 = str;
// LANG-530 - need to make sure 'ZZ' output doesn't hit SimpleDateFormat as it will ParseException
if (parsePattern.endsWith("ZZ")) {
str2 = str.replaceAll("([-+][0-9][0-9]):([0-9][0-9])$", "$1$2");
}
final Date date = parser.parse(str2, pos);
if (date != null && pos.getIndex() == str2.length()) {
return date; return date;
} }
pos.setIndex(0);
}
catch(IllegalArgumentException iae) {
}
} }
throw new ParseException("Unable to parse the date: " + str, -1); throw new ParseException("Unable to parse the date: " + str, -1);
} }

View File

@ -75,7 +75,7 @@ public class FastDateParser implements DateParser, Serializable {
* *
* @see java.io.Serializable * @see java.io.Serializable
*/ */
private static final long serialVersionUID = 2L; private static final long serialVersionUID = 3L;
static final Locale JAPANESE_IMPERIAL = new Locale("ja","JP","JP"); static final Locale JAPANESE_IMPERIAL = new Locale("ja","JP","JP");
@ -85,6 +85,7 @@ public class FastDateParser implements DateParser, Serializable {
private final Locale locale; private final Locale locale;
private final int century; private final int century;
private final int startYear; private final int startYear;
private final boolean lenient;
// derived fields // derived fields
private transient Pattern parsePattern; private transient Pattern parsePattern;
@ -106,7 +107,7 @@ public class FastDateParser implements DateParser, Serializable {
* @param locale non-null locale * @param locale non-null locale
*/ */
protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale) { protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale) {
this(pattern, timeZone, locale, null); this(pattern, timeZone, locale, null, true);
} }
/** /**
@ -121,11 +122,31 @@ public class FastDateParser implements DateParser, Serializable {
* @since 3.3 * @since 3.3
*/ */
protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) { protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) {
this(pattern, timeZone, locale, centuryStart, true);
}
/**
* <p>Constructs a new FastDateParser.</p>
*
* @param pattern non-null {@link java.text.SimpleDateFormat} compatible
* pattern
* @param timeZone non-null time zone to use
* @param locale non-null locale
* @param centuryStart The start of the century for 2 digit year parsing
* @param lenient if true, non-standard values for Calendar fields should be accepted;
* if false, non-standard values will cause a ParseException to be thrown {@link CalendaretLenient(boolean)}
*
* @since 3.5
*/
protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale,
final Date centuryStart, final boolean lenient) {
this.pattern = pattern; this.pattern = pattern;
this.timeZone = timeZone; this.timeZone = timeZone;
this.locale = locale; this.locale = locale;
this.lenient = lenient;
final Calendar definingCalendar = Calendar.getInstance(timeZone, locale); final Calendar definingCalendar = Calendar.getInstance(timeZone, locale);
int centuryStartYear; int centuryStartYear;
if(centuryStart!=null) { if(centuryStart!=null) {
definingCalendar.setTime(centuryStart); definingCalendar.setTime(centuryStart);
@ -336,6 +357,7 @@ public class FastDateParser implements DateParser, Serializable {
// timing tests indicate getting new instance is 19% faster than cloning // timing tests indicate getting new instance is 19% faster than cloning
final Calendar cal= Calendar.getInstance(timeZone, locale); final Calendar cal= Calendar.getInstance(timeZone, locale);
cal.clear(); cal.clear();
cal.setLenient(lenient);
for(int i=0; i<strategies.length;) { for(int i=0; i<strategies.length;) {
final Strategy strategy= strategies[i++]; final Strategy strategy= strategies[i++];

View File

@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.text.ParseException;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
@ -268,4 +269,20 @@ public class DateFormatUtilsTest {
String date = "2013-11-18T12:48:05Z"; String date = "2013-11-18T12:48:05Z";
DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.parse(date); DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.parse(date);
} }
@Test
public void testLang530() throws ParseException {
TimeZone save = TimeZone.getDefault();
try {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
final Date d = new Date();
final String isoDateStr = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(d);
final Date d2 = DateUtils.parseDate(isoDateStr, new String[] { DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern() });
// the format loses milliseconds so have to reintroduce them
assertEquals("Date not equal to itself ISO formatted and parsed", d.getTime(), d2.getTime() + d.getTime() % 1000);
}
finally {
TimeZone.setDefault(save);
}
}
} }