mirror of
https://github.com/apache/commons-lang.git
synced 2025-02-08 02:58:33 +00:00
Added missing support for ISO 8601 parsing and printing using "ZZ" pattern (code now matches Javadoc). Addresses LANG-1000.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1628061 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2aae22de23
commit
22b6781a0b
@ -22,6 +22,7 @@
|
||||
<body>
|
||||
|
||||
<release version="3.4" date="tba" description="tba">
|
||||
<action issue="LANG-1000" type="fix" dev="djones">ParseException when trying to parse UTC dates with Z as zone designator using DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT</action>
|
||||
<action issue="LANG-1035" type="fix" dev="djones">Javadoc for EqualsBuilder.reflectionEquals() is unclear</action>
|
||||
<action issue="LANG-1020" type="update" dev="britter" due-to="Libor Ondrusek">Improve performance of normalize space</action>
|
||||
<action issue="LANG-1033" type="add" dev="ggregory">Add StringUtils.countMatches(CharSequence, char)</action>
|
||||
|
@ -513,6 +513,10 @@ private Strategy getStrategy(final String formatField, final Calendar definingCa
|
||||
case 'y':
|
||||
return formatField.length()>2 ?LITERAL_YEAR_STRATEGY :ABBREVIATED_YEAR_STRATEGY;
|
||||
case 'Z':
|
||||
if (formatField.equals("ZZ")) {
|
||||
return ISO_8601_STRATEGY;
|
||||
}
|
||||
//$FALL-THROUGH$
|
||||
case 'z':
|
||||
return getLocaleSpecificStrategy(Calendar.ZONE_OFFSET, definingCalendar);
|
||||
}
|
||||
@ -814,6 +818,32 @@ else if(value.startsWith("GMT")) {
|
||||
cal.setTimeZone(tz);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ISO8601TimeZoneStrategy extends Strategy {
|
||||
// Z, +hh, -hh, +hhmm, -hhmm, +hh:mm or -hh:mm
|
||||
private static final String PATTERN = "(Z|(?:[+-]\\d{2}(?::?\\d{2})?))";
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
boolean addRegex(FastDateParser parser, StringBuilder regex) {
|
||||
regex.append(PATTERN);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
void setCalendar(FastDateParser parser, Calendar cal, String value) {
|
||||
if (value.equals("Z")) {
|
||||
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
} else {
|
||||
cal.setTimeZone(TimeZone.getTimeZone("GMT" + value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final Strategy NUMBER_MONTH_STRATEGY = new NumberStrategy(Calendar.MONTH) {
|
||||
@Override
|
||||
@ -844,4 +874,5 @@ int modify(final int iValue) {
|
||||
private static final Strategy MINUTE_STRATEGY = new NumberStrategy(Calendar.MINUTE);
|
||||
private static final Strategy SECOND_STRATEGY = new NumberStrategy(Calendar.SECOND);
|
||||
private static final Strategy MILLISECOND_STRATEGY = new NumberStrategy(Calendar.MILLISECOND);
|
||||
private static final Strategy ISO_8601_STRATEGY = new ISO8601TimeZoneStrategy();
|
||||
}
|
||||
|
@ -274,6 +274,8 @@ protected List<Rule> parsePattern() {
|
||||
case 'Z': // time zone (value)
|
||||
if (tokenLen == 1) {
|
||||
rule = TimeZoneNumberRule.INSTANCE_NO_COLON;
|
||||
} else if (tokenLen == 2) {
|
||||
rule = TimeZoneNumberRule.INSTANCE_ISO_8601;
|
||||
} else {
|
||||
rule = TimeZoneNumberRule.INSTANCE_COLON;
|
||||
}
|
||||
@ -1173,18 +1175,22 @@ public void appendTo(final StringBuffer buffer, final Calendar calendar) {
|
||||
* or {@code +/-HH:MM}.</p>
|
||||
*/
|
||||
private static class TimeZoneNumberRule implements Rule {
|
||||
static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true);
|
||||
static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false);
|
||||
static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true, false);
|
||||
static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false, false);
|
||||
static final TimeZoneNumberRule INSTANCE_ISO_8601 = new TimeZoneNumberRule(true, true);
|
||||
|
||||
final boolean mColon;
|
||||
final boolean mISO8601;
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@code TimeZoneNumberRule} with the specified properties.
|
||||
*
|
||||
* @param colon add colon between HH and MM in the output if {@code true}
|
||||
* @param iso8601 create an ISO 8601 format output
|
||||
*/
|
||||
TimeZoneNumberRule(final boolean colon) {
|
||||
TimeZoneNumberRule(final boolean colon, final boolean iso8601) {
|
||||
mColon = colon;
|
||||
mISO8601 = iso8601;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1200,6 +1206,11 @@ public int estimateLength() {
|
||||
*/
|
||||
@Override
|
||||
public void appendTo(final StringBuffer buffer, final Calendar calendar) {
|
||||
if (mISO8601 && calendar.getTimeZone().getID().equals("UTC")) {
|
||||
buffer.append("Z");
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
|
||||
|
||||
if (offset < 0) {
|
||||
|
@ -17,10 +17,13 @@
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@ -103,7 +106,7 @@ public void testFormatUTC() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeISO(){
|
||||
public void testDateTimeISO() throws Exception {
|
||||
final TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
|
||||
final Calendar cal = Calendar.getInstance(timeZone);
|
||||
cal.set(2002,1,23,9,11,12);
|
||||
@ -124,6 +127,14 @@ public void testDateTimeISO(){
|
||||
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, 1, 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);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -249,4 +260,9 @@ public void testLang312() {
|
||||
}
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testLANG1000() throws Exception {
|
||||
String date = "2013-11-18T12:48:05Z";
|
||||
DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.parse(date);
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,7 @@
|
||||
*/
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
@ -286,4 +283,17 @@ public void testCalendarTimezoneRespected() {
|
||||
final String actualValue = FastDateFormat.getInstance(pattern).format(cal);
|
||||
assertEquals(expectedValue, actualValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeZoneAsZ() throws Exception {
|
||||
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
FastDateFormat noColonFormat = FastDateFormat.getInstance("Z");
|
||||
assertEquals("+0000", noColonFormat.format(c));
|
||||
|
||||
FastDateFormat isoFormat = FastDateFormat.getInstance("ZZ");
|
||||
assertEquals("Z", isoFormat.format(c));
|
||||
|
||||
FastDateFormat colonFormat = FastDateFormat.getInstance("ZZZ");
|
||||
assertEquals("+00:00", colonFormat.format(c));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user