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>
<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-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>

View File

@ -18,12 +18,12 @@ package org.apache.commons.lang3.time;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
/**
@ -366,36 +366,20 @@ public class DateUtils {
throw new IllegalArgumentException("Date and Patterns must not be null");
}
SimpleDateFormat parser;
if (locale == null) {
parser = new SimpleDateFormat();
} else {
parser = new SimpleDateFormat("", locale);
}
parser.setLenient(lenient);
final TimeZone tz = TimeZone.getDefault();
final Locale lcl = locale==null ?Locale.getDefault() : locale;
final ParsePosition pos = new ParsePosition(0);
for (final String parsePattern : parsePatterns) {
String pattern = parsePattern;
// LANG-530 - need to make sure 'ZZ' output doesn't get passed to SimpleDateFormat
if (parsePattern.endsWith("ZZ")) {
pattern = pattern.substring(0, pattern.length() - 1);
FastDateParser fdp = new FastDateParser(parsePattern, tz, lcl, null, lenient);
try {
Date date = fdp.parse(str, pos);
if (pos.getIndex() == str.length()) {
return date;
}
pos.setIndex(0);
}
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;
catch(IllegalArgumentException iae) {
}
}
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
*/
private static final long serialVersionUID = 2L;
private static final long serialVersionUID = 3L;
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 int century;
private final int startYear;
private final boolean lenient;
// derived fields
private transient Pattern parsePattern;
@ -106,7 +107,7 @@ public class FastDateParser implements DateParser, Serializable {
* @param locale non-null 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
*/
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.timeZone = timeZone;
this.locale = locale;
this.lenient = lenient;
final Calendar definingCalendar = Calendar.getInstance(timeZone, locale);
int centuryStartYear;
if(centuryStart!=null) {
definingCalendar.setTime(centuryStart);
@ -336,6 +357,7 @@ public class FastDateParser implements DateParser, Serializable {
// timing tests indicate getting new instance is 19% faster than cloning
final Calendar cal= Calendar.getInstance(timeZone, locale);
cal.clear();
cal.setLenient(lenient);
for(int i=0; i<strategies.length;) {
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.Modifier;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
@ -268,4 +269,20 @@ public class DateFormatUtilsTest {
String date = "2013-11-18T12:48:05Z";
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);
}
}
}