Applying Chas Honton's implementation of DateParser and subsequent integration into FastDateFormat and the time package. See LANG-462.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1236055 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
dfa6882a3b
commit
cc340ad2eb
3
pom.xml
3
pom.xml
|
@ -247,6 +247,9 @@
|
|||
<contributor>
|
||||
<name>Michael Heuer</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Chas Honton</name>
|
||||
</contributor>
|
||||
<contributor>
|
||||
<name>Chris Hyzer</name>
|
||||
</contributor>
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* <p>DateParser is the "missing" interface for the parsing methods of
|
||||
* {@link java.text.DateFormat}.</p>
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public interface DateParser {
|
||||
|
||||
/**
|
||||
* Equivalent to DateFormat.parse(String).
|
||||
*
|
||||
* See {@link java.text.DateFormat#parse(String)} for more information.
|
||||
* @param source A <code>String</code> whose beginning should be parsed.
|
||||
* @return A <code>Date</code> parsed from the string
|
||||
* @throws ParseException if the beginning of the specified string cannot be parsed.
|
||||
*/
|
||||
public Date parse(String source) throws ParseException;
|
||||
|
||||
/**
|
||||
* Equivalent to DateFormat.parse(String, ParsePosition).
|
||||
*
|
||||
* See {@link java.text.DateFormat#parse(String, ParsePosition)} for more information.
|
||||
*
|
||||
* @param source A <code>String</code>, part of which should be parsed.
|
||||
* @param pos A <code>ParsePosition</code> object with index and error index information
|
||||
* as described above.
|
||||
* @return A <code>Date</code> parsed from the string. In case of error, returns null.
|
||||
* @throws NullPointerException if text or pos is null.
|
||||
*/
|
||||
public Date parse(String source, ParsePosition pos);
|
||||
|
||||
// Accessors
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Get the pattern used by this parser.</p>
|
||||
*
|
||||
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||
*/
|
||||
public String getPattern();
|
||||
|
||||
/**
|
||||
* <p>Get the time zone used by this parser.</p>
|
||||
*
|
||||
* <p>This zone is always used for <code>Date</code> formatting.
|
||||
* If a <code>Calendar</code> is passed in to be formatted, the
|
||||
* time zone on that may be used depending on
|
||||
* {@link #getTimeZoneOverridesCalendar()}.</p>
|
||||
*
|
||||
* @return the time zone
|
||||
*/
|
||||
public TimeZone getTimeZone();
|
||||
|
||||
/**
|
||||
* <p>Get the locale used by this parser.</p>
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
public Locale getLocale();
|
||||
|
||||
/**
|
||||
* Parses text from a string to produce a Date.
|
||||
* See {@link java.text.DateFormat#parseObject(String)}
|
||||
*/
|
||||
Object parseObject(String source) throws ParseException;
|
||||
|
||||
/**
|
||||
* Parse a date/time string according to the given parse position.
|
||||
* See {@link java.text.DateFormat#parseObject(String, ParsePosition)}
|
||||
*/
|
||||
public Object parseObject(String source, ParsePosition pos);
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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.FieldPosition;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* <p>DatePrinter is the "missing" interface for the format methods of
|
||||
* {@link java.text.DateFormat}.</p>
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public interface DatePrinter {
|
||||
|
||||
/**
|
||||
* <p>Formats a millisecond {@code long} value.</p>
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @return the formatted string
|
||||
* @since 2.1
|
||||
*/
|
||||
public String format(long millis);
|
||||
|
||||
/**
|
||||
* <p>Formats a {@code Date} object using a {@code GregorianCalendar}.</p>
|
||||
*
|
||||
* @param date the date to format
|
||||
* @return the formatted string
|
||||
*/
|
||||
public String format(Date date);
|
||||
|
||||
/**
|
||||
* <p>Formats a {@code Calendar} object.</p>
|
||||
*
|
||||
* @param calendar the calendar to format
|
||||
* @return the formatted string
|
||||
*/
|
||||
public String format(Calendar calendar);
|
||||
|
||||
/**
|
||||
* <p>Formats a milliseond {@code long} value into the
|
||||
* supplied {@code StringBuffer}.</p>
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
*/
|
||||
public StringBuffer format(long millis, StringBuffer buf);
|
||||
|
||||
/**
|
||||
* <p>Formats a {@code Date} object into the
|
||||
* supplied {@code StringBuffer} using a {@code GregorianCalendar}.</p>
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
*/
|
||||
public StringBuffer format(Date date, StringBuffer buf);
|
||||
|
||||
/**
|
||||
* <p>Formats a {@code Calendar} object into the
|
||||
* supplied {@code StringBuffer}.</p>
|
||||
*
|
||||
* @param calendar the calendar to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
*/
|
||||
public StringBuffer format(Calendar calendar, StringBuffer buf);
|
||||
|
||||
// Accessors
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Gets the pattern used by this printer.</p>
|
||||
*
|
||||
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||
*/
|
||||
public String getPattern();
|
||||
|
||||
/**
|
||||
* <p>Gets the time zone used by this printer.</p>
|
||||
*
|
||||
* <p>This zone is always used for {@code Date} printing. </p>
|
||||
*
|
||||
* @return the time zone
|
||||
*/
|
||||
public TimeZone getTimeZone();
|
||||
|
||||
/**
|
||||
* <p>Gets the locale used by this printer.</p>
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
public Locale getLocale();
|
||||
|
||||
/**
|
||||
* <p>Formats a {@code Date}, {@code Calendar} or
|
||||
* {@code Long} (milliseconds) object.</p>
|
||||
*
|
||||
* See {@link java.text.DateFormat#format(Object, StringBuffer, FieldPosition)
|
||||
*
|
||||
* @param obj the object to format
|
||||
* @param toAppendTo the buffer to append to
|
||||
* @param pos the position - ignored
|
||||
* @return the buffer passed in
|
||||
*/
|
||||
StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,816 @@
|
|||
/*
|
||||
* 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.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.ParseException;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* <p>FastDateParser is a fast and thread-safe version of
|
||||
* {@link java.text.SimpleDateFormat}.</p>
|
||||
*
|
||||
* <p>This class can be used as a direct replacement to
|
||||
* <code>SimpleDateFormat</code> in most parsing situations.
|
||||
* This class is especially useful in multi-threaded server environments.
|
||||
* <code>SimpleDateFormat</code> is not thread-safe in any JDK version,
|
||||
* nor will it be as Sun have closed the
|
||||
* <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335">bug</a>/RFE.
|
||||
* </p>
|
||||
*
|
||||
* <p>Only parsing is supported, but all patterns are compatible with
|
||||
* SimpleDateFormat.</p>
|
||||
*
|
||||
* <p>Timing tests indicate this class is as about as fast as SimpleDateFormat
|
||||
* in single thread applications and about 25% faster in multi-thread applications.</p>
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public class FastDateParser implements DateParser, Serializable {
|
||||
/**
|
||||
* Required for serialization support.
|
||||
*
|
||||
* @see java.io.Serializable
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final ConcurrentMap<Locale,TimeZoneStrategy> tzsCache=
|
||||
new ConcurrentHashMap<Locale,TimeZoneStrategy>(3);
|
||||
|
||||
// defining fields
|
||||
private final String pattern;
|
||||
private final TimeZone timeZone;
|
||||
private final Locale locale;
|
||||
|
||||
// derived fields
|
||||
private transient Pattern parsePattern;
|
||||
private transient Strategy[] strategies;
|
||||
private transient int thisYear;
|
||||
private transient ConcurrentMap<Integer, KeyValue[]> nameValues;
|
||||
|
||||
// dynamic fields to communicate with Strategy
|
||||
private transient String currentFormatField;
|
||||
private transient Strategy nextStrategy;
|
||||
|
||||
/**
|
||||
* <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
|
||||
*/
|
||||
protected FastDateParser(String pattern, TimeZone timeZone, Locale locale) {
|
||||
this.pattern = pattern;
|
||||
this.timeZone = timeZone;
|
||||
this.locale = locale;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize derived fields from defining fields.
|
||||
* This is called from constructor and from readObject (de-serialization)
|
||||
*/
|
||||
private void init() {
|
||||
thisYear= Calendar.getInstance(timeZone, locale).get(Calendar.YEAR);
|
||||
|
||||
nameValues= new ConcurrentHashMap<Integer, KeyValue[]>();
|
||||
|
||||
StringBuilder regex= new StringBuilder();
|
||||
List<Strategy> collector = new ArrayList<Strategy>();
|
||||
|
||||
Matcher patternMatcher= formatPattern.matcher(pattern);
|
||||
if(!patternMatcher.lookingAt()) {
|
||||
throw new IllegalArgumentException("Invalid pattern");
|
||||
}
|
||||
|
||||
currentFormatField= patternMatcher.group();
|
||||
Strategy currentStrategy= getStrategy(currentFormatField);
|
||||
for(;;) {
|
||||
patternMatcher.region(patternMatcher.end(), patternMatcher.regionEnd());
|
||||
if(!patternMatcher.lookingAt()) {
|
||||
nextStrategy = null;
|
||||
break;
|
||||
}
|
||||
String nextFormatField= patternMatcher.group();
|
||||
nextStrategy = getStrategy(nextFormatField);
|
||||
if(currentStrategy.addRegex(this, regex)) {
|
||||
collector.add(currentStrategy);
|
||||
}
|
||||
currentFormatField= nextFormatField;
|
||||
currentStrategy= nextStrategy;
|
||||
}
|
||||
if(currentStrategy.addRegex(this, regex)) {
|
||||
collector.add(currentStrategy);
|
||||
}
|
||||
currentFormatField= null;
|
||||
strategies= collector.toArray(new Strategy[collector.size()]);
|
||||
parsePattern= Pattern.compile(regex.toString());
|
||||
}
|
||||
|
||||
// Accessors
|
||||
//-----------------------------------------------------------------------
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.lang3.time.DateParser#getPattern()
|
||||
*/
|
||||
@Override
|
||||
public String getPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.lang3.time.DateParser#getTimeZone()
|
||||
*/
|
||||
@Override
|
||||
public TimeZone getTimeZone() {
|
||||
return timeZone;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.lang3.time.DateParser#getLocale()
|
||||
*/
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
// Basics
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>Compare another object for equality with this object.</p>
|
||||
*
|
||||
* @param obj the object to compare to
|
||||
* @return <code>true</code>if equal to this instance
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (! (obj instanceof FastDateParser) ) {
|
||||
return false;
|
||||
}
|
||||
FastDateParser other = (FastDateParser) obj;
|
||||
return pattern.equals(other.pattern)
|
||||
&& timeZone.equals(other.timeZone)
|
||||
&& locale.equals(other.locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Return a hashcode compatible with equals.</p>
|
||||
*
|
||||
* @return a hashcode compatible with equals
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return pattern.hashCode() + 13 * (timeZone.hashCode() + 13 * locale.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get a string version of this formatter.</p>
|
||||
*
|
||||
* @return a debugging string
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FastDateParser[" + pattern + "," + locale + "," + timeZone.getID() + "]";
|
||||
}
|
||||
|
||||
// Serializing
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Create the object after serialization. This implementation reinitializes the
|
||||
* transient properties.
|
||||
*
|
||||
* @param in ObjectInputStream from which the object is being deserialized.
|
||||
* @throws IOException if there is an IO issue.
|
||||
* @throws ClassNotFoundException if a class cannot be found.
|
||||
*/
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
init();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Object parseObject(String source) throws ParseException {
|
||||
return parse(source);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Date parse(String source) throws ParseException {
|
||||
Date date= parse(source, new ParsePosition(0));
|
||||
if(date==null) {
|
||||
throw new ParseException(source+" does not match "+parsePattern.pattern(), 0);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String, java.text.ParsePosition)
|
||||
*/
|
||||
@Override
|
||||
public Object parseObject(String source, ParsePosition pos) {
|
||||
return parse(source, pos);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String, java.text.ParsePosition)
|
||||
*/
|
||||
@Override
|
||||
public Date parse(String source, ParsePosition pos) {
|
||||
int offset= pos.getIndex();
|
||||
Matcher matcher= parsePattern.matcher(source.substring(offset));
|
||||
if(!matcher.lookingAt()) {
|
||||
return null;
|
||||
}
|
||||
// timing tests indicate getting new instance is 19% faster than cloning
|
||||
Calendar cal= Calendar.getInstance(timeZone, locale);
|
||||
cal.clear();
|
||||
|
||||
for(int i=0; i<strategies.length;) {
|
||||
Strategy strategy= strategies[i++];
|
||||
strategy.setCalendar(this, cal, matcher.group(i));
|
||||
}
|
||||
pos.setIndex(offset+matcher.end());
|
||||
return cal.getTime();
|
||||
}
|
||||
|
||||
// Support for strategies
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Escape constant fields into regular expression
|
||||
* @param regex The destination regex
|
||||
* @param value The source field
|
||||
* @param unquote If true, replace two success quotes ('') with single quote (')
|
||||
* @return The <code>StringBuilder</code>
|
||||
*/
|
||||
private static StringBuilder escapeRegex(StringBuilder regex, String value, boolean unquote) {
|
||||
boolean wasWhite= false;
|
||||
for(int i= 0; i<value.length(); ++i) {
|
||||
char c= value.charAt(i);
|
||||
if(Character.isWhitespace(c)) {
|
||||
if(!wasWhite) {
|
||||
wasWhite= true;
|
||||
regex.append("\\s*+");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
wasWhite= false;
|
||||
switch(c) {
|
||||
case '\'':
|
||||
if(unquote) {
|
||||
if(++i==value.length()) {
|
||||
return regex;
|
||||
}
|
||||
c= value.charAt(i);
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case '{':
|
||||
case '}':
|
||||
case '\\':
|
||||
case '|':
|
||||
case '*':
|
||||
case '+':
|
||||
case '^':
|
||||
case '$':
|
||||
case '.':
|
||||
regex.append('\\');
|
||||
}
|
||||
regex.append(c);
|
||||
}
|
||||
return regex;
|
||||
}
|
||||
|
||||
/**
|
||||
* A class to store Key / Value pairs
|
||||
*/
|
||||
private static class KeyValue {
|
||||
public String key;
|
||||
public int value;
|
||||
|
||||
/**
|
||||
* Construct a Key / Value pair
|
||||
* @param key The key
|
||||
* @param value The value
|
||||
*/
|
||||
public KeyValue(String key, int value) {
|
||||
this.key= key;
|
||||
this.value= value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ignore case comparison of keys
|
||||
*/
|
||||
private static final Comparator<KeyValue> IGNORE_CASE_COMPARATOR = new Comparator<KeyValue> () {
|
||||
public int compare(KeyValue left, KeyValue right) {
|
||||
return left.key.compareToIgnoreCase(right.key);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the short and long values displayed for a field
|
||||
* @param field The field of interest
|
||||
* @return A sorted array of the field key / value pairs
|
||||
*/
|
||||
KeyValue[] getDisplayNames(int field) {
|
||||
KeyValue[] fieldKeyValues= nameValues.get(field);
|
||||
if(fieldKeyValues==null) {
|
||||
DateFormatSymbols symbols= DateFormatSymbols.getInstance(locale);
|
||||
switch(field) {
|
||||
case Calendar.ERA:
|
||||
fieldKeyValues= createKeyValues(symbols.getEras(), null);
|
||||
break;
|
||||
case Calendar.DAY_OF_WEEK:
|
||||
fieldKeyValues= createKeyValues(symbols.getWeekdays(), symbols.getShortWeekdays());
|
||||
break;
|
||||
case Calendar.AM_PM:
|
||||
fieldKeyValues= createKeyValues(symbols.getAmPmStrings(), null);
|
||||
break;
|
||||
case Calendar.MONTH:
|
||||
fieldKeyValues= createKeyValues(symbols.getMonths(), symbols.getShortMonths());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid field value "+field);
|
||||
}
|
||||
KeyValue[] prior = nameValues.putIfAbsent(field, fieldKeyValues);
|
||||
if(prior!=null) {
|
||||
fieldKeyValues= prior;
|
||||
}
|
||||
}
|
||||
return fieldKeyValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create key / value pairs from keys
|
||||
* @param longValues The allowable long names for a field
|
||||
* @param shortValues The optional allowable short names for a field
|
||||
* @return The sorted name / value pairs for the field
|
||||
*/
|
||||
private static KeyValue[] createKeyValues(String[] longValues, String[] shortValues) {
|
||||
KeyValue[] fieldKeyValues= new KeyValue[count(longValues)+count(shortValues)];
|
||||
copy(fieldKeyValues, copy(fieldKeyValues, 0, longValues), shortValues);
|
||||
Arrays.sort(fieldKeyValues, IGNORE_CASE_COMPARATOR);
|
||||
return fieldKeyValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a count of valid values in array. A valid value is of non-zero length.
|
||||
* @param values The values to check. This parameter may be null
|
||||
* @return The number of valid values
|
||||
*/
|
||||
private static int count(String[] values) {
|
||||
int count= 0;
|
||||
if(values!=null) {
|
||||
for(String value : values) {
|
||||
if(value.length()>0) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create key / value pairs from values
|
||||
* @param fieldKeyValues The destination array
|
||||
* @param offset The offset into the destination array
|
||||
* @param values The values to use to create key / value pairs. This parameter may be null.
|
||||
* @return The offset into the destination array
|
||||
*/
|
||||
private static int copy(KeyValue[] fieldKeyValues, int offset, String[] values) {
|
||||
if(values!=null) {
|
||||
for(int i= 0; i<values.length; ++i) {
|
||||
String value= values[i];
|
||||
if(value.length()>0) {
|
||||
fieldKeyValues[offset++]= new KeyValue(value, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust dates to be within 80 years before and 20 years after instantiation
|
||||
* @param twoDigitYear The year to adjust
|
||||
* @return A value within -80 and +20 years from instantiation of this instance
|
||||
*/
|
||||
protected int adjustYear(int twoDigitYear) {
|
||||
int trial= twoDigitYear + thisYear - thisYear%100;
|
||||
if(trial < thisYear+20) {
|
||||
return trial;
|
||||
}
|
||||
return trial-100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the next field a number?
|
||||
* @return true, if next field will be a number
|
||||
*/
|
||||
boolean isNextNumber() {
|
||||
return nextStrategy!=null && nextStrategy.isNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* What is the width of the current field?
|
||||
* @return The number of characters in the current format field
|
||||
*/
|
||||
int getFieldWidth() {
|
||||
return currentFormatField.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* A strategy to parse a single field from the parsing pattern
|
||||
*/
|
||||
private interface Strategy {
|
||||
/**
|
||||
* Is this field a number?
|
||||
* @return true, if field is a number
|
||||
*/
|
||||
boolean isNumber();
|
||||
/**
|
||||
* Set the Calendar with the parsed field
|
||||
* @param parser The parser calling this strategy
|
||||
* @param cal The <code>Calendar</code> to set
|
||||
* @param value The parsed field to translate and set in cal
|
||||
*/
|
||||
void setCalendar(FastDateParser parser, Calendar cal, String value);
|
||||
/**
|
||||
* Generate a <code>Pattern</code> regular expression to the <code>StringBuilder</code>
|
||||
* which will accept this field
|
||||
* @param parser The parser calling this strategy
|
||||
* @param regex The <code>StringBuilder</code> to append to
|
||||
* @return true, if this field will set the calendar;
|
||||
* false, if this field is a constant value
|
||||
*/
|
||||
boolean addRegex(FastDateParser parser, StringBuilder regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* A <code>Pattern</code> to parse the user supplied SimpleDateFormat pattern
|
||||
*/
|
||||
private static 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]++");
|
||||
|
||||
/**
|
||||
* Obtain a Strategy given a field from a SimpleDateFormat pattern
|
||||
* @param formatField A sub-sequence of the SimpleDateFormat pattern
|
||||
* @return The Strategy that will handle parsing for the field
|
||||
*/
|
||||
private Strategy getStrategy(String formatField) {
|
||||
switch(formatField.charAt(0)) {
|
||||
case '\'':
|
||||
if(formatField.length()>2) {
|
||||
formatField= formatField.substring(1, formatField.length()-1);
|
||||
}
|
||||
default:
|
||||
return new CopyQuotedStrategy(formatField);
|
||||
case 'D':
|
||||
return DAY_OF_YEAR_STRATEGY;
|
||||
case 'E':
|
||||
return DAY_OF_WEEK_STRATEGY;
|
||||
case 'F':
|
||||
return DAY_OF_WEEK_IN_MONTH_STRATEGY;
|
||||
case 'G':
|
||||
return ERA_STRATEGY;
|
||||
case 'H':
|
||||
return MODULO_HOUR_OF_DAY_STRATEGY;
|
||||
case 'K':
|
||||
return HOUR_STRATEGY;
|
||||
case 'M':
|
||||
return formatField.length()>=3 ?TEXT_MONTH_STRATEGY :NUMBER_MONTH_STRATEGY;
|
||||
case 'S':
|
||||
return MILLISECOND_STRATEGY;
|
||||
case 'W':
|
||||
return WEEK_OF_MONTH_STRATEGY;
|
||||
case 'Z':
|
||||
break;
|
||||
case 'a':
|
||||
return AM_PM_STRATEGY;
|
||||
case 'd':
|
||||
return DAY_OF_MONTH_STRATEGY;
|
||||
case 'h':
|
||||
return MODULO_HOUR_STRATEGY;
|
||||
case 'k':
|
||||
return HOUR_OF_DAY_STRATEGY;
|
||||
case 'm':
|
||||
return MINUTE_STRATEGY;
|
||||
case 's':
|
||||
return SECOND_STRATEGY;
|
||||
case 'w':
|
||||
return WEEK_OF_YEAR_STRATEGY;
|
||||
case 'y':
|
||||
return formatField.length()>2 ?LITERAL_YEAR_STRATEGY :ABBREVIATED_YEAR_STRATEGY;
|
||||
case 'z':
|
||||
break;
|
||||
}
|
||||
TimeZoneStrategy tzs= tzsCache.get(locale);
|
||||
if(tzs==null) {
|
||||
tzs= new TimeZoneStrategy(locale);
|
||||
TimeZoneStrategy inCache= tzsCache.putIfAbsent(locale, tzs);
|
||||
if(inCache!=null) {
|
||||
return inCache;
|
||||
}
|
||||
}
|
||||
return tzs;
|
||||
}
|
||||
|
||||
/**
|
||||
* A strategy that copies the static or quoted field in the parsing pattern
|
||||
*/
|
||||
private static class CopyQuotedStrategy implements Strategy {
|
||||
private final String formatField;
|
||||
|
||||
/**
|
||||
* Construct a Strategy that ensures the formatField has literal text
|
||||
* @param formatField The literal text to match
|
||||
*/
|
||||
CopyQuotedStrategy(String formatField) {
|
||||
this.formatField= formatField;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean isNumber() {
|
||||
char c= formatField.charAt(0);
|
||||
if(c=='\'') {
|
||||
c= formatField.charAt(1);
|
||||
}
|
||||
return Character.isDigit(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean addRegex(FastDateParser parser, StringBuilder regex) {
|
||||
escapeRegex(regex, formatField, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void setCalendar(FastDateParser parser, Calendar cal, String value) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A strategy that handles a text field in the parsing pattern
|
||||
*/
|
||||
private static class TextStrategy implements Strategy {
|
||||
private final int field;
|
||||
|
||||
/**
|
||||
* Construct a Strategy that parses a Text field
|
||||
* @param field The Calendar field
|
||||
*/
|
||||
TextStrategy(int field) {
|
||||
this.field= field;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean isNumber() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean addRegex(FastDateParser parser, StringBuilder regex) {
|
||||
regex.append('(');
|
||||
for(KeyValue textKeyValue : parser.getDisplayNames(field)) {
|
||||
escapeRegex(regex, textKeyValue.key, false).append('|');
|
||||
}
|
||||
regex.setCharAt(regex.length()-1, ')');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void setCalendar(FastDateParser parser, Calendar cal, String value) {
|
||||
KeyValue[] textKeyValues= parser.getDisplayNames(field);
|
||||
int idx= Arrays.binarySearch(textKeyValues, new KeyValue(value, -1), IGNORE_CASE_COMPARATOR);
|
||||
if(idx<0) {
|
||||
StringBuilder sb= new StringBuilder(value);
|
||||
sb.append(" not in (");
|
||||
for(KeyValue textKeyValue : textKeyValues) {
|
||||
sb.append(textKeyValue.key).append(' ');
|
||||
}
|
||||
sb.setCharAt(sb.length()-1, ')');
|
||||
throw new IllegalArgumentException(sb.toString());
|
||||
}
|
||||
cal.set(field, textKeyValues[idx].value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A strategy that handles a number field in the parsing pattern
|
||||
*/
|
||||
private static class NumberStrategy implements Strategy {
|
||||
protected final int field;
|
||||
|
||||
/**
|
||||
* Construct a Strategy that parses a Number field
|
||||
* @param field The Calendar field
|
||||
*/
|
||||
NumberStrategy(int field) {
|
||||
this.field= field;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean isNumber() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean addRegex(FastDateParser parser, StringBuilder regex) {
|
||||
if(parser.isNextNumber()) {
|
||||
regex.append("(\\d{").append(parser.getFieldWidth()).append("}+)");
|
||||
}
|
||||
else {
|
||||
regex.append("(\\d++)");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void setCalendar(FastDateParser parser, Calendar cal, String value) {
|
||||
cal.set(field, modify(Integer.parseInt(value)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Make any modifications to parsed integer
|
||||
* @param iValue The parsed integer
|
||||
* @return The modified value
|
||||
*/
|
||||
public int modify(int iValue) {
|
||||
return iValue;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Strategy ABBREVIATED_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR) {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setCalendar(FastDateParser parser, Calendar cal, String value) {
|
||||
int iValue= Integer.parseInt(value);
|
||||
if(iValue<100) {
|
||||
iValue= parser.adjustYear(iValue);
|
||||
}
|
||||
cal.set(Calendar.YEAR, iValue);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A strategy that handles a timezone field in the parsing pattern
|
||||
*/
|
||||
private static class TimeZoneStrategy implements Strategy {
|
||||
|
||||
final String validTimeZoneChars;
|
||||
final SortedMap<String, TimeZone> tzNames= new TreeMap<String, TimeZone>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
/**
|
||||
* Construct a Strategy that parses a TimeZone
|
||||
* @param locale The Locale
|
||||
*/
|
||||
TimeZoneStrategy(Locale locale) {
|
||||
for(String id : TimeZone.getAvailableIDs()) {
|
||||
if(id.startsWith("GMT")) {
|
||||
continue;
|
||||
}
|
||||
TimeZone tz= TimeZone.getTimeZone(id);
|
||||
tzNames.put(tz.getDisplayName(false, TimeZone.SHORT, locale), tz);
|
||||
tzNames.put(tz.getDisplayName(false, TimeZone.LONG, locale), tz);
|
||||
if(tz.useDaylightTime()) {
|
||||
tzNames.put(tz.getDisplayName(true, TimeZone.SHORT, locale), tz);
|
||||
tzNames.put(tz.getDisplayName(true, TimeZone.LONG, locale), tz);
|
||||
}
|
||||
}
|
||||
StringBuilder sb= new StringBuilder();
|
||||
sb.append("(GMT[+\\-]\\d{0,1}\\d{2}|[+\\-]\\d{2}:?\\d{2}|");
|
||||
for(String id : tzNames.keySet()) {
|
||||
escapeRegex(sb, id, false).append('|');
|
||||
}
|
||||
sb.setCharAt(sb.length()-1, ')');
|
||||
validTimeZoneChars= sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean isNumber() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean addRegex(FastDateParser parser, StringBuilder regex) {
|
||||
regex.append(validTimeZoneChars);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void setCalendar(FastDateParser parser, Calendar cal, String value) {
|
||||
TimeZone tz;
|
||||
if(value.charAt(0)=='+' || value.charAt(0)=='-') {
|
||||
tz= TimeZone.getTimeZone("GMT"+value);
|
||||
}
|
||||
else if(value.startsWith("GMT")) {
|
||||
tz= TimeZone.getTimeZone(value);
|
||||
}
|
||||
else {
|
||||
tz= tzNames.get(value);
|
||||
if(tz==null) {
|
||||
throw new IllegalArgumentException(value + " is not a supported timezone name");
|
||||
}
|
||||
}
|
||||
cal.setTimeZone(tz);
|
||||
}
|
||||
};
|
||||
|
||||
private static final Strategy ERA_STRATEGY = new TextStrategy(Calendar.ERA);
|
||||
private static final Strategy DAY_OF_WEEK_STRATEGY = new TextStrategy(Calendar.DAY_OF_WEEK);
|
||||
private static final Strategy AM_PM_STRATEGY = new TextStrategy(Calendar.AM_PM);
|
||||
private static final Strategy TEXT_MONTH_STRATEGY = new TextStrategy(Calendar.MONTH);
|
||||
|
||||
private static final Strategy NUMBER_MONTH_STRATEGY = new NumberStrategy(Calendar.MONTH) {
|
||||
public int modify(int iValue) {
|
||||
return iValue-1;
|
||||
}
|
||||
};
|
||||
private static final Strategy LITERAL_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR);
|
||||
private static final Strategy WEEK_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_YEAR);
|
||||
private static final Strategy WEEK_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_MONTH);
|
||||
private static final Strategy DAY_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.DAY_OF_YEAR);
|
||||
private static final Strategy DAY_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_MONTH);
|
||||
private static final Strategy DAY_OF_WEEK_IN_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_WEEK_IN_MONTH);
|
||||
private static final Strategy HOUR_OF_DAY_STRATEGY = new NumberStrategy(Calendar.HOUR_OF_DAY);
|
||||
private static final Strategy MODULO_HOUR_OF_DAY_STRATEGY = new NumberStrategy(Calendar.HOUR_OF_DAY) {
|
||||
public int modify(int iValue) {
|
||||
return iValue%24;
|
||||
}
|
||||
};
|
||||
private static final Strategy MODULO_HOUR_STRATEGY = new NumberStrategy(Calendar.HOUR) {
|
||||
public int modify(int iValue) {
|
||||
return iValue%12;
|
||||
}
|
||||
};
|
||||
private static final Strategy HOUR_STRATEGY = new NumberStrategy(Calendar.HOUR);
|
||||
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);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -41,7 +41,7 @@ abstract class FormatCache<F extends Format> {
|
|||
private final ConcurrentMap<MultipartKey, F> cInstanceCache
|
||||
= new ConcurrentHashMap<MultipartKey, F>(7);
|
||||
|
||||
private final ConcurrentMap<MultipartKey, String> cDateTimeInstanceCache
|
||||
private static final ConcurrentMap<MultipartKey, String> cDateTimeInstanceCache
|
||||
= new ConcurrentHashMap<MultipartKey, String>(7);
|
||||
|
||||
/**
|
||||
|
@ -120,6 +120,20 @@ abstract class FormatCache<F extends Format> {
|
|||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
String pattern = getPatternForStyle(dateStyle, timeStyle, locale);
|
||||
return getInstance(pattern, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Gets a date/time format for the specified styles and locale.</p>
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format
|
||||
* @param locale The non-null locale of the desired format
|
||||
* @return a localized standard date/time format
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern defined
|
||||
*/
|
||||
public static String getPatternForStyle(Integer dateStyle, Integer timeStyle, Locale locale) {
|
||||
MultipartKey key = new MultipartKey(dateStyle, timeStyle, locale);
|
||||
|
||||
String pattern = cDateTimeInstanceCache.get(key);
|
||||
|
@ -147,8 +161,7 @@ abstract class FormatCache<F extends Format> {
|
|||
throw new IllegalArgumentException("No date time pattern for locale: " + locale);
|
||||
}
|
||||
}
|
||||
|
||||
return getInstance(pattern, timeZone, locale);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -172,12 +185,9 @@ abstract class FormatCache<F extends Format> {
|
|||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if ( obj instanceof MultipartKey == false ) {
|
||||
return false;
|
||||
}
|
||||
// Eliminate the usual boilerplate because
|
||||
// this inner static class is only used in a generic ConcurrentHashMap
|
||||
// which will not compare against other Object types
|
||||
return Arrays.equals(keys, ((MultipartKey)obj).keys);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,16 +16,25 @@
|
|||
*/
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.text.Format;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests {@link org.apache.commons.lang3.time.FastDateFormat}.
|
||||
|
@ -33,19 +42,21 @@ import org.apache.commons.lang3.SerializationUtils;
|
|||
* @since 2.0
|
||||
* @version $Id$
|
||||
*/
|
||||
public class FastDateFormatTest extends TestCase {
|
||||
|
||||
public FastDateFormatTest(String name) {
|
||||
super(name);
|
||||
}
|
||||
public class FastDateFormatTest {
|
||||
|
||||
/*
|
||||
* Only the cache methods need to be tested here.
|
||||
* The print methods are tested by {@link FastDateFormat_PrinterTest}
|
||||
* and the parse methods are tested by {@link FastDateFormat_ParserTest}
|
||||
*/
|
||||
@Test
|
||||
public void test_getInstance() {
|
||||
FastDateFormat format1 = FastDateFormat.getInstance();
|
||||
FastDateFormat format2 = FastDateFormat.getInstance();
|
||||
assertSame(format1, format2);
|
||||
assertEquals(new SimpleDateFormat().toPattern(), format1.getPattern());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getInstance_String() {
|
||||
FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy");
|
||||
FastDateFormat format2 = FastDateFormat.getInstance("MM-DD-yyyy");
|
||||
|
@ -58,6 +69,7 @@ public class FastDateFormatTest extends TestCase {
|
|||
assertEquals(TimeZone.getDefault(), format2.getTimeZone());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getInstance_String_TimeZone() {
|
||||
Locale realDefaultLocale = Locale.getDefault();
|
||||
TimeZone realDefaultZone = TimeZone.getDefault();
|
||||
|
@ -86,6 +98,7 @@ public class FastDateFormatTest extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getInstance_String_Locale() {
|
||||
Locale realDefaultLocale = Locale.getDefault();
|
||||
try {
|
||||
|
@ -103,6 +116,7 @@ public class FastDateFormatTest extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_changeDefault_Locale_DateInstance() {
|
||||
Locale realDefaultLocale = Locale.getDefault();
|
||||
try {
|
||||
|
@ -123,6 +137,7 @@ public class FastDateFormatTest extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_changeDefault_Locale_DateTimeInstance() {
|
||||
Locale realDefaultLocale = Locale.getDefault();
|
||||
try {
|
||||
|
@ -143,6 +158,7 @@ public class FastDateFormatTest extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getInstance_String_TimeZone_Locale() {
|
||||
Locale realDefaultLocale = Locale.getDefault();
|
||||
TimeZone realDefaultZone = TimeZone.getDefault();
|
||||
|
@ -168,154 +184,128 @@ public class FastDateFormatTest extends TestCase {
|
|||
Locale.setDefault(realDefaultLocale);
|
||||
TimeZone.setDefault(realDefaultZone);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckDefaults() {
|
||||
FastDateFormat format = FastDateFormat.getInstance();
|
||||
FastDateFormat medium = FastDateFormat.getDateTimeInstance(FastDateFormat.SHORT, FastDateFormat.SHORT);
|
||||
assertEquals(medium, format);
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat();
|
||||
assertEquals(sdf.toPattern(), format.getPattern());
|
||||
|
||||
assertEquals(Locale.getDefault(), format.getLocale());
|
||||
assertEquals(TimeZone.getDefault(), format.getTimeZone());
|
||||
}
|
||||
|
||||
public void testFormat() {
|
||||
Locale realDefaultLocale = Locale.getDefault();
|
||||
TimeZone realDefaultZone = TimeZone.getDefault();
|
||||
try {
|
||||
Locale.setDefault(Locale.US);
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
|
||||
@Test
|
||||
public void testCheckDifferingStyles() {
|
||||
FastDateFormat shortShort = FastDateFormat.getDateTimeInstance(FastDateFormat.SHORT, FastDateFormat.SHORT, Locale.US);
|
||||
FastDateFormat shortLong = FastDateFormat.getDateTimeInstance(FastDateFormat.SHORT, FastDateFormat.LONG, Locale.US);
|
||||
FastDateFormat longShort = FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.SHORT, Locale.US);
|
||||
FastDateFormat longLong = FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.LONG, Locale.US);
|
||||
|
||||
assertFalse(shortShort.equals(shortLong));
|
||||
assertFalse(shortShort.equals(longShort));
|
||||
assertFalse(shortShort.equals(longLong));
|
||||
assertFalse(shortLong.equals(longShort));
|
||||
assertFalse(shortLong.equals(longLong));
|
||||
assertFalse(longShort.equals(longLong));
|
||||
}
|
||||
|
||||
GregorianCalendar cal1 = new GregorianCalendar(2003, 0, 10, 15, 33, 20);
|
||||
GregorianCalendar cal2 = new GregorianCalendar(2003, 6, 10, 9, 00, 00);
|
||||
Date date1 = cal1.getTime();
|
||||
Date date2 = cal2.getTime();
|
||||
long millis1 = date1.getTime();
|
||||
long millis2 = date2.getTime();
|
||||
@Test
|
||||
public void testDateDefaults() {
|
||||
assertEquals(FastDateFormat.getDateInstance(FastDateFormat.LONG, Locale.CANADA),
|
||||
FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.CANADA));
|
||||
|
||||
assertEquals(FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZone.getTimeZone("America/New_York")),
|
||||
FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZone.getTimeZone("America/New_York"), Locale.getDefault()));
|
||||
|
||||
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
assertEquals(sdf.format(date1), fdf.format(date1));
|
||||
assertEquals("2003-01-10T15:33:20", fdf.format(date1));
|
||||
assertEquals("2003-01-10T15:33:20", fdf.format(cal1));
|
||||
assertEquals("2003-01-10T15:33:20", fdf.format(millis1));
|
||||
assertEquals("2003-07-10T09:00:00", fdf.format(date2));
|
||||
assertEquals("2003-07-10T09:00:00", fdf.format(cal2));
|
||||
assertEquals("2003-07-10T09:00:00", fdf.format(millis2));
|
||||
assertEquals(FastDateFormat.getDateInstance(FastDateFormat.LONG),
|
||||
FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.getDefault()));
|
||||
}
|
||||
|
||||
fdf = FastDateFormat.getInstance("Z");
|
||||
assertEquals("-0500", fdf.format(date1));
|
||||
assertEquals("-0500", fdf.format(cal1));
|
||||
assertEquals("-0500", fdf.format(millis1));
|
||||
@Test
|
||||
public void testTimeDefaults() {
|
||||
assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG, Locale.CANADA),
|
||||
FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.CANADA));
|
||||
|
||||
assertEquals("-0400", fdf.format(date2));
|
||||
assertEquals("-0400", fdf.format(cal2));
|
||||
assertEquals("-0400", fdf.format(millis2));
|
||||
assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getTimeZone("America/New_York")),
|
||||
FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getTimeZone("America/New_York"), Locale.getDefault()));
|
||||
|
||||
fdf = FastDateFormat.getInstance("ZZ");
|
||||
assertEquals("-05:00", fdf.format(date1));
|
||||
assertEquals("-05:00", fdf.format(cal1));
|
||||
assertEquals("-05:00", fdf.format(millis1));
|
||||
assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG),
|
||||
FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.getDefault()));
|
||||
}
|
||||
|
||||
assertEquals("-04:00", fdf.format(date2));
|
||||
assertEquals("-04:00", fdf.format(cal2));
|
||||
assertEquals("-04:00", fdf.format(millis2));
|
||||
@Test
|
||||
public void testTimeDateDefaults() {
|
||||
assertEquals(FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, Locale.CANADA),
|
||||
FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZone.getDefault(), Locale.CANADA));
|
||||
|
||||
String pattern = "GGGG GGG GG G yyyy yyy yy y MMMM MMM MM M" +
|
||||
" dddd ddd dd d DDDD DDD DD D EEEE EEE EE E aaaa aaa aa a zzzz zzz zz z";
|
||||
fdf = FastDateFormat.getInstance(pattern);
|
||||
sdf = new SimpleDateFormat(pattern);
|
||||
// SDF bug fix starting with Java 7
|
||||
assertEquals(sdf.format(date1).replaceAll("2003 03 03 03", "2003 2003 03 2003"), fdf.format(date1));
|
||||
assertEquals(sdf.format(date2).replaceAll("2003 03 03 03", "2003 2003 03 2003"), fdf.format(date2));
|
||||
} finally {
|
||||
Locale.setDefault(realDefaultLocale);
|
||||
TimeZone.setDefault(realDefaultZone);
|
||||
assertEquals(FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZone.getTimeZone("America/New_York")),
|
||||
FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZone.getTimeZone("America/New_York"), Locale.getDefault()));
|
||||
|
||||
assertEquals(FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM),
|
||||
FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZone.getDefault(), Locale.getDefault()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseSync() throws ParseException, InterruptedException {
|
||||
final FastDateFormat formatter= FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
|
||||
|
||||
long sdfTime= measureTime(formatter, new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z") {
|
||||
private static final long serialVersionUID = 1L; // because SimpleDateFormat is serializable
|
||||
|
||||
@Override
|
||||
public Object parseObject(String formattedDate) throws ParseException {
|
||||
synchronized(this) {
|
||||
return super.parse(formattedDate);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
long fdfTime= measureTime(formatter, FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS Z"));
|
||||
|
||||
String times= "FastDateParser:"+fdfTime+" SimpleDateFormat:"+sdfTime;
|
||||
System.out.println(times);
|
||||
}
|
||||
|
||||
final static private int NTHREADS= 10;
|
||||
final static private int NROUNDS= 10000;
|
||||
|
||||
private long measureTime(final Format formatter, final Format parser) throws ParseException, InterruptedException {
|
||||
final ExecutorService pool = Executors.newFixedThreadPool(NTHREADS);
|
||||
final AtomicInteger failures= new AtomicInteger(0);
|
||||
final AtomicLong totalElapsed= new AtomicLong(0);
|
||||
|
||||
for(int i= 0; i<NTHREADS; ++i) {
|
||||
pool.submit(new Runnable() {
|
||||
public void run() {
|
||||
for(int i= 0; i<NROUNDS; ++i) {
|
||||
try {
|
||||
Date date= new Date();
|
||||
String formattedDate= formatter.format(date);
|
||||
long start= System.currentTimeMillis();
|
||||
Object pd= parser.parseObject(formattedDate);
|
||||
totalElapsed.addAndGet(System.currentTimeMillis()-start);
|
||||
if(!date.equals(pd)) {
|
||||
failures.incrementAndGet();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
failures.incrementAndGet();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case for {@link FastDateFormat#getDateInstance(int, java.util.Locale)}.
|
||||
*/
|
||||
public void testShortDateStyleWithLocales() {
|
||||
Locale usLocale = Locale.US;
|
||||
Locale swedishLocale = new Locale("sv", "SE");
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(2004, 1, 3);
|
||||
FastDateFormat fdf = FastDateFormat.getDateInstance(FastDateFormat.SHORT, usLocale);
|
||||
assertEquals("2/3/04", fdf.format(cal));
|
||||
|
||||
fdf = FastDateFormat.getDateInstance(FastDateFormat.SHORT, swedishLocale);
|
||||
assertEquals("2004-02-03", fdf.format(cal));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that pre-1000AD years get padded with yyyy
|
||||
*/
|
||||
public void testLowYearPadding() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
FastDateFormat format = FastDateFormat.getInstance("yyyy/MM/DD");
|
||||
|
||||
cal.set(1,0,1);
|
||||
assertEquals("0001/01/01", format.format(cal));
|
||||
cal.set(10,0,1);
|
||||
assertEquals("0010/01/01", format.format(cal));
|
||||
cal.set(100,0,1);
|
||||
assertEquals("0100/01/01", format.format(cal));
|
||||
cal.set(999,0,1);
|
||||
assertEquals("0999/01/01", format.format(cal));
|
||||
}
|
||||
/**
|
||||
* Show Bug #39410 is solved
|
||||
*/
|
||||
public void testMilleniumBug() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
FastDateFormat format = FastDateFormat.getInstance("dd.MM.yyyy");
|
||||
|
||||
cal.set(1000,0,1);
|
||||
assertEquals("01.01.1000", format.format(cal));
|
||||
}
|
||||
|
||||
/**
|
||||
* testLowYearPadding showed that the date was buggy
|
||||
* This test confirms it, getting 366 back as a date
|
||||
*/
|
||||
public void testSimpleDate() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
FastDateFormat format = FastDateFormat.getInstance("yyyy/MM/dd");
|
||||
|
||||
cal.set(2004,11,31);
|
||||
assertEquals("2004/12/31", format.format(cal));
|
||||
cal.set(999,11,31);
|
||||
assertEquals("0999/12/31", format.format(cal));
|
||||
cal.set(1,2,2);
|
||||
assertEquals("0001/03/02", format.format(cal));
|
||||
}
|
||||
|
||||
public void testLang303() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(2004,11,31);
|
||||
|
||||
FastDateFormat format = FastDateFormat.getInstance("yyyy/MM/dd");
|
||||
String output = format.format(cal);
|
||||
|
||||
format = (FastDateFormat) SerializationUtils.deserialize( SerializationUtils.serialize( format ) );
|
||||
assertEquals(output, format.format(cal));
|
||||
}
|
||||
|
||||
public void testLang538() {
|
||||
// more commonly constructed with: cal = new GregorianCalendar(2009, 9, 16, 8, 42, 16)
|
||||
// for the unit test to work in any time zone, constructing with GMT-8 rather than default locale time zone
|
||||
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT-8"));
|
||||
cal.clear();
|
||||
cal.set(2009, 9, 16, 8, 42, 16);
|
||||
|
||||
FastDateFormat format = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("GMT"));
|
||||
assertEquals("dateTime", "2009-10-16T16:42:16.000Z", format.format(cal.getTime()));
|
||||
assertEquals("dateTime", "2009-10-16T08:42:16.000Z", format.format(cal));
|
||||
}
|
||||
|
||||
public void testLang645() {
|
||||
Locale locale = new Locale("sv", "SE");
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(2010, 0, 1, 12, 0, 0);
|
||||
Date d = cal.getTime();
|
||||
|
||||
FastDateFormat fdf = FastDateFormat.getInstance("EEEE', week 'ww", locale);
|
||||
|
||||
assertEquals("fredag, week 53", fdf.format(d));
|
||||
pool.shutdown();
|
||||
if(!pool.awaitTermination(20, TimeUnit.SECONDS)) {
|
||||
pool.shutdownNow();
|
||||
fail("did not complete tasks");
|
||||
}
|
||||
assertEquals(0, failures.get());
|
||||
return totalElapsed.get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Unit tests for the parse methods of FastDateFormat
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public class FastDateFormat_ParserTest extends FastDateParserTest {
|
||||
|
||||
@Override
|
||||
protected DateParser getInstance(String format, TimeZone timeZone, Locale locale) {
|
||||
return FastDateFormat.getInstance(format, timeZone, locale);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Unit tests for the print methods of FastDateFormat
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public class FastDateFormat_PrinterTest extends FastDatePrinterTest {
|
||||
|
||||
@Override
|
||||
protected DatePrinter getInstance(String format, TimeZone timeZone, Locale locale) {
|
||||
return FastDateFormat.getInstance(format, timeZone, locale);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional inparserion 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 static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests {@link org.apache.commons.lang3.time.FastDateParser}.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public class FastDateParserTest {
|
||||
private static final String yMdHmsSZ = "yyyy-MM-dd'T'HH:mm:ss.SSS Z";
|
||||
private static final String DMY_DOT = "dd.MM.yyyy";
|
||||
private static final String YMD_SLASH = "yyyy/MM/dd";
|
||||
private static final String MDY_DASH = "MM-DD-yyyy";
|
||||
private static final String MDY_SLASH = "MM/DD/yyyy";
|
||||
private static final TimeZone REYKJAVIK = TimeZone.getTimeZone("Atlantic/Reykjavik");
|
||||
private static final TimeZone NEW_YORK = TimeZone.getTimeZone("America/New_York");
|
||||
private static final Locale SWEDEN = new Locale("sv", "SE");
|
||||
|
||||
DateParser getInstance(String format) {
|
||||
return getInstance(format, TimeZone.getDefault(), Locale.getDefault());
|
||||
}
|
||||
|
||||
private DateParser getDateInstance(int dateStyle, Locale locale) {
|
||||
return getInstance(FormatCache.getPatternForStyle(dateStyle, null, locale), TimeZone.getDefault(), Locale.getDefault());
|
||||
}
|
||||
|
||||
private DateParser getInstance(String format, Locale locale) {
|
||||
return getInstance(format, TimeZone.getDefault(), locale);
|
||||
}
|
||||
|
||||
private DateParser getInstance(String format, TimeZone timeZone) {
|
||||
return getInstance(format, timeZone, Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method in derived tests to change the construction of instances
|
||||
* @param format
|
||||
* @param timeZone
|
||||
* @param locale
|
||||
* @return
|
||||
*/
|
||||
protected DateParser getInstance(String format, TimeZone timeZone, Locale locale) {
|
||||
return new FastDateParser(format, timeZone, locale);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Equality_Hash() {
|
||||
DateParser[] parsers= {
|
||||
getInstance(yMdHmsSZ, NEW_YORK, Locale.US),
|
||||
getInstance(DMY_DOT, NEW_YORK, Locale.US),
|
||||
getInstance(YMD_SLASH, NEW_YORK, Locale.US),
|
||||
getInstance(MDY_DASH, NEW_YORK, Locale.US),
|
||||
getInstance(MDY_SLASH, NEW_YORK, Locale.US),
|
||||
getInstance(MDY_SLASH, REYKJAVIK, Locale.US),
|
||||
getInstance(MDY_SLASH, REYKJAVIK, SWEDEN)
|
||||
};
|
||||
|
||||
Map<DateParser,Integer> map= new HashMap<DateParser,Integer>();
|
||||
int i= 0;
|
||||
for(DateParser parser:parsers) {
|
||||
map.put(parser, i++);
|
||||
}
|
||||
|
||||
i= 0;
|
||||
for(DateParser parser:parsers) {
|
||||
assertEquals(i++, (int)map.get(parser));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseZone() throws ParseException {
|
||||
Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
|
||||
cal.clear();
|
||||
cal.set(2003, 6, 10, 16, 33, 20);
|
||||
|
||||
DateParser fdf = getInstance(yMdHmsSZ, NEW_YORK, Locale.US);
|
||||
|
||||
assertEquals(cal.getTime(), fdf.parse("2003-07-10T15:33:20.000 -0500"));
|
||||
assertEquals(cal.getTime(), fdf.parse("2003-07-10T15:33:20.000 GMT-05:00"));
|
||||
assertEquals(cal.getTime(), fdf.parse("2003-07-10T16:33:20.000 Eastern Daylight Time"));
|
||||
assertEquals(cal.getTime(), fdf.parse("2003-07-10T16:33:20.000 EDT"));
|
||||
|
||||
cal.setTimeZone(TimeZone.getTimeZone("GMT-3"));
|
||||
cal.set(2003, 1, 10, 9, 0, 0);
|
||||
|
||||
assertEquals(cal.getTime(), fdf.parse("2003-02-10T09:00:00.000 -0300"));
|
||||
|
||||
cal.setTimeZone(TimeZone.getTimeZone("GMT+5"));
|
||||
cal.set(2003, 1, 10, 15, 5, 6);
|
||||
|
||||
assertEquals(cal.getTime(), fdf.parse("2003-02-10T15:05:06.000 +0500"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseLongShort() throws ParseException {
|
||||
Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
|
||||
cal.clear();
|
||||
cal.set(2003, 1, 10, 15, 33, 20);
|
||||
cal.set(Calendar.MILLISECOND, 989);
|
||||
cal.setTimeZone(NEW_YORK);
|
||||
|
||||
DateParser fdf = getInstance("yyyy GGGG MMMM dddd aaaa EEEE HHHH mmmm ssss SSSS ZZZZ", NEW_YORK, Locale.US);
|
||||
|
||||
assertEquals(cal.getTime(), fdf.parse("2003 AD February 0010 PM Monday 0015 0033 0020 0989 GMT-05:00"));
|
||||
cal.set(Calendar.ERA, GregorianCalendar.BC);
|
||||
|
||||
Date parse = fdf.parse("2003 BC February 0010 PM Saturday 0015 0033 0020 0989 GMT-05:00");
|
||||
assertEquals(cal.getTime(), parse);
|
||||
|
||||
fdf = getInstance("y G M d a E H m s S Z");
|
||||
assertEquals(cal.getTime(), fdf.parse("03 BC 2 10 PM Sat 15 33 20 989 -0500"));
|
||||
|
||||
cal.set(Calendar.ERA, GregorianCalendar.AD);
|
||||
assertEquals(cal.getTime(), fdf.parse("03 AD 2 10 PM Saturday 15 33 20 989 -0500"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAmPm() throws ParseException {
|
||||
Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
|
||||
cal.clear();
|
||||
|
||||
DateParser h = getInstance("yyyy-MM-dd hh a mm:ss", NEW_YORK, Locale.US);
|
||||
DateParser K = getInstance("yyyy-MM-dd KK a mm:ss", NEW_YORK, Locale.US);
|
||||
DateParser k = getInstance("yyyy-MM-dd kk:mm:ss", NEW_YORK, Locale.US);
|
||||
DateParser H = getInstance("yyyy-MM-dd HH:mm:ss", NEW_YORK, Locale.US);
|
||||
|
||||
cal.set(2010, 7, 1, 0, 33, 20);
|
||||
assertEquals(cal.getTime(), h.parse("2010-08-01 12 AM 33:20"));
|
||||
assertEquals(cal.getTime(), K.parse("2010-08-01 0 AM 33:20"));
|
||||
assertEquals(cal.getTime(), k.parse("2010-08-01 00:33:20"));
|
||||
assertEquals(cal.getTime(), H.parse("2010-08-01 00:33:20"));
|
||||
|
||||
cal.set(2010, 7, 1, 3, 33, 20);
|
||||
assertEquals(cal.getTime(), h.parse("2010-08-01 3 AM 33:20"));
|
||||
assertEquals(cal.getTime(), K.parse("2010-08-01 3 AM 33:20"));
|
||||
assertEquals(cal.getTime(), k.parse("2010-08-01 03:33:20"));
|
||||
assertEquals(cal.getTime(), H.parse("2010-08-01 03:33:20"));
|
||||
|
||||
cal.set(2010, 7, 1, 15, 33, 20);
|
||||
assertEquals(cal.getTime(), h.parse("2010-08-01 3 PM 33:20"));
|
||||
assertEquals(cal.getTime(), K.parse("2010-08-01 3 PM 33:20"));
|
||||
assertEquals(cal.getTime(), k.parse("2010-08-01 15:33:20"));
|
||||
assertEquals(cal.getTime(), H.parse("2010-08-01 15:33:20"));
|
||||
|
||||
cal.set(2010, 7, 1, 12, 33, 20);
|
||||
assertEquals(cal.getTime(), h.parse("2010-08-01 12 PM 33:20"));
|
||||
assertEquals(cal.getTime(), K.parse("2010-08-01 0 PM 33:20"));
|
||||
assertEquals(cal.getTime(), k.parse("2010-08-01 12:33:20"));
|
||||
assertEquals(cal.getTime(), H.parse("2010-08-01 12:33:20"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocales() throws ParseException {
|
||||
|
||||
for(Locale locale : Locale.getAvailableLocales()) {
|
||||
Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
|
||||
cal.clear();
|
||||
cal.set(2003, 1, 10);
|
||||
|
||||
try {
|
||||
String longFormat= "GGGG/yyyy/MMMM/dddd/aaaa/EEEE/ZZZZ";
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(longFormat, locale);
|
||||
DateParser fdf = getInstance(longFormat, locale);
|
||||
|
||||
checkParse(cal, sdf, fdf);
|
||||
|
||||
cal.set(Calendar.ERA, GregorianCalendar.BC);
|
||||
checkParse(cal, sdf, fdf);
|
||||
|
||||
String shortFormat= "G/y/M/d/a/E/Z";
|
||||
sdf = new SimpleDateFormat(shortFormat, locale);
|
||||
fdf = getInstance(shortFormat, locale);
|
||||
checkParse(cal, sdf, fdf);
|
||||
|
||||
cal.set(Calendar.ERA, GregorianCalendar.AD);
|
||||
checkParse(cal, sdf, fdf);
|
||||
}
|
||||
catch(ParseException ex) {
|
||||
// TODO: why do ja_JP_JP, hi_IN, th_TH, and th_TH_TH fail?
|
||||
System.out.println("Locale "+locale+ " failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkParse(Calendar cal, SimpleDateFormat sdf, DateParser fdf) throws ParseException {
|
||||
String formattedDate= sdf.format(cal.getTime());
|
||||
Date expectedTime = sdf.parse(formattedDate);
|
||||
Date actualTime = fdf.parse(formattedDate);
|
||||
assertEquals(expectedTime, actualTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseNumerics() throws ParseException {
|
||||
Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
|
||||
cal.clear();
|
||||
cal.set(2003, 1, 10, 15, 33, 20);
|
||||
cal.set(Calendar.MILLISECOND, 989);
|
||||
|
||||
DateParser fdf = getInstance("yyyyMMddHHmmssSSS", NEW_YORK, Locale.US);
|
||||
assertEquals(cal.getTime(), fdf.parse("20030210153320989"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuotes() throws ParseException {
|
||||
Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
|
||||
cal.clear();
|
||||
cal.set(2003, 1, 10, 15, 33, 20);
|
||||
cal.set(Calendar.MILLISECOND, 989);
|
||||
|
||||
DateParser fdf = getInstance("''yyyyMMdd'A''B'HHmmssSSS''", NEW_YORK, Locale.US);
|
||||
assertEquals(cal.getTime(), fdf.parse("'20030210A'B153320989'"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDayOf() throws ParseException {
|
||||
Calendar cal= Calendar.getInstance(NEW_YORK, Locale.US);
|
||||
cal.clear();
|
||||
cal.set(2003, 1, 10);
|
||||
|
||||
DateParser fdf = getInstance("W w F D y", NEW_YORK, Locale.US);
|
||||
assertEquals(cal.getTime(), fdf.parse("3 7 2 41 03"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case for {@link FastDateParser#getDateInstance(int, java.util.Locale)}.
|
||||
* @throws ParseException
|
||||
*/
|
||||
@Test
|
||||
public void testShortDateStyleWithLocales() throws ParseException {
|
||||
DateParser fdf = getDateInstance(FastDateFormat.SHORT, Locale.US);
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.clear();
|
||||
|
||||
cal.set(2004, 1, 3);
|
||||
assertEquals(cal.getTime(), fdf.parse("2/3/04"));
|
||||
|
||||
fdf = getDateInstance(FastDateFormat.SHORT, SWEDEN);
|
||||
assertEquals(cal.getTime(), fdf.parse("2004-02-03"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that pre-1000AD years get padded with yyyy
|
||||
* @throws ParseException
|
||||
*/
|
||||
@Test
|
||||
public void testLowYearPadding() throws ParseException {
|
||||
DateParser parser = getInstance(YMD_SLASH);
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.clear();
|
||||
|
||||
cal.set(1,0,1);
|
||||
assertEquals(cal.getTime(), parser.parse("0001/01/01"));
|
||||
cal.set(10,0,1);
|
||||
assertEquals(cal.getTime(), parser.parse("0010/01/01"));
|
||||
cal.set(100,0,1);
|
||||
assertEquals(cal.getTime(), parser.parse("0100/01/01"));
|
||||
cal.set(999,0,1);
|
||||
assertEquals(cal.getTime(), parser.parse("0999/01/01"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ParseException
|
||||
*/
|
||||
@Test
|
||||
public void testMilleniumBug() throws ParseException {
|
||||
DateParser parser = getInstance(DMY_DOT);
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.clear();
|
||||
|
||||
cal.set(1000,0,1);
|
||||
assertEquals(cal.getTime(), parser.parse("01.01.1000"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLang303() throws ParseException {
|
||||
DateParser parser = getInstance(YMD_SLASH);
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(2004,11,31);
|
||||
|
||||
Date date = parser.parse("2004/11/31");
|
||||
|
||||
parser = (DateParser) SerializationUtils.deserialize( SerializationUtils.serialize( (Serializable)parser ) );
|
||||
assertEquals(date, parser.parse("2004/11/31"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLang538() throws ParseException {
|
||||
DateParser parser = getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("GMT"));
|
||||
|
||||
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT-8"));
|
||||
cal.clear();
|
||||
cal.set(2009, 9, 16, 8, 42, 16);
|
||||
|
||||
assertEquals(cal.getTime(), parser.parse("2009-10-16T16:42:16.000Z"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
DateParser parser1= getInstance(YMD_SLASH);
|
||||
DateParser parser2= getInstance(YMD_SLASH);
|
||||
|
||||
assertEquals(parser1, parser2);
|
||||
assertEquals(parser1.hashCode(), parser2.hashCode());
|
||||
|
||||
assertFalse(parser1.equals(new Object()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToStringContainsName() {
|
||||
DateParser parser= getInstance(YMD_SLASH);
|
||||
assertTrue(parser.toString().startsWith("FastDate"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatternMatches() {
|
||||
DateParser parser= getInstance(yMdHmsSZ);
|
||||
assertEquals(yMdHmsSZ, parser.getPattern());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocaleMatches() {
|
||||
DateParser parser= getInstance(yMdHmsSZ, SWEDEN);
|
||||
assertEquals(SWEDEN, parser.getLocale());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeZoneMatches() {
|
||||
DateParser parser= getInstance(yMdHmsSZ, REYKJAVIK);
|
||||
assertEquals(REYKJAVIK, parser.getTimeZone());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* 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 static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests {@link org.apache.commons.lang3.time.FastDatePrinter}.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
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 Locale SWEDEN = new Locale("sv", "SE");
|
||||
|
||||
DatePrinter getInstance(String format) {
|
||||
return getInstance(format, TimeZone.getDefault(), Locale.getDefault());
|
||||
}
|
||||
|
||||
private DatePrinter getDateInstance(int dateStyle, Locale locale) {
|
||||
return getInstance(FormatCache.getPatternForStyle(dateStyle, null, locale), TimeZone.getDefault(), Locale.getDefault());
|
||||
}
|
||||
|
||||
private DatePrinter getInstance(String format, Locale locale) {
|
||||
return getInstance(format, TimeZone.getDefault(), locale);
|
||||
}
|
||||
|
||||
private DatePrinter getInstance(String format, TimeZone timeZone) {
|
||||
return getInstance(format, timeZone, Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method in derived tests to change the construction of instances
|
||||
* @param format
|
||||
* @param timeZone
|
||||
* @param locale
|
||||
* @return
|
||||
*/
|
||||
protected DatePrinter getInstance(String format, TimeZone timeZone, Locale locale) {
|
||||
return new FastDatePrinter(format, timeZone, locale);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormat() {
|
||||
Locale realDefaultLocale = Locale.getDefault();
|
||||
TimeZone realDefaultZone = TimeZone.getDefault();
|
||||
try {
|
||||
Locale.setDefault(Locale.US);
|
||||
TimeZone.setDefault(NEW_YORK);
|
||||
|
||||
GregorianCalendar cal1 = new GregorianCalendar(2003, 0, 10, 15, 33, 20);
|
||||
GregorianCalendar cal2 = new GregorianCalendar(2003, 6, 10, 9, 00, 00);
|
||||
Date date1 = cal1.getTime();
|
||||
Date date2 = cal2.getTime();
|
||||
long millis1 = date1.getTime();
|
||||
long millis2 = date2.getTime();
|
||||
|
||||
DatePrinter fdf = getInstance("yyyy-MM-dd'T'HH:mm:ss");
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
assertEquals(sdf.format(date1), fdf.format(date1));
|
||||
assertEquals("2003-01-10T15:33:20", fdf.format(date1));
|
||||
assertEquals("2003-01-10T15:33:20", fdf.format(cal1));
|
||||
assertEquals("2003-01-10T15:33:20", fdf.format(millis1));
|
||||
assertEquals("2003-07-10T09:00:00", fdf.format(date2));
|
||||
assertEquals("2003-07-10T09:00:00", fdf.format(cal2));
|
||||
assertEquals("2003-07-10T09:00:00", fdf.format(millis2));
|
||||
|
||||
fdf = getInstance("Z");
|
||||
assertEquals("-0500", fdf.format(date1));
|
||||
assertEquals("-0500", fdf.format(cal1));
|
||||
assertEquals("-0500", fdf.format(millis1));
|
||||
|
||||
assertEquals("-0400", fdf.format(date2));
|
||||
assertEquals("-0400", fdf.format(cal2));
|
||||
assertEquals("-0400", fdf.format(millis2));
|
||||
|
||||
fdf = getInstance("ZZ");
|
||||
assertEquals("-05:00", fdf.format(date1));
|
||||
assertEquals("-05:00", fdf.format(cal1));
|
||||
assertEquals("-05:00", fdf.format(millis1));
|
||||
|
||||
assertEquals("-04:00", fdf.format(date2));
|
||||
assertEquals("-04:00", fdf.format(cal2));
|
||||
assertEquals("-04:00", fdf.format(millis2));
|
||||
|
||||
String pattern = "GGGG GGG GG G yyyy yyy yy y MMMM MMM MM M" +
|
||||
" dddd ddd dd d DDDD DDD DD D EEEE EEE EE E aaaa aaa aa a zzzz zzz zz z";
|
||||
fdf = getInstance(pattern);
|
||||
sdf = new SimpleDateFormat(pattern);
|
||||
// SDF bug fix starting with Java 7
|
||||
assertEquals(sdf.format(date1).replaceAll("2003 03 03 03", "2003 2003 03 2003"), fdf.format(date1));
|
||||
assertEquals(sdf.format(date2).replaceAll("2003 03 03 03", "2003 2003 03 2003"), fdf.format(date2));
|
||||
} finally {
|
||||
Locale.setDefault(realDefaultLocale);
|
||||
TimeZone.setDefault(realDefaultZone);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case for {@link FastDatePrinter#getDateInstance(int, java.util.Locale)}.
|
||||
*/
|
||||
@Test
|
||||
public void testShortDateStyleWithLocales() {
|
||||
Locale usLocale = Locale.US;
|
||||
Locale swedishLocale = new Locale("sv", "SE");
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(2004, 1, 3);
|
||||
DatePrinter fdf = getDateInstance(FastDateFormat.SHORT, usLocale);
|
||||
assertEquals("2/3/04", fdf.format(cal));
|
||||
|
||||
fdf = getDateInstance(FastDateFormat.SHORT, swedishLocale);
|
||||
assertEquals("2004-02-03", fdf.format(cal));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that pre-1000AD years get padded with yyyy
|
||||
*/
|
||||
@Test
|
||||
public void testLowYearPadding() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
DatePrinter format = getInstance(YYYY_MM_DD);
|
||||
|
||||
cal.set(1,0,1);
|
||||
assertEquals("0001/01/01", format.format(cal));
|
||||
cal.set(10,0,1);
|
||||
assertEquals("0010/01/01", format.format(cal));
|
||||
cal.set(100,0,1);
|
||||
assertEquals("0100/01/01", format.format(cal));
|
||||
cal.set(999,0,1);
|
||||
assertEquals("0999/01/01", format.format(cal));
|
||||
}
|
||||
/**
|
||||
* Show Bug #39410 is solved
|
||||
*/
|
||||
@Test
|
||||
public void testMilleniumBug() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
DatePrinter format = getInstance("dd.MM.yyyy");
|
||||
|
||||
cal.set(1000,0,1);
|
||||
assertEquals("01.01.1000", format.format(cal));
|
||||
}
|
||||
|
||||
/**
|
||||
* testLowYearPadding showed that the date was buggy
|
||||
* This test confirms it, getting 366 back as a date
|
||||
*/
|
||||
@Test
|
||||
public void testSimpleDate() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
DatePrinter format = getInstance(YYYY_MM_DD);
|
||||
|
||||
cal.set(2004,11,31);
|
||||
assertEquals("2004/12/31", format.format(cal));
|
||||
cal.set(999,11,31);
|
||||
assertEquals("0999/12/31", format.format(cal));
|
||||
cal.set(1,2,2);
|
||||
assertEquals("0001/03/02", format.format(cal));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLang303() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(2004,11,31);
|
||||
|
||||
DatePrinter format = getInstance(YYYY_MM_DD);
|
||||
String output = format.format(cal);
|
||||
|
||||
format = (DatePrinter) SerializationUtils.deserialize( SerializationUtils.serialize( (Serializable)format ) );
|
||||
assertEquals(output, format.format(cal));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLang538() {
|
||||
// more commonly constructed with: cal = new GregorianCalendar(2009, 9, 16, 8, 42, 16)
|
||||
// for the unit test to work in any time zone, constructing with GMT-8 rather than default locale time zone
|
||||
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT-8"));
|
||||
cal.clear();
|
||||
cal.set(2009, 9, 16, 8, 42, 16);
|
||||
|
||||
DatePrinter format = getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("GMT"));
|
||||
assertEquals("dateTime", "2009-10-16T16:42:16.000Z", format.format(cal.getTime()));
|
||||
assertEquals("dateTime", "2009-10-16T08:42:16.000Z", format.format(cal));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLang645() {
|
||||
Locale locale = new Locale("sv", "SE");
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(2010, 0, 1, 12, 0, 0);
|
||||
Date d = cal.getTime();
|
||||
|
||||
DatePrinter fdf = getInstance("EEEE', week 'ww", locale);
|
||||
|
||||
assertEquals("fredag, week 53", fdf.format(d));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
DatePrinter printer1= getInstance(YYYY_MM_DD);
|
||||
DatePrinter printer2= getInstance(YYYY_MM_DD);
|
||||
|
||||
assertEquals(printer1, printer2);
|
||||
assertEquals(printer1.hashCode(), printer2.hashCode());
|
||||
|
||||
assertFalse(printer1.equals(new Object()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToStringContainsName() {
|
||||
DatePrinter printer= getInstance(YYYY_MM_DD);
|
||||
assertTrue(printer.toString().startsWith("FastDate"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatternMatches() {
|
||||
DatePrinter printer= getInstance(YYYY_MM_DD);
|
||||
assertEquals(YYYY_MM_DD, printer.getPattern());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocaleMatches() {
|
||||
DatePrinter printer= getInstance(YYYY_MM_DD, SWEDEN);
|
||||
assertEquals(SWEDEN, printer.getLocale());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeZoneMatches() {
|
||||
DatePrinter printer= getInstance(YYYY_MM_DD, NEW_YORK);
|
||||
assertEquals(NEW_YORK, printer.getTimeZone());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue