-1 All Travis builds started failing after this commit [1]
Benedikt [1] https://travis-ci.org/apache/commons-lang/builds 2015-12-14 1:39 GMT+01:00 <c...@apache.org>: > Repository: commons-lang > Updated Branches: > refs/heads/master 2ebf9a21d -> 2fa0b168d > > > LANG-1192: FastDateFormat support of the week-year component (uppercase > 'Y') > > > Project: http://git-wip-us.apache.org/repos/asf/commons-lang/repo > Commit: > http://git-wip-us.apache.org/repos/asf/commons-lang/commit/2fa0b168 > Tree: http://git-wip-us.apache.org/repos/asf/commons-lang/tree/2fa0b168 > Diff: http://git-wip-us.apache.org/repos/asf/commons-lang/diff/2fa0b168 > > Branch: refs/heads/master > Commit: 2fa0b168d62a07365b2787d0ed97fa1c2cfb673b > Parents: 2ebf9a2 > Author: Chas Honton <c...@apache.org> > Authored: Sun Dec 13 16:38:35 2015 -0800 > Committer: Chas Honton <c...@apache.org> > Committed: Sun Dec 13 16:38:35 2015 -0800 > > ---------------------------------------------------------------------- > src/changes/changes.xml | 1 + > .../commons/lang3/time/CalendarReflection.java | 99 ++++++++++++++++++++ > .../apache/commons/lang3/time/DateParser.java | 16 ++++ > .../commons/lang3/time/FastDateFormat.java | 11 ++- > .../commons/lang3/time/FastDateParser.java | 32 ++++--- > .../commons/lang3/time/FastDatePrinter.java | 54 ++++++++--- > .../apache/commons/lang3/time/WeekYearTest.java | 90 ++++++++++++++++++ > 7 files changed, 276 insertions(+), 27 deletions(-) > ---------------------------------------------------------------------- > > > > http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/changes/changes.xml > ---------------------------------------------------------------------- > diff --git a/src/changes/changes.xml b/src/changes/changes.xml > index d4904c4..7a184df 100644 > --- a/src/changes/changes.xml > +++ b/src/changes/changes.xml > @@ -22,6 +22,7 @@ > <body> > > <release version="3.5" date="tba" description="tba"> > + <action issue="LANG-1192" type="add" dev="chas" due-to="Dominik > Stadler">FastDateFormat support of the week-year component (uppercase > 'Y')</action> > <action issue="LANG-1193" type="fix" dev="sebb" due-to="Qin > Li">ordinalIndexOf("abc", "ab", 1) gives incorrect answer of -1 (correct > answer should be 0); revert fix for LANG-1077</action> > <action issue="LANG-1182" type="update" dev="britter" due-to="Larry > West, Pascal Schumacher">Clarify JavaDoc of > StringUtils.containsAny()</action> > <action issue="LANG-1169" type="add" dev="lguibert" due-to="Rafal > Glowinski, Robert Parr, Arman Sharif">Add StringUtils methods to compare a > string to multiple strings</action> > > > http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java > ---------------------------------------------------------------------- > diff --git > a/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java > b/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java > new file mode 100644 > index 0000000..79ebb3f > --- /dev/null > +++ b/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java > @@ -0,0 +1,99 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You under the Apache License, Version 2.0 > + * (the "License"); you may not use this file except in compliance with > + * the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > +package org.apache.commons.lang3.time; > + > +import java.lang.reflect.Method; > +import java.util.Calendar; > +import java.util.GregorianCalendar; > + > +import org.apache.commons.lang3.exception.ExceptionUtils; > + > +/** > + * Use reflection to access java 1.7 methods in Calendar. This allows > compilation with 1.6 compiler. > + */ > +class CalendarReflection { > + > + private static final Method IS_WEEK_DATE_SUPPORTED = > getCalendarMethod("isWeekDateSupported"); > + private static final Method GET_WEEK_YEAR = > getCalendarMethod("getWeekYear"); > + > + private static Method getCalendarMethod(String methodName, > Class<?>... argTypes) { > + try { > + Method m = Calendar.class.getMethod(methodName, argTypes); > + return m; > + } catch (Exception e) { > + return null; > + } > + } > + > + /** > + * Does this calendar instance support week date? > + * @param calendar The calendar instance. > + * @return false, if runtime is less than java 1.7; otherwise, the > result of calendar.isWeekDateSupported(). > + */ > + static boolean isWeekDateSupported(Calendar calendar) { > + try { > + return IS_WEEK_DATE_SUPPORTED!=null && > ((Boolean)IS_WEEK_DATE_SUPPORTED.invoke(calendar)).booleanValue(); > + } catch (Exception e) { > + return ExceptionUtils.<Boolean>rethrow(e); > + } > + } > + > + /** > + * Invoke getWeekYear() method of calendar instance. > + * <p> > + * If runtime is 1.7 or better and calendar instance support week > year, > + * return the value from invocation of getWeekYear(). > + * <p> > + * If runtime is less than 1.7, and calendar is an instance of > + * GregorianCalendar, return an approximation of the week year. > + * (Approximation is good for all years after the Julian to Gregorian > + * cutover.) > + * <p> > + * Otherwise, return the calendar instance year value. > + * > + * @param calendar The calendar instance. > + * @return the week year or year value. > + */ > + public static int getWeekYear(Calendar calendar) { > + try { > + if (isWeekDateSupported(calendar)) { > + return (Integer) GET_WEEK_YEAR.invoke(calendar); > + } > + } catch (Exception e) { > + return ExceptionUtils.<Integer> rethrow(e); > + } > + > + int year = calendar.get(Calendar.YEAR); > + if (IS_WEEK_DATE_SUPPORTED == null && calendar instanceof > GregorianCalendar) { > + // not perfect, won't work before gregorian cutover > + // good enough for most business use. > + switch (calendar.get(Calendar.MONTH)) { > + case Calendar.JANUARY: > + if (calendar.get(Calendar.WEEK_OF_YEAR) >= 52) { > + --year; > + } > + break; > + case Calendar.DECEMBER: > + if (calendar.get(Calendar.WEEK_OF_YEAR) == 1) { > + ++year; > + } > + break; > + } > + } > + return year; > + } > +} > > > http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/DateParser.java > ---------------------------------------------------------------------- > diff --git a/src/main/java/org/apache/commons/lang3/time/DateParser.java > b/src/main/java/org/apache/commons/lang3/time/DateParser.java > index 120c4ab..c91f9a2 100644 > --- a/src/main/java/org/apache/commons/lang3/time/DateParser.java > +++ b/src/main/java/org/apache/commons/lang3/time/DateParser.java > @@ -18,6 +18,7 @@ package org.apache.commons.lang3.time; > > import java.text.ParseException; > import java.text.ParsePosition; > +import java.util.Calendar; > import java.util.Date; > import java.util.Locale; > import java.util.TimeZone; > @@ -53,6 +54,21 @@ public interface DateParser { > */ > Date parse(String source, ParsePosition pos); > > + /** > + * Parse a formatted date string according to the format. Updates > the Calendar with parsed fields. > + * Upon success, the ParsePosition index is updated to indicate how > much of the source text was consumed. > + * Not all source text needs to be consumed. Upon parse failure, > ParsePosition error index is updated to > + * the offset of the source text which does not match the supplied > format. > + * > + * @param source The text to parse. > + * @param pos On input, the position in the source to start parsing, > on output, updated position. > + * @param calendar The calendar into which to set parsed fields. > + * @return true, if source has been parsed (pos parsePosition is > updated); otherwise false (and pos errorIndex is updated) > + * @throws IllegalArgumentException when Calendar has been set to be > not lenient, and a parsed field is > + * out of range. > + */ > + boolean parse(String source, ParsePosition pos, Calendar calendar); > + > // Accessors > > //----------------------------------------------------------------------- > /** > > > http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java > ---------------------------------------------------------------------- > diff --git > a/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java > b/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java > index abb5198..c2907b2 100644 > --- a/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java > +++ b/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java > @@ -550,7 +550,16 @@ public class FastDateFormat extends Format implements > DateParser, DatePrinter { > */ > @Override > public Date parse(final String source, final ParsePosition pos) { > - return parser.parse(source, pos); > + return parser.parse(source, pos); > + } > + > + /* > + * (non-Javadoc) > + * @see > org.apache.commons.lang3.time.DateParser#parse(java.lang.String, > java.text.ParsePosition, java.util.Calendar) > + */ > + @Override > + public boolean parse(final String source, final ParsePosition pos, > final Calendar calendar) { > + return parser.parse(source, pos, calendar); > } > > /* (non-Javadoc) > > > http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/FastDateParser.java > ---------------------------------------------------------------------- > diff --git > a/src/main/java/org/apache/commons/lang3/time/FastDateParser.java > b/src/main/java/org/apache/commons/lang3/time/FastDateParser.java > index 4dc897b..8210ee3 100644 > --- a/src/main/java/org/apache/commons/lang3/time/FastDateParser.java > +++ b/src/main/java/org/apache/commons/lang3/time/FastDateParser.java > @@ -170,7 +170,7 @@ public class FastDateParser implements DateParser, > Serializable { > > //----------------------------------------------------------------------- > > /** > - * Struct to hold strategy and filed width > + * Struct to hold strategy and field width > */ > private static class StrategyAndWidth { > final Strategy strategy; > @@ -401,12 +401,12 @@ public class FastDateParser implements DateParser, > Serializable { > > return parse(source, pos, cal) ?cal.getTime() :null; > } > - > + > /** > - * Parse a formatted date string according to the format. Updates > the Calendar with parsed fields. > + * Parse a formatted date string according to the format. Updates > the Calendar with parsed fields. > * Upon success, the ParsePosition index is updated to indicate how > much of the source text was consumed. > * Not all source text needs to be consumed. Upon parse failure, > ParsePosition error index is updated to > - * the offset of the source text which does not match the supplied > format. > + * the offset of the source text which does not match the supplied > format. > * > * @param source The text to parse. > * @param pos On input, the position in the source to start parsing, > on output, updated position. > @@ -415,17 +415,18 @@ public class FastDateParser implements DateParser, > Serializable { > * @throws IllegalArgumentException when Calendar has been set to be > not lenient, and a parsed field is > * out of range. > */ > - public boolean parse(final String source, final ParsePosition pos, > final Calendar calendar) { > - ListIterator<StrategyAndWidth> lt = patterns.listIterator(); > - while(lt.hasNext()) { > - StrategyAndWidth pattern = lt.next(); > - int maxWidth = pattern.getMaxWidth(lt); > - if(!pattern.strategy.parse(this, calendar, source, pos, > maxWidth)) { > - return false; > - } > - } > - return true; > - } > + @Override > + public boolean parse(final String source, final ParsePosition pos, > final Calendar calendar) { > + ListIterator<StrategyAndWidth> lt = patterns.listIterator(); > + while(lt.hasNext()) { > + StrategyAndWidth pattern = lt.next(); > + int maxWidth = pattern.getMaxWidth(lt); > + if(!pattern.strategy.parse(this, calendar, source, pos, > maxWidth)) { > + return false; > + } > + } > + return true; > + } > > // Support for strategies > > //----------------------------------------------------------------------- > @@ -606,6 +607,7 @@ public class FastDateParser implements DateParser, > Serializable { > case 'w': > return WEEK_OF_YEAR_STRATEGY; > case 'y': > + case 'Y': > return width>2 ?LITERAL_YEAR_STRATEGY > :ABBREVIATED_YEAR_STRATEGY; > case 'X': > return ISO8601TimeZoneStrategy.getStrategy(width); > > > http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java > ---------------------------------------------------------------------- > 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 4f84cc7..f044552 100644 > --- a/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java > +++ b/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java > @@ -25,7 +25,6 @@ import java.text.FieldPosition; > import java.util.ArrayList; > import java.util.Calendar; > import java.util.Date; > -import java.util.GregorianCalendar; > import java.util.List; > import java.util.Locale; > import java.util.TimeZone; > @@ -211,11 +210,15 @@ public class FastDatePrinter implements DatePrinter, > Serializable { > rule = new TextField(Calendar.ERA, ERAs); > break; > case 'y': // year (number) > + case 'Y': // week year > if (tokenLen == 2) { > rule = TwoDigitYearField.INSTANCE; > } else { > rule = selectNumberRule(Calendar.YEAR, tokenLen < 4 ? > 4 : tokenLen); > } > + if (c == 'Y') { > + rule = new WeekYear((NumberRule) rule); > + } > break; > case 'M': // month in year (text and number) > if (tokenLen >= 4) { > @@ -438,7 +441,7 @@ public class FastDatePrinter implements DatePrinter, > Serializable { > */ > @Override > public String format(final long millis) { > - final Calendar c = newCalendar(); // hard code GregorianCalendar > + final Calendar c = newCalendar(); > c.setTimeInMillis(millis); > return applyRulesToString(c); > } > @@ -453,12 +456,11 @@ public class FastDatePrinter implements DatePrinter, > Serializable { > } > > /** > - * Creation method for ne calender instances. > + * Creation method for new calender instances. > * @return a new Calendar instance. > */ > - private GregorianCalendar newCalendar() { > - // hard code GregorianCalendar > - return new GregorianCalendar(mTimeZone, mLocale); > + private Calendar newCalendar() { > + return Calendar.getInstance(mTimeZone, mLocale); > } > > /* (non-Javadoc) > @@ -466,7 +468,7 @@ public class FastDatePrinter implements DatePrinter, > Serializable { > */ > @Override > public String format(final Date date) { > - final Calendar c = newCalendar(); // hard code GregorianCalendar > + final Calendar c = newCalendar(); > c.setTime(date); > return applyRulesToString(c); > } > @@ -492,7 +494,7 @@ public class FastDatePrinter implements DatePrinter, > Serializable { > */ > @Override > public StringBuffer format(final Date date, final StringBuffer buf) { > - final Calendar c = newCalendar(); // hard code GregorianCalendar > + final Calendar c = newCalendar(); > c.setTime(date); > return applyRules(c, buf); > } > @@ -519,7 +521,7 @@ public class FastDatePrinter implements DatePrinter, > Serializable { > */ > @Override > public <B extends Appendable> B format(final Date date, final B buf) { > - final Calendar c = newCalendar(); // hard code GregorianCalendar > + final Calendar c = newCalendar(); > c.setTime(date); > return applyRules(c, buf); > } > @@ -528,9 +530,13 @@ public class FastDatePrinter implements DatePrinter, > Serializable { > * @see > org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar, > java.lang.Appendable) > */ > @Override > - public <B extends Appendable> B format(final Calendar calendar, final > B buf) { > + public <B extends Appendable> B format(Calendar calendar, final B > buf) { > // do not pass in calendar directly, this will cause TimeZone of > FastDatePrinter to be ignored > - return format(calendar.getTime(), buf); > + if(!calendar.getTimeZone().equals(mTimeZone)) { > + calendar = (Calendar)calendar.clone(); > + calendar.setTimeZone(mTimeZone); > + } > + return applyRules(calendar, buf); > } > > /** > @@ -1202,6 +1208,32 @@ public class FastDatePrinter implements > DatePrinter, Serializable { > } > } > > + /** > + * <p>Inner class to output the numeric day in week.</p> > + */ > + private static class WeekYear implements NumberRule { > + private final NumberRule mRule; > + > + WeekYear(final NumberRule rule) { > + mRule = rule; > + } > + > + @Override > + public int estimateLength() { > + return mRule.estimateLength(); > + } > + > + @Override > + public void appendTo(final Appendable buffer, final Calendar > calendar) throws IOException { > + mRule.appendTo(buffer, > CalendarReflection.getWeekYear(calendar)); > + } > + > + @Override > + public void appendTo(final Appendable buffer, final int value) > throws IOException { > + mRule.appendTo(buffer, value); > + } > + } > + > > //----------------------------------------------------------------------- > > private static final ConcurrentMap<TimeZoneDisplayKey, String> > cTimeZoneDisplayCache = > > > http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java > ---------------------------------------------------------------------- > diff --git a/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java > b/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java > new file mode 100644 > index 0000000..95f5ad8 > --- /dev/null > +++ b/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java > @@ -0,0 +1,90 @@ > +/* > + * Licensed to the Apache Software Foundation (ASF) under one or more > + * contributor license agreements. See the NOTICE file distributed with > + * this work for additional information regarding copyright ownership. > + * The ASF licenses this file to You under the Apache License, Version 2.0 > + * (the "License"); you may not use this file except in compliance with > + * the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > +package org.apache.commons.lang3.time; > + > +import java.text.ParseException; > +import java.text.ParsePosition; > +import java.util.Arrays; > +import java.util.Calendar; > +import java.util.Collection; > +import java.util.GregorianCalendar; > +import java.util.Locale; > +import java.util.TimeZone; > + > +import org.junit.Assert; > +import org.junit.Test; > +import org.junit.runner.RunWith; > +import org.junit.runners.Parameterized; > +import org.junit.runners.Parameterized.Parameters; > + > +@RunWith(Parameterized.class) > +public class WeekYearTest { > + > + @Parameters(name = "{index}: {3}") > + public static Collection<Object[]> data() { > + return Arrays > + .asList(new Object[][] { > + { 2005, Calendar.JANUARY, 1, "2004-W53-6" }, > + { 2005, Calendar.JANUARY, 2, "2004-W53-7" }, > + { 2005, Calendar.DECEMBER, 31, "2005-W52-6" }, > + { 2007, Calendar.JANUARY, 1, "2007-W01-1" }, > + { 2007, Calendar.DECEMBER, 30, "2007-W52-7" }, > + { 2007, Calendar.DECEMBER, 31, "2008-W01-1" }, > + { 2008, Calendar.JANUARY, 1, "2008-W01-2" }, > + { 2008, Calendar.DECEMBER, 28, "2008-W52-7" }, > + { 2008, Calendar.DECEMBER, 29, "2009-W01-1" }, > + { 2008, Calendar.DECEMBER, 30, "2009-W01-2" }, > + { 2008, Calendar.DECEMBER, 31, "2009-W01-3" }, > + { 2009, Calendar.JANUARY, 1, "2009-W01-4" }, > + { 2009, Calendar.DECEMBER, 31, "2009-W53-4" }, > + { 2010, Calendar.JANUARY, 1, "2009-W53-5" }, > + { 2010, Calendar.JANUARY, 2, "2009-W53-6" }, > + { 2010, Calendar.JANUARY, 3, "2009-W53-7" } > + }); > + } > + > + final Calendar vulgar; > + final String isoForm; > + > + public WeekYearTest(int year, int month, int day, String isoForm) { > + vulgar = new GregorianCalendar(year, month, day); > + this.isoForm = isoForm; > + } > + > + @Test > + public void testParser() throws ParseException { > + final DateParser parser = new FastDateParser("YYYY-'W'ww-u", > TimeZone.getDefault(), Locale.getDefault()); > + > + Calendar cal = Calendar.getInstance(); > + cal.setMinimalDaysInFirstWeek(4); > + cal.setFirstDayOfWeek(Calendar.MONDAY); > + cal.clear(); > + > + parser.parse(isoForm, new ParsePosition(0), cal); > + Assert.assertEquals(vulgar.getTime(), cal.getTime()); > + } > + > + @Test > + public void testPrinter() { > + final FastDatePrinter printer = new > FastDatePrinter("YYYY-'W'ww-u", TimeZone.getDefault(), Locale.getDefault()); > + > + vulgar.setMinimalDaysInFirstWeek(4); > + vulgar.setFirstDayOfWeek(Calendar.MONDAY); > + > + Assert.assertEquals(isoForm, printer.format(vulgar)); > + } > +} > > -- http://home.apache.org/~britter/ http://twitter.com/BenediktRitter http://github.com/britter