You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Benedikt Ritter <br...@apache.org> on 2015/03/23 07:56:03 UTC
Re: svn commit: r1668511 - in /commons/proper/lang/trunk/src:
main/java/org/apache/commons/lang3/time/ test/java/org/apache/commons/lang3/time/
Charles, I think I've told you this several times now. Please add issues
you fix to changes.xml! This is necessary to automatically create release
notes.
Thank you.
Benedikt
2015-03-23 3:33 GMT+01:00 <ch...@apache.org>:
> Author: chas
> Date: Mon Mar 23 02:33:41 2015
> New Revision: 1668511
>
> URL: http://svn.apache.org/r1668511
> Log:
> LANG-1101 FastDateParser and FastDatePrinter support 'X' format
>
> Modified:
>
> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>
> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>
> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
>
> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
>
> Modified:
> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
> URL:
> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>
> ==============================================================================
> ---
> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
> (original)
> +++
> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
> Mon Mar 23 02:33:41 2015
> @@ -96,7 +96,10 @@ public class FastDateParser implements D
>
> /**
> * <p>Constructs a new FastDateParser.</p>
> - *
> + *
> + * Use {@link FastDateFormat#getInstance(String, TimeZone, Locale)}
> or another variation of the
> + * factory methods of {@link FastDateFormat} to get a cached
> FastDateParser instance.
> + *
> * @param pattern non-null {@link java.text.SimpleDateFormat}
> compatible
> * pattern
> * @param timeZone non-null time zone to use
> @@ -467,13 +470,14 @@ public class FastDateParser implements D
> * false, if this field is a constant value
> */
> abstract boolean addRegex(FastDateParser parser, StringBuilder
> regex);
> +
> }
>
> /**
> * A <code>Pattern</code> to parse the user supplied SimpleDateFormat
> pattern
> */
> private static final Pattern formatPattern= Pattern.compile(
> -
> "D+|E+|F+|G+|H+|K+|M+|S+|W+|Z+|a+|d+|h+|k+|m+|s+|w+|y+|z+|''|'[^']++(''[^']*+)*+'|[^'A-Za-z]++");
> +
> "D+|E+|F+|G+|H+|K+|M+|S+|W+|X+|Z+|a+|d+|h+|k+|m+|s+|w+|y+|z+|''|'[^']++(''[^']*+)*+'|[^'A-Za-z]++");
>
> /**
> * Obtain a Strategy given a field from a SimpleDateFormat pattern
> @@ -524,6 +528,8 @@ public class FastDateParser implements D
> return WEEK_OF_YEAR_STRATEGY;
> case 'y':
> return formatField.length()>2 ?LITERAL_YEAR_STRATEGY
> :ABBREVIATED_YEAR_STRATEGY;
> + case 'X':
> + return
> ISO8601TimeZoneStrategy.getStrategy(formatField.length());
> case 'Z':
> if (formatField.equals("ZZ")) {
> return ISO_8601_STRATEGY;
> @@ -834,14 +840,18 @@ public class FastDateParser implements D
>
> 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})?))";
> + private final String pattern;
> +
> + ISO8601TimeZoneStrategy(String pattern) {
> + this.pattern = pattern;
> + }
>
> /**
> * {@inheritDoc}
> */
> @Override
> boolean addRegex(FastDateParser parser, StringBuilder regex) {
> - regex.append(PATTERN);
> + regex.append(pattern);
> return true;
> }
>
> @@ -856,6 +866,23 @@ public class FastDateParser implements D
> cal.setTimeZone(TimeZone.getTimeZone("GMT" + value));
> }
> }
> +
> + private static final Strategy ISO_8601_1_STRATEGY = new
> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}))");
> + private static final Strategy ISO_8601_2_STRATEGY = new
> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}\\d{2}))");
> + private static final Strategy ISO_8601_3_STRATEGY = new
> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::)\\d{2}))");
> +
> + static Strategy getStrategy(int tokenLen) {
> + switch(tokenLen) {
> + case 1:
> + return ISO_8601_1_STRATEGY;
> + case 2:
> + return ISO_8601_2_STRATEGY;
> + case 3:
> + return ISO_8601_3_STRATEGY;
> + default:
> + throw new IllegalArgumentException("invalid number
> of X");
> + }
> + }
> }
>
> private static final Strategy NUMBER_MONTH_STRATEGY = new
> NumberStrategy(Calendar.MONTH) {
> @@ -887,5 +914,7 @@ public class FastDateParser implements D
> 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();
> + private static final Strategy ISO_8601_STRATEGY = new
> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::?\\d{2})?))");
> +
> +
> }
>
> Modified:
> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
> URL:
> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>
> ==============================================================================
> ---
> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
> (original)
> +++
> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
> Mon Mar 23 02:33:41 2015
> @@ -38,7 +38,7 @@ import org.apache.commons.lang3.Validate
> * <p>FastDatePrinter is a fast and thread-safe version of
> * {@link java.text.SimpleDateFormat}.</p>
> *
> - * <p>To obtain a proxy to a FastDatePrinter, use {@link
> FastDateFormat#getInstance(String, TimeZone, Locale)}
> + * <p>To obtain a FastDatePrinter, use {@link
> FastDateFormat#getInstance(String, TimeZone, Locale)}
> * or another variation of the factory methods of {@link
> FastDateFormat}.</p>
> *
> * <p>Since FastDatePrinter is thread safe, you can use a static member
> instance:</p>
> @@ -64,6 +64,10 @@ import org.apache.commons.lang3.Validate
> * ISO 8601 full format time zones (eg. {@code +08:00} or {@code -11:00}).
> * This introduces a minor incompatibility with Java 1.4, but at a gain of
> * useful functionality.</p>
> + *
> + * <p>Starting with JDK7, ISO 8601 support was added using the pattern
> {@code 'X'}.
> + * To maintain compatibility, {@code 'ZZ'} will continue to be supported,
> but using
> + * one of the {@code 'X'} formats is recommended.
> *
> * <p>Javadoc cites for the year pattern: <i>For formatting, if the
> number of
> * pattern letters is 2, the year is truncated to 2 digits; otherwise it
> is
> @@ -137,6 +141,8 @@ public class FastDatePrinter implements
>
> //-----------------------------------------------------------------------
> /**
> * <p>Constructs a new FastDatePrinter.</p>
> + * Use {@link FastDateFormat#getInstance(String, TimeZone, Locale)}
> or another variation of the
> + * factory methods of {@link FastDateFormat} to get a cached
> FastDatePrinter instance.
> *
> * @param pattern {@link java.text.SimpleDateFormat} compatible
> pattern
> * @param timeZone non-null time zone to use
> @@ -265,6 +271,9 @@ public class FastDatePrinter implements
> case 'K': // hour in am/pm (0..11)
> rule = selectNumberRule(Calendar.HOUR, tokenLen);
> break;
> + case 'X': // ISO 8601
> + rule = Iso8601_Rule.getRule(tokenLen);
> + break;
> case 'z': // time zone (text)
> if (tokenLen >= 4) {
> rule = new TimeZoneNameRule(mTimeZone, mLocale,
> TimeZone.LONG);
> @@ -581,6 +590,11 @@ public class FastDatePrinter implements
> init();
> }
>
> + private static void appendDigits(final StringBuffer buffer, final
> int value) {
> + buffer.append((char)(value / 10 + '0'));
> + buffer.append((char)(value % 10 + '0'));
> + }
> +
> // Rules
>
> //-----------------------------------------------------------------------
> /**
> @@ -588,7 +602,7 @@ public class FastDatePrinter implements
> */
> private interface Rule {
> /**
> - * Returns the estimated lentgh of the result.
> + * Returns the estimated length of the result.
> *
> * @return the estimated length
> */
> @@ -810,8 +824,7 @@ public class FastDatePrinter implements
> if (value < 10) {
> buffer.append((char)(value + '0'));
> } else {
> - buffer.append((char)(value / 10 + '0'));
> - buffer.append((char)(value % 10 + '0'));
> + appendDigits(buffer, value);
> }
> }
> }
> @@ -863,8 +876,7 @@ public class FastDatePrinter implements
> for (int i = mSize; --i >= 2; ) {
> buffer.append('0');
> }
> - buffer.append((char)(value / 10 + '0'));
> - buffer.append((char)(value % 10 + '0'));
> + appendDigits(buffer, value);
> } else {
> int digits;
> if (value < 1000) {
> @@ -918,8 +930,7 @@ public class FastDatePrinter implements
> @Override
> public final void appendTo(final StringBuffer buffer, final int
> value) {
> if (value < 100) {
> - buffer.append((char)(value / 10 + '0'));
> - buffer.append((char)(value % 10 + '0'));
> + appendDigits(buffer, value);
> } else {
> buffer.append(Integer.toString(value));
> }
> @@ -960,8 +971,7 @@ public class FastDatePrinter implements
> */
> @Override
> public final void appendTo(final StringBuffer buffer, final int
> value) {
> - buffer.append((char)(value / 10 + '0'));
> - buffer.append((char)(value % 10 + '0'));
> + appendDigits(buffer, value);
> }
> }
>
> @@ -999,8 +1009,7 @@ public class FastDatePrinter implements
> */
> @Override
> public final void appendTo(final StringBuffer buffer, final int
> value) {
> - buffer.append((char)(value / 10 + '0'));
> - buffer.append((char)(value % 10 + '0'));
> + appendDigits(buffer, value);
> }
> }
>
> @@ -1121,7 +1130,7 @@ public class FastDatePrinter implements
> return value;
> }
>
> - /**
> + /**
> * <p>Inner class to output a time zone name.</p>
> */
> private static class TimeZoneNameRule implements Rule {
> @@ -1178,7 +1187,7 @@ public class FastDatePrinter implements
> 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;
>
> @@ -1221,16 +1230,95 @@ public class FastDatePrinter implements
> }
>
> final int hours = offset / (60 * 60 * 1000);
> - buffer.append((char)(hours / 10 + '0'));
> - buffer.append((char)(hours % 10 + '0'));
> + appendDigits(buffer, hours);
>
> if (mColon) {
> buffer.append(':');
> }
>
> final int minutes = offset / (60 * 1000) - 60 * hours;
> - buffer.append((char)(minutes / 10 + '0'));
> - buffer.append((char)(minutes % 10 + '0'));
> + appendDigits(buffer, minutes);
> + }
> + }
> +
> + /**
> + * <p>Inner class to output a time zone as a number {@code +/-HHMM}
> + * or {@code +/-HH:MM}.</p>
> + */
> + private static class Iso8601_Rule implements Rule {
> +
> + // Sign TwoDigitHours or Z
> + static final Iso8601_Rule ISO8601_HOURS = new Iso8601_Rule(3);
> + // Sign TwoDigitHours Minutes or Z
> + static final Iso8601_Rule ISO8601_HOURS_MINUTES = new
> Iso8601_Rule(5);
> + // Sign TwoDigitHours : Minutes or Z
> + static final Iso8601_Rule ISO8601_HOURS_COLON_MINUTES = new
> Iso8601_Rule(6);
> +
> + static Iso8601_Rule getRule(int tokenLen) {
> + switch(tokenLen) {
> + case 1:
> + return Iso8601_Rule.ISO8601_HOURS;
> + case 2:
> + return Iso8601_Rule.ISO8601_HOURS_MINUTES;
> + case 3:
> + return Iso8601_Rule.ISO8601_HOURS_COLON_MINUTES;
> + default:
> + throw new IllegalArgumentException("invalid number
> of X");
> + }
> + }
> +
> + final int length;
> +
> + /**
> + * Constructs an instance of {@code Iso8601_Rule} with the
> specified properties.
> + *
> + * @param length The number of characters in output (unless Z is
> output)
> + */
> + Iso8601_Rule(final int length) {
> + this.length = length;
> + }
> +
> + /**
> + * {@inheritDoc}
> + */
> + @Override
> + public int estimateLength() {
> + return length;
> + }
> +
> + /**
> + * {@inheritDoc}
> + */
> + @Override
> + public void appendTo(final StringBuffer buffer, final Calendar
> calendar) {
> + int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
> + if (zoneOffset == 0) {
> + buffer.append("Z");
> + return;
> + }
> +
> + int offset = zoneOffset + calendar.get(Calendar.DST_OFFSET);
> +
> + if (offset < 0) {
> + buffer.append('-');
> + offset = -offset;
> + } else {
> + buffer.append('+');
> + }
> +
> + final int hours = offset / (60 * 60 * 1000);
> + appendDigits(buffer, hours);
> +
> + if (length<5) {
> + return;
> + }
> +
> + if (length==6) {
> + buffer.append(':');
> + }
> +
> + final int minutes = offset / (60 * 1000) - 60 * hours;
> + appendDigits(buffer, minutes);
> }
> }
>
>
> Modified:
> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
> URL:
> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>
> ==============================================================================
> ---
> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
> (original)
> +++
> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
> Mon Mar 23 02:33:41 2015
> @@ -56,6 +56,7 @@ public class FastDateParserTest {
> private static final TimeZone REYKJAVIK =
> TimeZone.getTimeZone("Atlantic/Reykjavik");
> private static final TimeZone NEW_YORK =
> TimeZone.getTimeZone("America/New_York");
> private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
> + private static final TimeZone INDIA =
> TimeZone.getTimeZone("Asia/Calcutta");
>
> private static final Locale SWEDEN = new Locale("sv", "SE");
>
> @@ -556,4 +557,63 @@ public class FastDateParserTest {
> assertEquals(expected.getTime(), fdp.parse("14MAY2014"));
> assertEquals(expected.getTime(), fdp.parse("14May2014"));
> }
> +
> + @Test(expected = IllegalArgumentException.class)
> + public void test1806Argument() {
> + getInstance("XXXX");
> + }
> +
> + private static Calendar initializeCalendar(TimeZone tz) {
> + Calendar cal = Calendar.getInstance(tz);
> + cal.set(Calendar.YEAR, 2001);
> + cal.set(Calendar.MONTH, 1); // not daylight savings
> + cal.set(Calendar.DAY_OF_MONTH, 4);
> + cal.set(Calendar.HOUR_OF_DAY, 12);
> + cal.set(Calendar.MINUTE, 8);
> + cal.set(Calendar.SECOND, 56);
> + cal.set(Calendar.MILLISECOND, 235);
> + return cal;
> + }
> +
> + private static enum Expected1806 {
> + India(INDIA, "+05", "+0530", "+05:30", true),
> + Greenwich(GMT, "Z", "Z", "Z", false),
> + NewYork(NEW_YORK, "-05", "-0500", "-05:00", false);
> +
> + private Expected1806(TimeZone zone, String one, String
> two, String three, boolean hasHalfHourOffset) {
> + this.zone = zone;
> + this.one = one;
> + this.two = two;
> + this.three = three;
> + this.offset = hasHalfHourOffset ?30*60*1000 :0;
> + }
> +
> + final TimeZone zone;
> + final String one;
> + final String two;
> + final String three;
> + final long offset;
> + }
> +
> + @Test
> + public void test1806() throws ParseException {
> + String formatStub = "yyyy-MM-dd'T'HH:mm:ss.SSS";
> + String dateStub = "2001-02-04T12:08:56.235";
> +
> + for (Expected1806 trial : Expected1806.values()) {
> + Calendar cal = initializeCalendar(trial.zone);
> +
> + String message = trial.zone.getDisplayName()+";";
> +
> + DateParser parser = getInstance(formatStub+"X",
> trial.zone);
> + assertEquals(message+trial.one,
> cal.getTime().getTime(),
> parser.parse(dateStub+trial.one).getTime()-trial.offset);
> +
> + parser = getInstance(formatStub+"XX", trial.zone);
> + assertEquals(message+trial.two, cal.getTime(),
> parser.parse(dateStub+trial.two));
> +
> + parser = getInstance(formatStub+"XXX", trial.zone);
> + assertEquals(message+trial.three, cal.getTime(),
> parser.parse(dateStub+trial.three));
> + }
> + }
> +
> }
>
> Modified:
> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
> URL:
> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>
> ==============================================================================
> ---
> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
> (original)
> +++
> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
> Mon Mar 23 02:33:41 2015
> @@ -19,6 +19,7 @@ package org.apache.commons.lang3.time;
> import static org.junit.Assert.*;
>
> import java.io.Serializable;
> +import java.text.ParseException;
> import java.text.SimpleDateFormat;
> import java.util.Calendar;
> import java.util.Date;
> @@ -39,6 +40,8 @@ public class FastDatePrinterTest {
>
> private static final String YYYY_MM_DD = "yyyy/MM/dd";
> private static final TimeZone NEW_YORK =
> TimeZone.getTimeZone("America/New_York");
> + private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
> + private static final TimeZone INDIA =
> TimeZone.getTimeZone("Asia/Calcutta");
> private static final Locale SWEDEN = new Locale("sv", "SE");
>
> DatePrinter getInstance(final String format) {
> @@ -272,4 +275,55 @@ public class FastDatePrinterTest {
> FastDateFormat colonFormat = FastDateFormat.getInstance("ZZZ");
> assertEquals("+00:00", colonFormat.format(c));
> }
> +
> + private static Calendar initializeCalendar(TimeZone tz) {
> + Calendar cal = Calendar.getInstance(tz);
> + cal.set(Calendar.YEAR, 2001);
> + cal.set(Calendar.MONTH, 1); // not daylight savings
> + cal.set(Calendar.DAY_OF_MONTH, 4);
> + cal.set(Calendar.HOUR_OF_DAY, 12);
> + cal.set(Calendar.MINUTE, 8);
> + cal.set(Calendar.SECOND, 56);
> + cal.set(Calendar.MILLISECOND, 235);
> + return cal;
> + }
> +
> + @Test(expected = IllegalArgumentException.class)
> + public void test1806Argument() {
> + getInstance("XXXX");
> + }
> +
> + private static enum Expected1806 {
> + India(INDIA, "+05", "+0530", "+05:30"), Greenwich(GMT,
> "Z", "Z", "Z"), NewYork(
> + NEW_YORK, "-05", "-0500", "-05:00");
> +
> + private Expected1806(TimeZone zone, String one, String
> two, String three) {
> + this.zone = zone;
> + this.one = one;
> + this.two = two;
> + this.three = three;
> + }
> +
> + final TimeZone zone;
> + final String one;
> + final String two;
> + final String three;
> + }
> +
> +
> + @Test
> + public void test1806() throws ParseException {
> + for (Expected1806 trial : Expected1806.values()) {
> + Calendar cal = initializeCalendar(trial.zone);
> +
> + DatePrinter printer = getInstance("X", trial.zone);
> + assertEquals(trial.one, printer.format(cal));
> +
> + printer = getInstance("XX", trial.zone);
> + assertEquals(trial.two, printer.format(cal));
> +
> + printer = getInstance("XXX", trial.zone);
> + assertEquals(trial.three, printer.format(cal));
> + }
> + }
> }
>
>
>
--
http://people.apache.org/~britter/
http://www.systemoutprintln.de/
http://twitter.com/BenediktRitter
http://github.com/britter
Re: svn commit: r1668511 - in /commons/proper/lang/trunk/src:
main/java/org/apache/commons/lang3/time/
test/java/org/apache/commons/lang3/time/
Posted by Jacques Le Roux <ja...@les7arts.com>.
Hi All,
In case it would help, to automate this we (OFBiz team) use Jira release notes
For instance you have https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12310481&version=12326666
Simply put the Jira ref in your commits comments. This also provides a direct access to Fisheye if you use it
https://confluence.atlassian.com/display/JIRA/Viewing+the+Code+Development+Information+for+an+Issue
HTH
Jacques
Le 23/03/2015 07:56, Benedikt Ritter a écrit :
> Charles, I think I've told you this several times now. Please add issues
> you fix to changes.xml! This is necessary to automatically create release
> notes.
>
> Thank you.
> Benedikt
>
> 2015-03-23 3:33 GMT+01:00 <ch...@apache.org>:
>
>> Author: chas
>> Date: Mon Mar 23 02:33:41 2015
>> New Revision: 1668511
>>
>> URL: http://svn.apache.org/r1668511
>> Log:
>> LANG-1101 FastDateParser and FastDatePrinter support 'X' format
>>
>> Modified:
>>
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>>
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
>>
>> Modified:
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> URL:
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>>
>> ==============================================================================
>> ---
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> (original)
>> +++
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> Mon Mar 23 02:33:41 2015
>> @@ -96,7 +96,10 @@ public class FastDateParser implements D
>>
>> /**
>> * <p>Constructs a new FastDateParser.</p>
>> - *
>> + *
>> + * Use {@link FastDateFormat#getInstance(String, TimeZone, Locale)}
>> or another variation of the
>> + * factory methods of {@link FastDateFormat} to get a cached
>> FastDateParser instance.
>> + *
>> * @param pattern non-null {@link java.text.SimpleDateFormat}
>> compatible
>> * pattern
>> * @param timeZone non-null time zone to use
>> @@ -467,13 +470,14 @@ public class FastDateParser implements D
>> * false, if this field is a constant value
>> */
>> abstract boolean addRegex(FastDateParser parser, StringBuilder
>> regex);
>> +
>> }
>>
>> /**
>> * A <code>Pattern</code> to parse the user supplied SimpleDateFormat
>> pattern
>> */
>> private static final Pattern formatPattern= Pattern.compile(
>> -
>> "D+|E+|F+|G+|H+|K+|M+|S+|W+|Z+|a+|d+|h+|k+|m+|s+|w+|y+|z+|''|'[^']++(''[^']*+)*+'|[^'A-Za-z]++");
>> +
>> "D+|E+|F+|G+|H+|K+|M+|S+|W+|X+|Z+|a+|d+|h+|k+|m+|s+|w+|y+|z+|''|'[^']++(''[^']*+)*+'|[^'A-Za-z]++");
>>
>> /**
>> * Obtain a Strategy given a field from a SimpleDateFormat pattern
>> @@ -524,6 +528,8 @@ public class FastDateParser implements D
>> return WEEK_OF_YEAR_STRATEGY;
>> case 'y':
>> return formatField.length()>2 ?LITERAL_YEAR_STRATEGY
>> :ABBREVIATED_YEAR_STRATEGY;
>> + case 'X':
>> + return
>> ISO8601TimeZoneStrategy.getStrategy(formatField.length());
>> case 'Z':
>> if (formatField.equals("ZZ")) {
>> return ISO_8601_STRATEGY;
>> @@ -834,14 +840,18 @@ public class FastDateParser implements D
>>
>> 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})?))";
>> + private final String pattern;
>> +
>> + ISO8601TimeZoneStrategy(String pattern) {
>> + this.pattern = pattern;
>> + }
>>
>> /**
>> * {@inheritDoc}
>> */
>> @Override
>> boolean addRegex(FastDateParser parser, StringBuilder regex) {
>> - regex.append(PATTERN);
>> + regex.append(pattern);
>> return true;
>> }
>>
>> @@ -856,6 +866,23 @@ public class FastDateParser implements D
>> cal.setTimeZone(TimeZone.getTimeZone("GMT" + value));
>> }
>> }
>> +
>> + private static final Strategy ISO_8601_1_STRATEGY = new
>> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}))");
>> + private static final Strategy ISO_8601_2_STRATEGY = new
>> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}\\d{2}))");
>> + private static final Strategy ISO_8601_3_STRATEGY = new
>> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::)\\d{2}))");
>> +
>> + static Strategy getStrategy(int tokenLen) {
>> + switch(tokenLen) {
>> + case 1:
>> + return ISO_8601_1_STRATEGY;
>> + case 2:
>> + return ISO_8601_2_STRATEGY;
>> + case 3:
>> + return ISO_8601_3_STRATEGY;
>> + default:
>> + throw new IllegalArgumentException("invalid number
>> of X");
>> + }
>> + }
>> }
>>
>> private static final Strategy NUMBER_MONTH_STRATEGY = new
>> NumberStrategy(Calendar.MONTH) {
>> @@ -887,5 +914,7 @@ public class FastDateParser implements D
>> 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();
>> + private static final Strategy ISO_8601_STRATEGY = new
>> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::?\\d{2})?))");
>> +
>> +
>> }
>>
>> Modified:
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> URL:
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>>
>> ==============================================================================
>> ---
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> (original)
>> +++
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> Mon Mar 23 02:33:41 2015
>> @@ -38,7 +38,7 @@ import org.apache.commons.lang3.Validate
>> * <p>FastDatePrinter is a fast and thread-safe version of
>> * {@link java.text.SimpleDateFormat}.</p>
>> *
>> - * <p>To obtain a proxy to a FastDatePrinter, use {@link
>> FastDateFormat#getInstance(String, TimeZone, Locale)}
>> + * <p>To obtain a FastDatePrinter, use {@link
>> FastDateFormat#getInstance(String, TimeZone, Locale)}
>> * or another variation of the factory methods of {@link
>> FastDateFormat}.</p>
>> *
>> * <p>Since FastDatePrinter is thread safe, you can use a static member
>> instance:</p>
>> @@ -64,6 +64,10 @@ import org.apache.commons.lang3.Validate
>> * ISO 8601 full format time zones (eg. {@code +08:00} or {@code -11:00}).
>> * This introduces a minor incompatibility with Java 1.4, but at a gain of
>> * useful functionality.</p>
>> + *
>> + * <p>Starting with JDK7, ISO 8601 support was added using the pattern
>> {@code 'X'}.
>> + * To maintain compatibility, {@code 'ZZ'} will continue to be supported,
>> but using
>> + * one of the {@code 'X'} formats is recommended.
>> *
>> * <p>Javadoc cites for the year pattern: <i>For formatting, if the
>> number of
>> * pattern letters is 2, the year is truncated to 2 digits; otherwise it
>> is
>> @@ -137,6 +141,8 @@ public class FastDatePrinter implements
>>
>> //-----------------------------------------------------------------------
>> /**
>> * <p>Constructs a new FastDatePrinter.</p>
>> + * Use {@link FastDateFormat#getInstance(String, TimeZone, Locale)}
>> or another variation of the
>> + * factory methods of {@link FastDateFormat} to get a cached
>> FastDatePrinter instance.
>> *
>> * @param pattern {@link java.text.SimpleDateFormat} compatible
>> pattern
>> * @param timeZone non-null time zone to use
>> @@ -265,6 +271,9 @@ public class FastDatePrinter implements
>> case 'K': // hour in am/pm (0..11)
>> rule = selectNumberRule(Calendar.HOUR, tokenLen);
>> break;
>> + case 'X': // ISO 8601
>> + rule = Iso8601_Rule.getRule(tokenLen);
>> + break;
>> case 'z': // time zone (text)
>> if (tokenLen >= 4) {
>> rule = new TimeZoneNameRule(mTimeZone, mLocale,
>> TimeZone.LONG);
>> @@ -581,6 +590,11 @@ public class FastDatePrinter implements
>> init();
>> }
>>
>> + private static void appendDigits(final StringBuffer buffer, final
>> int value) {
>> + buffer.append((char)(value / 10 + '0'));
>> + buffer.append((char)(value % 10 + '0'));
>> + }
>> +
>> // Rules
>>
>> //-----------------------------------------------------------------------
>> /**
>> @@ -588,7 +602,7 @@ public class FastDatePrinter implements
>> */
>> private interface Rule {
>> /**
>> - * Returns the estimated lentgh of the result.
>> + * Returns the estimated length of the result.
>> *
>> * @return the estimated length
>> */
>> @@ -810,8 +824,7 @@ public class FastDatePrinter implements
>> if (value < 10) {
>> buffer.append((char)(value + '0'));
>> } else {
>> - buffer.append((char)(value / 10 + '0'));
>> - buffer.append((char)(value % 10 + '0'));
>> + appendDigits(buffer, value);
>> }
>> }
>> }
>> @@ -863,8 +876,7 @@ public class FastDatePrinter implements
>> for (int i = mSize; --i >= 2; ) {
>> buffer.append('0');
>> }
>> - buffer.append((char)(value / 10 + '0'));
>> - buffer.append((char)(value % 10 + '0'));
>> + appendDigits(buffer, value);
>> } else {
>> int digits;
>> if (value < 1000) {
>> @@ -918,8 +930,7 @@ public class FastDatePrinter implements
>> @Override
>> public final void appendTo(final StringBuffer buffer, final int
>> value) {
>> if (value < 100) {
>> - buffer.append((char)(value / 10 + '0'));
>> - buffer.append((char)(value % 10 + '0'));
>> + appendDigits(buffer, value);
>> } else {
>> buffer.append(Integer.toString(value));
>> }
>> @@ -960,8 +971,7 @@ public class FastDatePrinter implements
>> */
>> @Override
>> public final void appendTo(final StringBuffer buffer, final int
>> value) {
>> - buffer.append((char)(value / 10 + '0'));
>> - buffer.append((char)(value % 10 + '0'));
>> + appendDigits(buffer, value);
>> }
>> }
>>
>> @@ -999,8 +1009,7 @@ public class FastDatePrinter implements
>> */
>> @Override
>> public final void appendTo(final StringBuffer buffer, final int
>> value) {
>> - buffer.append((char)(value / 10 + '0'));
>> - buffer.append((char)(value % 10 + '0'));
>> + appendDigits(buffer, value);
>> }
>> }
>>
>> @@ -1121,7 +1130,7 @@ public class FastDatePrinter implements
>> return value;
>> }
>>
>> - /**
>> + /**
>> * <p>Inner class to output a time zone name.</p>
>> */
>> private static class TimeZoneNameRule implements Rule {
>> @@ -1178,7 +1187,7 @@ public class FastDatePrinter implements
>> 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;
>>
>> @@ -1221,16 +1230,95 @@ public class FastDatePrinter implements
>> }
>>
>> final int hours = offset / (60 * 60 * 1000);
>> - buffer.append((char)(hours / 10 + '0'));
>> - buffer.append((char)(hours % 10 + '0'));
>> + appendDigits(buffer, hours);
>>
>> if (mColon) {
>> buffer.append(':');
>> }
>>
>> final int minutes = offset / (60 * 1000) - 60 * hours;
>> - buffer.append((char)(minutes / 10 + '0'));
>> - buffer.append((char)(minutes % 10 + '0'));
>> + appendDigits(buffer, minutes);
>> + }
>> + }
>> +
>> + /**
>> + * <p>Inner class to output a time zone as a number {@code +/-HHMM}
>> + * or {@code +/-HH:MM}.</p>
>> + */
>> + private static class Iso8601_Rule implements Rule {
>> +
>> + // Sign TwoDigitHours or Z
>> + static final Iso8601_Rule ISO8601_HOURS = new Iso8601_Rule(3);
>> + // Sign TwoDigitHours Minutes or Z
>> + static final Iso8601_Rule ISO8601_HOURS_MINUTES = new
>> Iso8601_Rule(5);
>> + // Sign TwoDigitHours : Minutes or Z
>> + static final Iso8601_Rule ISO8601_HOURS_COLON_MINUTES = new
>> Iso8601_Rule(6);
>> +
>> + static Iso8601_Rule getRule(int tokenLen) {
>> + switch(tokenLen) {
>> + case 1:
>> + return Iso8601_Rule.ISO8601_HOURS;
>> + case 2:
>> + return Iso8601_Rule.ISO8601_HOURS_MINUTES;
>> + case 3:
>> + return Iso8601_Rule.ISO8601_HOURS_COLON_MINUTES;
>> + default:
>> + throw new IllegalArgumentException("invalid number
>> of X");
>> + }
>> + }
>> +
>> + final int length;
>> +
>> + /**
>> + * Constructs an instance of {@code Iso8601_Rule} with the
>> specified properties.
>> + *
>> + * @param length The number of characters in output (unless Z is
>> output)
>> + */
>> + Iso8601_Rule(final int length) {
>> + this.length = length;
>> + }
>> +
>> + /**
>> + * {@inheritDoc}
>> + */
>> + @Override
>> + public int estimateLength() {
>> + return length;
>> + }
>> +
>> + /**
>> + * {@inheritDoc}
>> + */
>> + @Override
>> + public void appendTo(final StringBuffer buffer, final Calendar
>> calendar) {
>> + int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
>> + if (zoneOffset == 0) {
>> + buffer.append("Z");
>> + return;
>> + }
>> +
>> + int offset = zoneOffset + calendar.get(Calendar.DST_OFFSET);
>> +
>> + if (offset < 0) {
>> + buffer.append('-');
>> + offset = -offset;
>> + } else {
>> + buffer.append('+');
>> + }
>> +
>> + final int hours = offset / (60 * 60 * 1000);
>> + appendDigits(buffer, hours);
>> +
>> + if (length<5) {
>> + return;
>> + }
>> +
>> + if (length==6) {
>> + buffer.append(':');
>> + }
>> +
>> + final int minutes = offset / (60 * 1000) - 60 * hours;
>> + appendDigits(buffer, minutes);
>> }
>> }
>>
>>
>> Modified:
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
>> URL:
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>>
>> ==============================================================================
>> ---
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
>> (original)
>> +++
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
>> Mon Mar 23 02:33:41 2015
>> @@ -56,6 +56,7 @@ public class FastDateParserTest {
>> private static final TimeZone REYKJAVIK =
>> TimeZone.getTimeZone("Atlantic/Reykjavik");
>> private static final TimeZone NEW_YORK =
>> TimeZone.getTimeZone("America/New_York");
>> private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
>> + private static final TimeZone INDIA =
>> TimeZone.getTimeZone("Asia/Calcutta");
>>
>> private static final Locale SWEDEN = new Locale("sv", "SE");
>>
>> @@ -556,4 +557,63 @@ public class FastDateParserTest {
>> assertEquals(expected.getTime(), fdp.parse("14MAY2014"));
>> assertEquals(expected.getTime(), fdp.parse("14May2014"));
>> }
>> +
>> + @Test(expected = IllegalArgumentException.class)
>> + public void test1806Argument() {
>> + getInstance("XXXX");
>> + }
>> +
>> + private static Calendar initializeCalendar(TimeZone tz) {
>> + Calendar cal = Calendar.getInstance(tz);
>> + cal.set(Calendar.YEAR, 2001);
>> + cal.set(Calendar.MONTH, 1); // not daylight savings
>> + cal.set(Calendar.DAY_OF_MONTH, 4);
>> + cal.set(Calendar.HOUR_OF_DAY, 12);
>> + cal.set(Calendar.MINUTE, 8);
>> + cal.set(Calendar.SECOND, 56);
>> + cal.set(Calendar.MILLISECOND, 235);
>> + return cal;
>> + }
>> +
>> + private static enum Expected1806 {
>> + India(INDIA, "+05", "+0530", "+05:30", true),
>> + Greenwich(GMT, "Z", "Z", "Z", false),
>> + NewYork(NEW_YORK, "-05", "-0500", "-05:00", false);
>> +
>> + private Expected1806(TimeZone zone, String one, String
>> two, String three, boolean hasHalfHourOffset) {
>> + this.zone = zone;
>> + this.one = one;
>> + this.two = two;
>> + this.three = three;
>> + this.offset = hasHalfHourOffset ?30*60*1000 :0;
>> + }
>> +
>> + final TimeZone zone;
>> + final String one;
>> + final String two;
>> + final String three;
>> + final long offset;
>> + }
>> +
>> + @Test
>> + public void test1806() throws ParseException {
>> + String formatStub = "yyyy-MM-dd'T'HH:mm:ss.SSS";
>> + String dateStub = "2001-02-04T12:08:56.235";
>> +
>> + for (Expected1806 trial : Expected1806.values()) {
>> + Calendar cal = initializeCalendar(trial.zone);
>> +
>> + String message = trial.zone.getDisplayName()+";";
>> +
>> + DateParser parser = getInstance(formatStub+"X",
>> trial.zone);
>> + assertEquals(message+trial.one,
>> cal.getTime().getTime(),
>> parser.parse(dateStub+trial.one).getTime()-trial.offset);
>> +
>> + parser = getInstance(formatStub+"XX", trial.zone);
>> + assertEquals(message+trial.two, cal.getTime(),
>> parser.parse(dateStub+trial.two));
>> +
>> + parser = getInstance(formatStub+"XXX", trial.zone);
>> + assertEquals(message+trial.three, cal.getTime(),
>> parser.parse(dateStub+trial.three));
>> + }
>> + }
>> +
>> }
>>
>> Modified:
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
>> URL:
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>>
>> ==============================================================================
>> ---
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
>> (original)
>> +++
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
>> Mon Mar 23 02:33:41 2015
>> @@ -19,6 +19,7 @@ package org.apache.commons.lang3.time;
>> import static org.junit.Assert.*;
>>
>> import java.io.Serializable;
>> +import java.text.ParseException;
>> import java.text.SimpleDateFormat;
>> import java.util.Calendar;
>> import java.util.Date;
>> @@ -39,6 +40,8 @@ public class FastDatePrinterTest {
>>
>> private static final String YYYY_MM_DD = "yyyy/MM/dd";
>> private static final TimeZone NEW_YORK =
>> TimeZone.getTimeZone("America/New_York");
>> + private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
>> + private static final TimeZone INDIA =
>> TimeZone.getTimeZone("Asia/Calcutta");
>> private static final Locale SWEDEN = new Locale("sv", "SE");
>>
>> DatePrinter getInstance(final String format) {
>> @@ -272,4 +275,55 @@ public class FastDatePrinterTest {
>> FastDateFormat colonFormat = FastDateFormat.getInstance("ZZZ");
>> assertEquals("+00:00", colonFormat.format(c));
>> }
>> +
>> + private static Calendar initializeCalendar(TimeZone tz) {
>> + Calendar cal = Calendar.getInstance(tz);
>> + cal.set(Calendar.YEAR, 2001);
>> + cal.set(Calendar.MONTH, 1); // not daylight savings
>> + cal.set(Calendar.DAY_OF_MONTH, 4);
>> + cal.set(Calendar.HOUR_OF_DAY, 12);
>> + cal.set(Calendar.MINUTE, 8);
>> + cal.set(Calendar.SECOND, 56);
>> + cal.set(Calendar.MILLISECOND, 235);
>> + return cal;
>> + }
>> +
>> + @Test(expected = IllegalArgumentException.class)
>> + public void test1806Argument() {
>> + getInstance("XXXX");
>> + }
>> +
>> + private static enum Expected1806 {
>> + India(INDIA, "+05", "+0530", "+05:30"), Greenwich(GMT,
>> "Z", "Z", "Z"), NewYork(
>> + NEW_YORK, "-05", "-0500", "-05:00");
>> +
>> + private Expected1806(TimeZone zone, String one, String
>> two, String three) {
>> + this.zone = zone;
>> + this.one = one;
>> + this.two = two;
>> + this.three = three;
>> + }
>> +
>> + final TimeZone zone;
>> + final String one;
>> + final String two;
>> + final String three;
>> + }
>> +
>> +
>> + @Test
>> + public void test1806() throws ParseException {
>> + for (Expected1806 trial : Expected1806.values()) {
>> + Calendar cal = initializeCalendar(trial.zone);
>> +
>> + DatePrinter printer = getInstance("X", trial.zone);
>> + assertEquals(trial.one, printer.format(cal));
>> +
>> + printer = getInstance("XX", trial.zone);
>> + assertEquals(trial.two, printer.format(cal));
>> +
>> + printer = getInstance("XXX", trial.zone);
>> + assertEquals(trial.three, printer.format(cal));
>> + }
>> + }
>> }
>>
>>
>>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org
Re: svn commit: r1668511 - in /commons/proper/lang/trunk/src:
main/java/org/apache/commons/lang3/time/ test/java/org/apache/commons/lang3/time/
Posted by Benedikt Ritter <br...@apache.org>.
Hello Charles,
2015-03-23 16:08 GMT+01:00 Chas Honton <ch...@honton.org>:
> Benedikt,
>
> I apologize. Thank you for the reminder. I will update changes.xml this
> evening (GMT-07).
>
> I will also investigate when LANG-1088 was fixed and update changes.xml
> for that.
>
Thank you! I've already added LANG-1100 and LANG-1101.
Regards,
Benedikt
>
>
> Chas
>
> On Mar 22, 2015, at 11:56 PM, Benedikt Ritter <br...@apache.org> wrote:
>
> Charles, I think I've told you this several times now. Please add issues
> you fix to changes.xml! This is necessary to automatically create release
> notes.
>
> Thank you.
> Benedikt
>
> 2015-03-23 3:33 GMT+01:00 <ch...@apache.org>:
>
>> Author: chas
>> Date: Mon Mar 23 02:33:41 2015
>> New Revision: 1668511
>>
>> URL: http://svn.apache.org/r1668511
>> Log:
>> LANG-1101 FastDateParser and FastDatePrinter support 'X' format
>>
>> Modified:
>>
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>>
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
>>
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
>>
>> Modified:
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> URL:
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>>
>> ==============================================================================
>> ---
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> (original)
>> +++
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> Mon Mar 23 02:33:41 2015
>> @@ -96,7 +96,10 @@ public class FastDateParser implements D
>>
>> /**
>> * <p>Constructs a new FastDateParser.</p>
>> - *
>> + *
>> + * Use {@link FastDateFormat#getInstance(String, TimeZone, Locale)}
>> or another variation of the
>> + * factory methods of {@link FastDateFormat} to get a cached
>> FastDateParser instance.
>> + *
>> * @param pattern non-null {@link java.text.SimpleDateFormat}
>> compatible
>> * pattern
>> * @param timeZone non-null time zone to use
>> @@ -467,13 +470,14 @@ public class FastDateParser implements D
>> * false, if this field is a constant value
>> */
>> abstract boolean addRegex(FastDateParser parser, StringBuilder
>> regex);
>> +
>> }
>>
>> /**
>> * A <code>Pattern</code> to parse the user supplied
>> SimpleDateFormat pattern
>> */
>> private static final Pattern formatPattern= Pattern.compile(
>> -
>> "D+|E+|F+|G+|H+|K+|M+|S+|W+|Z+|a+|d+|h+|k+|m+|s+|w+|y+|z+|''|'[^']++(''[^']*+)*+'|[^'A-Za-z]++");
>> +
>> "D+|E+|F+|G+|H+|K+|M+|S+|W+|X+|Z+|a+|d+|h+|k+|m+|s+|w+|y+|z+|''|'[^']++(''[^']*+)*+'|[^'A-Za-z]++");
>>
>> /**
>> * Obtain a Strategy given a field from a SimpleDateFormat pattern
>> @@ -524,6 +528,8 @@ public class FastDateParser implements D
>> return WEEK_OF_YEAR_STRATEGY;
>> case 'y':
>> return formatField.length()>2 ?LITERAL_YEAR_STRATEGY
>> :ABBREVIATED_YEAR_STRATEGY;
>> + case 'X':
>> + return
>> ISO8601TimeZoneStrategy.getStrategy(formatField.length());
>> case 'Z':
>> if (formatField.equals("ZZ")) {
>> return ISO_8601_STRATEGY;
>> @@ -834,14 +840,18 @@ public class FastDateParser implements D
>>
>> 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})?))";
>> + private final String pattern;
>> +
>> + ISO8601TimeZoneStrategy(String pattern) {
>> + this.pattern = pattern;
>> + }
>>
>> /**
>> * {@inheritDoc}
>> */
>> @Override
>> boolean addRegex(FastDateParser parser, StringBuilder regex) {
>> - regex.append(PATTERN);
>> + regex.append(pattern);
>> return true;
>> }
>>
>> @@ -856,6 +866,23 @@ public class FastDateParser implements D
>> cal.setTimeZone(TimeZone.getTimeZone("GMT" + value));
>> }
>> }
>> +
>> + private static final Strategy ISO_8601_1_STRATEGY = new
>> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}))");
>> + private static final Strategy ISO_8601_2_STRATEGY = new
>> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}\\d{2}))");
>> + private static final Strategy ISO_8601_3_STRATEGY = new
>> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::)\\d{2}))");
>> +
>> + static Strategy getStrategy(int tokenLen) {
>> + switch(tokenLen) {
>> + case 1:
>> + return ISO_8601_1_STRATEGY;
>> + case 2:
>> + return ISO_8601_2_STRATEGY;
>> + case 3:
>> + return ISO_8601_3_STRATEGY;
>> + default:
>> + throw new IllegalArgumentException("invalid
>> number of X");
>> + }
>> + }
>> }
>>
>> private static final Strategy NUMBER_MONTH_STRATEGY = new
>> NumberStrategy(Calendar.MONTH) {
>> @@ -887,5 +914,7 @@ public class FastDateParser implements D
>> 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();
>> + private static final Strategy ISO_8601_STRATEGY = new
>> ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::?\\d{2})?))");
>> +
>> +
>> }
>>
>> Modified:
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> URL:
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>>
>> ==============================================================================
>> ---
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> (original)
>> +++
>> commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> Mon Mar 23 02:33:41 2015
>> @@ -38,7 +38,7 @@ import org.apache.commons.lang3.Validate
>> * <p>FastDatePrinter is a fast and thread-safe version of
>> * {@link java.text.SimpleDateFormat}.</p>
>> *
>> - * <p>To obtain a proxy to a FastDatePrinter, use {@link
>> FastDateFormat#getInstance(String, TimeZone, Locale)}
>> + * <p>To obtain a FastDatePrinter, use {@link
>> FastDateFormat#getInstance(String, TimeZone, Locale)}
>> * or another variation of the factory methods of {@link
>> FastDateFormat}.</p>
>> *
>> * <p>Since FastDatePrinter is thread safe, you can use a static member
>> instance:</p>
>> @@ -64,6 +64,10 @@ import org.apache.commons.lang3.Validate
>> * ISO 8601 full format time zones (eg. {@code +08:00} or {@code
>> -11:00}).
>> * This introduces a minor incompatibility with Java 1.4, but at a gain
>> of
>> * useful functionality.</p>
>> + *
>> + * <p>Starting with JDK7, ISO 8601 support was added using the pattern
>> {@code 'X'}.
>> + * To maintain compatibility, {@code 'ZZ'} will continue to be
>> supported, but using
>> + * one of the {@code 'X'} formats is recommended.
>> *
>> * <p>Javadoc cites for the year pattern: <i>For formatting, if the
>> number of
>> * pattern letters is 2, the year is truncated to 2 digits; otherwise it
>> is
>> @@ -137,6 +141,8 @@ public class FastDatePrinter implements
>>
>> //-----------------------------------------------------------------------
>> /**
>> * <p>Constructs a new FastDatePrinter.</p>
>> + * Use {@link FastDateFormat#getInstance(String, TimeZone, Locale)}
>> or another variation of the
>> + * factory methods of {@link FastDateFormat} to get a cached
>> FastDatePrinter instance.
>> *
>> * @param pattern {@link java.text.SimpleDateFormat} compatible
>> pattern
>> * @param timeZone non-null time zone to use
>> @@ -265,6 +271,9 @@ public class FastDatePrinter implements
>> case 'K': // hour in am/pm (0..11)
>> rule = selectNumberRule(Calendar.HOUR, tokenLen);
>> break;
>> + case 'X': // ISO 8601
>> + rule = Iso8601_Rule.getRule(tokenLen);
>> + break;
>> case 'z': // time zone (text)
>> if (tokenLen >= 4) {
>> rule = new TimeZoneNameRule(mTimeZone, mLocale,
>> TimeZone.LONG);
>> @@ -581,6 +590,11 @@ public class FastDatePrinter implements
>> init();
>> }
>>
>> + private static void appendDigits(final StringBuffer buffer, final
>> int value) {
>> + buffer.append((char)(value / 10 + '0'));
>> + buffer.append((char)(value % 10 + '0'));
>> + }
>> +
>> // Rules
>>
>> //-----------------------------------------------------------------------
>> /**
>> @@ -588,7 +602,7 @@ public class FastDatePrinter implements
>> */
>> private interface Rule {
>> /**
>> - * Returns the estimated lentgh of the result.
>> + * Returns the estimated length of the result.
>> *
>> * @return the estimated length
>> */
>> @@ -810,8 +824,7 @@ public class FastDatePrinter implements
>> if (value < 10) {
>> buffer.append((char)(value + '0'));
>> } else {
>> - buffer.append((char)(value / 10 + '0'));
>> - buffer.append((char)(value % 10 + '0'));
>> + appendDigits(buffer, value);
>> }
>> }
>> }
>> @@ -863,8 +876,7 @@ public class FastDatePrinter implements
>> for (int i = mSize; --i >= 2; ) {
>> buffer.append('0');
>> }
>> - buffer.append((char)(value / 10 + '0'));
>> - buffer.append((char)(value % 10 + '0'));
>> + appendDigits(buffer, value);
>> } else {
>> int digits;
>> if (value < 1000) {
>> @@ -918,8 +930,7 @@ public class FastDatePrinter implements
>> @Override
>> public final void appendTo(final StringBuffer buffer, final int
>> value) {
>> if (value < 100) {
>> - buffer.append((char)(value / 10 + '0'));
>> - buffer.append((char)(value % 10 + '0'));
>> + appendDigits(buffer, value);
>> } else {
>> buffer.append(Integer.toString(value));
>> }
>> @@ -960,8 +971,7 @@ public class FastDatePrinter implements
>> */
>> @Override
>> public final void appendTo(final StringBuffer buffer, final int
>> value) {
>> - buffer.append((char)(value / 10 + '0'));
>> - buffer.append((char)(value % 10 + '0'));
>> + appendDigits(buffer, value);
>> }
>> }
>>
>> @@ -999,8 +1009,7 @@ public class FastDatePrinter implements
>> */
>> @Override
>> public final void appendTo(final StringBuffer buffer, final int
>> value) {
>> - buffer.append((char)(value / 10 + '0'));
>> - buffer.append((char)(value % 10 + '0'));
>> + appendDigits(buffer, value);
>> }
>> }
>>
>> @@ -1121,7 +1130,7 @@ public class FastDatePrinter implements
>> return value;
>> }
>>
>> - /**
>> + /**
>> * <p>Inner class to output a time zone name.</p>
>> */
>> private static class TimeZoneNameRule implements Rule {
>> @@ -1178,7 +1187,7 @@ public class FastDatePrinter implements
>> 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;
>>
>> @@ -1221,16 +1230,95 @@ public class FastDatePrinter implements
>> }
>>
>> final int hours = offset / (60 * 60 * 1000);
>> - buffer.append((char)(hours / 10 + '0'));
>> - buffer.append((char)(hours % 10 + '0'));
>> + appendDigits(buffer, hours);
>>
>> if (mColon) {
>> buffer.append(':');
>> }
>>
>> final int minutes = offset / (60 * 1000) - 60 * hours;
>> - buffer.append((char)(minutes / 10 + '0'));
>> - buffer.append((char)(minutes % 10 + '0'));
>> + appendDigits(buffer, minutes);
>> + }
>> + }
>> +
>> + /**
>> + * <p>Inner class to output a time zone as a number {@code +/-HHMM}
>> + * or {@code +/-HH:MM}.</p>
>> + */
>> + private static class Iso8601_Rule implements Rule {
>> +
>> + // Sign TwoDigitHours or Z
>> + static final Iso8601_Rule ISO8601_HOURS = new Iso8601_Rule(3);
>> + // Sign TwoDigitHours Minutes or Z
>> + static final Iso8601_Rule ISO8601_HOURS_MINUTES = new
>> Iso8601_Rule(5);
>> + // Sign TwoDigitHours : Minutes or Z
>> + static final Iso8601_Rule ISO8601_HOURS_COLON_MINUTES = new
>> Iso8601_Rule(6);
>> +
>> + static Iso8601_Rule getRule(int tokenLen) {
>> + switch(tokenLen) {
>> + case 1:
>> + return Iso8601_Rule.ISO8601_HOURS;
>> + case 2:
>> + return Iso8601_Rule.ISO8601_HOURS_MINUTES;
>> + case 3:
>> + return Iso8601_Rule.ISO8601_HOURS_COLON_MINUTES;
>> + default:
>> + throw new IllegalArgumentException("invalid
>> number of X");
>> + }
>> + }
>> +
>> + final int length;
>> +
>> + /**
>> + * Constructs an instance of {@code Iso8601_Rule} with the
>> specified properties.
>> + *
>> + * @param length The number of characters in output (unless Z is
>> output)
>> + */
>> + Iso8601_Rule(final int length) {
>> + this.length = length;
>> + }
>> +
>> + /**
>> + * {@inheritDoc}
>> + */
>> + @Override
>> + public int estimateLength() {
>> + return length;
>> + }
>> +
>> + /**
>> + * {@inheritDoc}
>> + */
>> + @Override
>> + public void appendTo(final StringBuffer buffer, final Calendar
>> calendar) {
>> + int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
>> + if (zoneOffset == 0) {
>> + buffer.append("Z");
>> + return;
>> + }
>> +
>> + int offset = zoneOffset + calendar.get(Calendar.DST_OFFSET);
>> +
>> + if (offset < 0) {
>> + buffer.append('-');
>> + offset = -offset;
>> + } else {
>> + buffer.append('+');
>> + }
>> +
>> + final int hours = offset / (60 * 60 * 1000);
>> + appendDigits(buffer, hours);
>> +
>> + if (length<5) {
>> + return;
>> + }
>> +
>> + if (length==6) {
>> + buffer.append(':');
>> + }
>> +
>> + final int minutes = offset / (60 * 1000) - 60 * hours;
>> + appendDigits(buffer, minutes);
>> }
>> }
>>
>>
>> Modified:
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
>> URL:
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>>
>> ==============================================================================
>> ---
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
>> (original)
>> +++
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDateParserTest.java
>> Mon Mar 23 02:33:41 2015
>> @@ -56,6 +56,7 @@ public class FastDateParserTest {
>> private static final TimeZone REYKJAVIK =
>> TimeZone.getTimeZone("Atlantic/Reykjavik");
>> private static final TimeZone NEW_YORK =
>> TimeZone.getTimeZone("America/New_York");
>> private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
>> + private static final TimeZone INDIA =
>> TimeZone.getTimeZone("Asia/Calcutta");
>>
>> private static final Locale SWEDEN = new Locale("sv", "SE");
>>
>> @@ -556,4 +557,63 @@ public class FastDateParserTest {
>> assertEquals(expected.getTime(), fdp.parse("14MAY2014"));
>> assertEquals(expected.getTime(), fdp.parse("14May2014"));
>> }
>> +
>> + @Test(expected = IllegalArgumentException.class)
>> + public void test1806Argument() {
>> + getInstance("XXXX");
>> + }
>> +
>> + private static Calendar initializeCalendar(TimeZone tz) {
>> + Calendar cal = Calendar.getInstance(tz);
>> + cal.set(Calendar.YEAR, 2001);
>> + cal.set(Calendar.MONTH, 1); // not daylight savings
>> + cal.set(Calendar.DAY_OF_MONTH, 4);
>> + cal.set(Calendar.HOUR_OF_DAY, 12);
>> + cal.set(Calendar.MINUTE, 8);
>> + cal.set(Calendar.SECOND, 56);
>> + cal.set(Calendar.MILLISECOND, 235);
>> + return cal;
>> + }
>> +
>> + private static enum Expected1806 {
>> + India(INDIA, "+05", "+0530", "+05:30", true),
>> + Greenwich(GMT, "Z", "Z", "Z", false),
>> + NewYork(NEW_YORK, "-05", "-0500", "-05:00", false);
>> +
>> + private Expected1806(TimeZone zone, String one, String
>> two, String three, boolean hasHalfHourOffset) {
>> + this.zone = zone;
>> + this.one = one;
>> + this.two = two;
>> + this.three = three;
>> + this.offset = hasHalfHourOffset ?30*60*1000 :0;
>> + }
>> +
>> + final TimeZone zone;
>> + final String one;
>> + final String two;
>> + final String three;
>> + final long offset;
>> + }
>> +
>> + @Test
>> + public void test1806() throws ParseException {
>> + String formatStub = "yyyy-MM-dd'T'HH:mm:ss.SSS";
>> + String dateStub = "2001-02-04T12:08:56.235";
>> +
>> + for (Expected1806 trial : Expected1806.values()) {
>> + Calendar cal = initializeCalendar(trial.zone);
>> +
>> + String message = trial.zone.getDisplayName()+";";
>> +
>> + DateParser parser = getInstance(formatStub+"X",
>> trial.zone);
>> + assertEquals(message+trial.one,
>> cal.getTime().getTime(),
>> parser.parse(dateStub+trial.one).getTime()-trial.offset);
>> +
>> + parser = getInstance(formatStub+"XX", trial.zone);
>> + assertEquals(message+trial.two, cal.getTime(),
>> parser.parse(dateStub+trial.two));
>> +
>> + parser = getInstance(formatStub+"XXX",
>> trial.zone);
>> + assertEquals(message+trial.three, cal.getTime(),
>> parser.parse(dateStub+trial.three));
>> + }
>> + }
>> +
>> }
>>
>> Modified:
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
>> URL:
>> http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java?rev=1668511&r1=1668510&r2=1668511&view=diff
>>
>> ==============================================================================
>> ---
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
>> (original)
>> +++
>> commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/time/FastDatePrinterTest.java
>> Mon Mar 23 02:33:41 2015
>> @@ -19,6 +19,7 @@ package org.apache.commons.lang3.time;
>> import static org.junit.Assert.*;
>>
>> import java.io.Serializable;
>> +import java.text.ParseException;
>> import java.text.SimpleDateFormat;
>> import java.util.Calendar;
>> import java.util.Date;
>> @@ -39,6 +40,8 @@ public class FastDatePrinterTest {
>>
>> private static final String YYYY_MM_DD = "yyyy/MM/dd";
>> private static final TimeZone NEW_YORK =
>> TimeZone.getTimeZone("America/New_York");
>> + private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
>> + private static final TimeZone INDIA =
>> TimeZone.getTimeZone("Asia/Calcutta");
>> private static final Locale SWEDEN = new Locale("sv", "SE");
>>
>> DatePrinter getInstance(final String format) {
>> @@ -272,4 +275,55 @@ public class FastDatePrinterTest {
>> FastDateFormat colonFormat = FastDateFormat.getInstance("ZZZ");
>> assertEquals("+00:00", colonFormat.format(c));
>> }
>> +
>> + private static Calendar initializeCalendar(TimeZone tz) {
>> + Calendar cal = Calendar.getInstance(tz);
>> + cal.set(Calendar.YEAR, 2001);
>> + cal.set(Calendar.MONTH, 1); // not daylight savings
>> + cal.set(Calendar.DAY_OF_MONTH, 4);
>> + cal.set(Calendar.HOUR_OF_DAY, 12);
>> + cal.set(Calendar.MINUTE, 8);
>> + cal.set(Calendar.SECOND, 56);
>> + cal.set(Calendar.MILLISECOND, 235);
>> + return cal;
>> + }
>> +
>> + @Test(expected = IllegalArgumentException.class)
>> + public void test1806Argument() {
>> + getInstance("XXXX");
>> + }
>> +
>> + private static enum Expected1806 {
>> + India(INDIA, "+05", "+0530", "+05:30"), Greenwich(GMT,
>> "Z", "Z", "Z"), NewYork(
>> + NEW_YORK, "-05", "-0500", "-05:00");
>> +
>> + private Expected1806(TimeZone zone, String one, String
>> two, String three) {
>> + this.zone = zone;
>> + this.one = one;
>> + this.two = two;
>> + this.three = three;
>> + }
>> +
>> + final TimeZone zone;
>> + final String one;
>> + final String two;
>> + final String three;
>> + }
>> +
>> +
>> + @Test
>> + public void test1806() throws ParseException {
>> + for (Expected1806 trial : Expected1806.values()) {
>> + Calendar cal = initializeCalendar(trial.zone);
>> +
>> + DatePrinter printer = getInstance("X",
>> trial.zone);
>> + assertEquals(trial.one, printer.format(cal));
>> +
>> + printer = getInstance("XX", trial.zone);
>> + assertEquals(trial.two, printer.format(cal));
>> +
>> + printer = getInstance("XXX", trial.zone);
>> + assertEquals(trial.three, printer.format(cal));
>> + }
>> + }
>> }
>>
>>
>>
>
>
> --
> http://people.apache.org/~britter/
> http://www.systemoutprintln.de/
> http://twitter.com/BenediktRitter
> http://github.com/britter
>
>
--
http://people.apache.org/~britter/
http://www.systemoutprintln.de/
http://twitter.com/BenediktRitter
http://github.com/britter