Rework time package in preparation for 2.0 release
DateUtils split to DateFormatUtils and DurationFormatUtils CalendarUtils renamed to DateUtils StopWatch time format method moved to DurationFormatUtils Tests updated and pass git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137361 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9bb3f9b9a3
commit
73ee6c3d27
|
@ -1,506 +0,0 @@
|
|||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution, if
|
||||
* any, must include the following acknowlegement:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowlegement may appear in the software itself,
|
||||
* if and wherever such third-party acknowlegements normally appear.
|
||||
*
|
||||
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
|
||||
* Foundation" must not be used to endorse or promote products derived
|
||||
* from this software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache"
|
||||
* nor may "Apache" appear in their names without prior written
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
package org.apache.commons.lang.time;
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A suite of utilities surrounding the use of the Calendar and Date object.
|
||||
*
|
||||
* @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
|
||||
* @since 2.1
|
||||
* @version $Id: CalendarUtils.java,v 1.3 2003/04/09 01:04:48 ggregory Exp $
|
||||
*/
|
||||
public class CalendarUtils {
|
||||
|
||||
/**
|
||||
* This is half a month, so this represents whether a date is in the top
|
||||
* or bottom half of the month.
|
||||
*/
|
||||
public final static int SEMI_MONTH = 1001;
|
||||
|
||||
private static final int[][] fields = {
|
||||
{Calendar.MILLISECOND},
|
||||
{Calendar.SECOND},
|
||||
{Calendar.MINUTE},
|
||||
{Calendar.HOUR_OF_DAY, Calendar.HOUR},
|
||||
{Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */},
|
||||
{Calendar.MONTH, CalendarUtils.SEMI_MONTH},
|
||||
{Calendar.YEAR},
|
||||
{Calendar.ERA}};
|
||||
|
||||
private static DateFormat[] dateFormats = {
|
||||
//3/31/92 10:00:07 PST
|
||||
new SimpleDateFormat("M/dd/yy h:mm:ss z"),
|
||||
//January 23, 1987 10:05pm
|
||||
new SimpleDateFormat("MMM d, yyyy h:mm a"),
|
||||
//22:00 GMT
|
||||
new SimpleDateFormat("h:mm z")};
|
||||
|
||||
/**
|
||||
* A week range, starting on Sunday.
|
||||
*/
|
||||
public final static int RANGE_WEEK_SUNDAY = 1;
|
||||
|
||||
/**
|
||||
* A week range, starting on Monday.
|
||||
*/
|
||||
public final static int RANGE_WEEK_MONDAY = 2;
|
||||
|
||||
/**
|
||||
* A week range, starting on the day focused.
|
||||
*/
|
||||
public final static int RANGE_WEEK_RELATIVE = 3;
|
||||
|
||||
/**
|
||||
* A week range, centered around the day focused.
|
||||
*/
|
||||
public final static int RANGE_WEEK_CENTER = 4;
|
||||
|
||||
/**
|
||||
* A month range, the week starting on Sunday.
|
||||
*/
|
||||
public final static int RANGE_MONTH_SUNDAY = 5;
|
||||
|
||||
/**
|
||||
* A month range, the week starting on Monday.
|
||||
*/
|
||||
public final static int RANGE_MONTH_MONDAY = 6;
|
||||
|
||||
/**
|
||||
* See the other round method. Works with a Date object.
|
||||
*/
|
||||
public static Date round(Date val, int field) {
|
||||
GregorianCalendar gval = new GregorianCalendar();
|
||||
gval.setTime(val);
|
||||
modify(gval, field, true);
|
||||
return gval.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Round this date, leaving the field specified as the most significant
|
||||
* field. For example, if you had the datetime of 28 Mar 2002
|
||||
* 13:45:01.231, if this was passed with HOUR, it would return 28 Mar
|
||||
* 2002 14:00:00.000. If this was passed with MONTH, it would return
|
||||
* 1 April 2002 0:00:00.000.
|
||||
*/
|
||||
public static Calendar round(Calendar val, int field) {
|
||||
Calendar rounded = (Calendar) val.clone();
|
||||
modify(rounded, field, true);
|
||||
return rounded;
|
||||
}
|
||||
|
||||
/**
|
||||
* See the other round method. Works with an Object, trying to
|
||||
* use it as either a Date or Calendar.
|
||||
*/
|
||||
public static Date round(Object val, int field) {
|
||||
if (val instanceof Date) {
|
||||
return round((Date) val, field);
|
||||
} else if (val instanceof Calendar) {
|
||||
return round((Calendar) val, field).getTime();
|
||||
} else {
|
||||
throw new ClassCastException("Could not round " + val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See the other trunc method. Works with a Date.
|
||||
*/
|
||||
public static Date trunc(Date val, int field) {
|
||||
GregorianCalendar gval = new GregorianCalendar();
|
||||
gval.setTime(val);
|
||||
modify(gval, field, false);
|
||||
return gval.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate this date, leaving the field specified as the most significant
|
||||
* field. For example, if you had the datetime of 28 Mar 2002
|
||||
* 13:45:01.231, if you passed with HOUR, it would return 28 Mar
|
||||
* 2002 13:00:00.000. If this was passed with MONTH, it would return
|
||||
* 1 Mar 2002 0:00:00.000.
|
||||
*/
|
||||
public static Calendar trunc(Calendar val, int field) {
|
||||
Calendar truncated = (Calendar) val.clone();
|
||||
modify(truncated, field, false);
|
||||
return truncated;
|
||||
}
|
||||
|
||||
/**
|
||||
* See the other trunc method. Works with an Object, trying to
|
||||
* use it as either a Date or Calendar.
|
||||
*/
|
||||
public static Date trunc(Object val, int field) {
|
||||
if (val instanceof Date) {
|
||||
return trunc((Date) val, field);
|
||||
} else if (val instanceof Calendar) {
|
||||
return trunc((Calendar) val, field).getTime();
|
||||
} else {
|
||||
throw new ClassCastException("Could not trunc " + val);
|
||||
}
|
||||
}
|
||||
|
||||
private static void modify(Calendar val, int field, boolean round) {
|
||||
boolean roundUp = false;
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
for (int j = 0; j < fields[i].length; j++) {
|
||||
if (fields[i][j] == field) {
|
||||
//This is our field... we stop looping
|
||||
if (round && roundUp) {
|
||||
if (field == CalendarUtils.SEMI_MONTH) {
|
||||
//This is a special case that's hard to generalize
|
||||
//If the date is 1, we round up to 16, otherwise
|
||||
// we subtract 15 days and add 1 month
|
||||
if (val.get(Calendar.DATE) == 1) {
|
||||
val.add(Calendar.DATE, 15);
|
||||
} else {
|
||||
val.add(Calendar.DATE, -15);
|
||||
val.add(Calendar.MONTH, 1);
|
||||
}
|
||||
} else {
|
||||
//We need at add one to this field since the
|
||||
// last number causes us to round up
|
||||
val.add(fields[i][0], 1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
//We have various fields that are not easy roundings
|
||||
int offset = 0;
|
||||
boolean offsetSet = false;
|
||||
//These are special types of fields that require different rounding rules
|
||||
switch (field) {
|
||||
case CalendarUtils.SEMI_MONTH:
|
||||
if (fields[i][0] == Calendar.DATE) {
|
||||
//If we're going to drop the DATE field's value,
|
||||
// we want to do this our own way.
|
||||
//We need to subtrace 1 since the date has a minimum of 1
|
||||
offset = val.get(Calendar.DATE) - 1;
|
||||
//If we're above 15 days adjustment, that means we're in the
|
||||
// bottom half of the month and should stay accordingly.
|
||||
if (offset >= 15) {
|
||||
offset -= 15;
|
||||
}
|
||||
//Record whether we're in the top or bottom half of that range
|
||||
roundUp = offset > 7;
|
||||
offsetSet = true;
|
||||
}
|
||||
break;
|
||||
case Calendar.AM_PM:
|
||||
if (fields[i][0] == Calendar.HOUR) {
|
||||
//If we're going to drop the HOUR field's value,
|
||||
// we want to do this our own way.
|
||||
offset = val.get(Calendar.HOUR);
|
||||
if (offset >= 12) {
|
||||
offset -= 12;
|
||||
}
|
||||
roundUp = offset > 6;
|
||||
offsetSet = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!offsetSet) {
|
||||
int min = val.getActualMinimum(fields[i][0]);
|
||||
int max = val.getActualMaximum(fields[i][0]);
|
||||
//Calculate the offset from the minimum allowed value
|
||||
offset = val.get(fields[i][0]) - min;
|
||||
//Set roundUp if this is more than half way between the minimum and maximum
|
||||
roundUp = offset > ((max - min) / 2);
|
||||
}
|
||||
//We need to remove this field
|
||||
val.add(fields[i][0], -offset);
|
||||
}
|
||||
throw new RuntimeException("We do not support that field.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses strings the way that CVS supports it (very human readable).
|
||||
*/
|
||||
public static Calendar parse(String original) {
|
||||
return parse(original, Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses strings the way that CVS supports it (very human readable).
|
||||
*/
|
||||
public static Calendar parse(String original, Locale locale) {
|
||||
//Get the symbol names
|
||||
DateFormatSymbols symbols = new DateFormatSymbols(locale);
|
||||
|
||||
//Prep the string to parse
|
||||
String value = original.toLowerCase().trim();
|
||||
|
||||
//Get the current date/time
|
||||
Calendar now = Calendar.getInstance();
|
||||
if (value.endsWith(" ago")) {
|
||||
//If this was a date that was "ago" the current time...
|
||||
//Strip out the ' ago' part
|
||||
value = value.substring(0, value.length() - 4);
|
||||
|
||||
//Split the value and unit
|
||||
int start = value.indexOf(" ");
|
||||
if (start < 0) {
|
||||
throw new RuntimeException("Could not find space in between value and unit");
|
||||
}
|
||||
String unit = value.substring(start + 1);
|
||||
value = value.substring(0, start);
|
||||
//We support "a week", so we need to parse the value as "a"
|
||||
int val = 0;
|
||||
if (value.equals("a") || value.equals("an")) {
|
||||
val = 1;
|
||||
} else {
|
||||
val = Integer.parseInt(value);
|
||||
}
|
||||
|
||||
//Determine the unit
|
||||
if (unit.equals("milliseconds") || unit.equals("millisecond")) {
|
||||
now.add(Calendar.MILLISECOND, -val);
|
||||
} else if (unit.equals("seconds") || unit.equals("second")) {
|
||||
now.add(Calendar.SECOND, -val);
|
||||
} else if (unit.equals("minutes") || unit.equals("minute")) {
|
||||
now.add(Calendar.MINUTE, -val);
|
||||
} else if (unit.equals("hours") || unit.equals("hour")) {
|
||||
now.add(Calendar.HOUR, -val);
|
||||
} else if (unit.equals("days") || unit.equals("day")) {
|
||||
now.add(Calendar.DATE, -val);
|
||||
} else if (unit.equals("weeks") || unit.equals("week")) {
|
||||
now.add(Calendar.DATE, -val * 7);
|
||||
} else if (unit.equals("fortnights") || unit.equals("fortnight")) {
|
||||
now.add(Calendar.DATE, -val * 14);
|
||||
} else if (unit.equals("months") || unit.equals("month")) {
|
||||
now.add(Calendar.MONTH, -val);
|
||||
} else if (unit.equals("years") || unit.equals("year")) {
|
||||
now.add(Calendar.YEAR, -val);
|
||||
} else {
|
||||
throw new RuntimeException("We do not understand that many units ago");
|
||||
}
|
||||
return now;
|
||||
} else if (value.startsWith("last ")) {
|
||||
//If this was the last time a certain field was met
|
||||
//Strip out the 'last ' part
|
||||
value = value.substring(5);
|
||||
//Get the current date/time
|
||||
String[] strings = symbols.getWeekdays();
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
if (value.equalsIgnoreCase(strings[i])) {
|
||||
//How many days after Sunday
|
||||
int daysAgo = now.get(Calendar.DAY_OF_WEEK) - i;
|
||||
if (daysAgo <= 0) {
|
||||
daysAgo += 7;
|
||||
}
|
||||
now.add(Calendar.DATE, -daysAgo);
|
||||
return now;
|
||||
}
|
||||
}
|
||||
strings = symbols.getMonths();
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
if (value.equalsIgnoreCase(strings[i])) {
|
||||
//How many days after January
|
||||
int monthsAgo = now.get(Calendar.MONTH) - i;
|
||||
if (monthsAgo <= 0) {
|
||||
monthsAgo += 12;
|
||||
}
|
||||
now.add(Calendar.MONTH, -monthsAgo);
|
||||
return now;
|
||||
}
|
||||
}
|
||||
if (value.equals("week")) {
|
||||
now.add(Calendar.DATE, -7);
|
||||
return now;
|
||||
}
|
||||
} else if (value.equals("yesterday")) {
|
||||
now.add(Calendar.DATE, -1);
|
||||
return now;
|
||||
} else if (value.equals("tomorrow")) {
|
||||
now.add(Calendar.DATE, 1);
|
||||
return now;
|
||||
}
|
||||
//Try to parse the date a number of different ways
|
||||
for (int i = 0; i < dateFormats.length; i++) {
|
||||
try {
|
||||
Date datetime = dateFormats[i].parse(original);
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(datetime);
|
||||
return cal;
|
||||
} catch (ParseException pe) {
|
||||
//we ignore this and just keep trying
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unable to parse '" + original + "'.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructs an Iterator that will start and stop over a date
|
||||
* range based on the focused date and the range style. For instance,
|
||||
* passing Thursday, July 4, 2002 and a RANGE_MONTH_SUNDAY will return
|
||||
* an Iterator that starts with Sunday, June 30, 2002 and ends with
|
||||
* Saturday, August 3, 2002.
|
||||
*/
|
||||
public static Iterator getCalendarIterator(Calendar focus, int rangeStyle) {
|
||||
Calendar start = null;
|
||||
Calendar end = null;
|
||||
int startCutoff = Calendar.SUNDAY;
|
||||
int endCutoff = Calendar.SATURDAY;
|
||||
switch (rangeStyle) {
|
||||
case RANGE_MONTH_SUNDAY:
|
||||
case RANGE_MONTH_MONDAY:
|
||||
//Set start to the first of the month
|
||||
start = trunc(focus, Calendar.MONTH);
|
||||
//Set end to the last of the month
|
||||
end = (Calendar) start.clone();
|
||||
end.add(Calendar.MONTH, 1);
|
||||
end.add(Calendar.DATE, -1);
|
||||
//Loop start back to the previous sunday or monday
|
||||
if (rangeStyle == RANGE_MONTH_MONDAY) {
|
||||
startCutoff = Calendar.MONDAY;
|
||||
endCutoff = Calendar.SUNDAY;
|
||||
}
|
||||
break;
|
||||
case RANGE_WEEK_SUNDAY:
|
||||
case RANGE_WEEK_MONDAY:
|
||||
case RANGE_WEEK_RELATIVE:
|
||||
case RANGE_WEEK_CENTER:
|
||||
//Set start and end to the current date
|
||||
start = trunc(focus, Calendar.DATE);
|
||||
end = trunc(focus, Calendar.DATE);
|
||||
switch (rangeStyle) {
|
||||
case RANGE_WEEK_SUNDAY:
|
||||
//already set by default
|
||||
break;
|
||||
case RANGE_WEEK_MONDAY:
|
||||
startCutoff = Calendar.MONDAY;
|
||||
endCutoff = Calendar.SUNDAY;
|
||||
break;
|
||||
case RANGE_WEEK_RELATIVE:
|
||||
startCutoff = focus.get(Calendar.DAY_OF_WEEK);
|
||||
endCutoff = startCutoff - 1;
|
||||
break;
|
||||
case RANGE_WEEK_CENTER:
|
||||
startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3;
|
||||
endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("The range style " + rangeStyle + " is not valid.");
|
||||
}
|
||||
if (startCutoff < Calendar.SUNDAY) {
|
||||
startCutoff += 7;
|
||||
}
|
||||
if (endCutoff > Calendar.SATURDAY) {
|
||||
endCutoff -= 7;
|
||||
}
|
||||
while (start.get(Calendar.DAY_OF_WEEK) != startCutoff) {
|
||||
start.add(Calendar.DATE, -1);
|
||||
}
|
||||
while (end.get(Calendar.DAY_OF_WEEK) != endCutoff) {
|
||||
end.add(Calendar.DATE, 1);
|
||||
}
|
||||
final Calendar startFinal = start;
|
||||
final Calendar endFinal = end;
|
||||
Iterator it = new Iterator() {
|
||||
Calendar spot = null;
|
||||
{
|
||||
spot = startFinal;
|
||||
spot.add(Calendar.DATE, -1);
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return spot.before(endFinal);
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
if (spot.equals(endFinal)) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
spot.add(Calendar.DATE, 1);
|
||||
return spot.clone();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* See the other getCalendarIterator. Works with a Date.
|
||||
*/
|
||||
public static Iterator getCalendarIterator(Date focus, int rangeStyle) {
|
||||
GregorianCalendar gval = new GregorianCalendar();
|
||||
gval.setTime(focus);
|
||||
return getCalendarIterator(gval, rangeStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the other getCalendarIterator. Works with an Object, trying
|
||||
* to use it as a Date or Calendar.
|
||||
*/
|
||||
public static Iterator getCalendarIterator(Object focus, int rangeStyle) {
|
||||
if (focus instanceof Date) {
|
||||
return getCalendarIterator((Date) focus, rangeStyle);
|
||||
} else if (focus instanceof Calendar) {
|
||||
return getCalendarIterator((Calendar) focus, rangeStyle);
|
||||
} else {
|
||||
throw new ClassCastException("Could not iterate based on " + focus);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,297 @@
|
|||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution, if
|
||||
* any, must include the following acknowlegement:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowlegement may appear in the software itself,
|
||||
* if and wherever such third-party acknowlegements normally appear.
|
||||
*
|
||||
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
|
||||
* Foundation" must not be used to endorse or promote products derived
|
||||
* from this software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache"
|
||||
* nor may "Apache" appear in their names without prior written
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
package org.apache.commons.lang.time;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Date and time formatting utilites and constants.
|
||||
* <p>
|
||||
* Formatting is performed using the
|
||||
* {@link org.apache.commons.lang.time.FastDateFormat} class.
|
||||
*
|
||||
* @author Apache Ant - DateUtils
|
||||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
|
||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
|
||||
* @author Stephen Colebourne
|
||||
* @since 2.0
|
||||
* @version $Id: DateFormatUtils.java,v 1.1 2003/06/08 23:14:23 scolebourne Exp $
|
||||
*/
|
||||
public final class DateFormatUtils {
|
||||
|
||||
/**
|
||||
* ISO8601 formatter for date-time witout timezone.
|
||||
* The format used is <tt>yyyy-MM-dd'T'HH:mm:ss</tt>.
|
||||
*/
|
||||
public static final FastDateFormat ISO_DATETIME_FORMAT
|
||||
= FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
|
||||
|
||||
/**
|
||||
* ISO8601 formatter for date-time with timezone.
|
||||
* The format used is <tt>yyyy-MM-dd'T'HH:mm:ssZZ</tt>.
|
||||
*/
|
||||
public static final FastDateFormat ISO_DATETIME_TIMEZONE_FORMAT
|
||||
= FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ");
|
||||
|
||||
/**
|
||||
* ISO8601 formatter for date without timezone.
|
||||
* The format used is <tt>yyyy-MM-dd</tt>.
|
||||
*/
|
||||
public static final FastDateFormat ISO_DATE_FORMAT
|
||||
= FastDateFormat.getInstance("yyyy-MM-dd");
|
||||
|
||||
/**
|
||||
* ISO8601-like formatter for date with timezone.
|
||||
* The format used is <tt>yyyy-MM-ddZZ</tt>.
|
||||
* This pattern does not comply with the formal ISO8601 specification
|
||||
* as the standard does not allow a timezone without a time.
|
||||
*/
|
||||
public static final FastDateFormat ISO_DATE_TIMEZONE_FORMAT
|
||||
= FastDateFormat.getInstance("yyyy-MM-ddZZ");
|
||||
|
||||
/**
|
||||
* ISO8601 formatter for time without timezone.
|
||||
* The format used is <tt>'T'HH:mm:ss</tt>.
|
||||
*/
|
||||
public static final FastDateFormat ISO_TIME_FORMAT
|
||||
= FastDateFormat.getInstance("'T'HH:mm:ss");
|
||||
|
||||
/**
|
||||
* ISO8601 formatter for time with timezone.
|
||||
* The format used is <tt>'T'HH:mm:ssZZ</tt>.
|
||||
*/
|
||||
public static final FastDateFormat ISO_TIME_TIMEZONE_FORMAT
|
||||
= FastDateFormat.getInstance("'T'HH:mm:ssZZ");
|
||||
|
||||
/**
|
||||
* ISO8601-like formatter for time without timezone.
|
||||
* The format used is <tt>HH:mm:ss</tt>.
|
||||
* This pattern does not comply with the formal ISO8601 specification
|
||||
* as the standard requires the 'T' prefix for times.
|
||||
*/
|
||||
public static final FastDateFormat ISO_TIME_NO_T_FORMAT
|
||||
= FastDateFormat.getInstance("HH:mm:ss");
|
||||
|
||||
/**
|
||||
* ISO8601-like formatter for time with timezone.
|
||||
* The format used is <tt>HH:mm:ssZZ</tt>.
|
||||
* This pattern does not comply with the formal ISO8601 specification
|
||||
* as the standard requires the 'T' prefix for times.
|
||||
*/
|
||||
public static final FastDateFormat ISO_TIME_NO_T_TIMEZONE_FORMAT
|
||||
= FastDateFormat.getInstance("HH:mm:ssZZ");
|
||||
|
||||
/**
|
||||
* SMTP (and probably other) date headers.
|
||||
* The format used is <tt>EEE, dd MMM yyyy HH:mm:ss Z</tt> in US locale.
|
||||
*/
|
||||
public static final FastDateFormat SMTP_DATETIME_FORMAT
|
||||
= FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* DateFormatUtils instances should NOT be constructed in standard programming.
|
||||
* <p>
|
||||
* This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.
|
||||
*/
|
||||
public DateFormatUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern using the UTC timezone.
|
||||
*
|
||||
* @param millis the date to format expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String formatUTC(long millis, String pattern) {
|
||||
return format(new Date(millis), pattern, DateUtils.UTC_TIMEZONE, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern using the UTC timezone.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String formatUTC(Date date, String pattern) {
|
||||
return format(date, pattern, DateUtils.UTC_TIMEZONE, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern using the UTC timezone.
|
||||
*
|
||||
* @param millis the date to format expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @param locale the locale to use, may be null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String formatUTC(long millis, String pattern, Locale locale) {
|
||||
return format(new Date(millis), pattern, DateUtils.UTC_TIMEZONE, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern using the UTC timezone.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @param locale the locale to use, may be null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String formatUTC(Date date, String pattern, Locale locale) {
|
||||
return format(date, pattern, DateUtils.UTC_TIMEZONE, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern.
|
||||
*
|
||||
* @param millis the date to format expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(long millis, String pattern) {
|
||||
return format(new Date(millis), pattern, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(Date date, String pattern) {
|
||||
return format(date, pattern, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern in a timezone.
|
||||
*
|
||||
* @param millis the time expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @param timeZone the timezone to use, may be null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(long millis, String pattern, TimeZone timeZone) {
|
||||
return format(new Date(millis), pattern, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern in a timezone.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @param timeZone the timezone to use, may be null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(Date date, String pattern, TimeZone timeZone) {
|
||||
return format(date, pattern, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern in a locale.
|
||||
*
|
||||
* @param millis the date to format expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @param locale the locale to use, may be null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(long millis, String pattern, Locale locale) {
|
||||
return format(new Date(millis), pattern, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern in a locale.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @param locale the locale to use, may be null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(Date date, String pattern, Locale locale) {
|
||||
return format(date, pattern, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern in a timezone and locale.
|
||||
*
|
||||
* @param millis the date to format expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @param timeZone the timezone to use, may be null
|
||||
* @param locale the locale to use, may be null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(long millis, String pattern, TimeZone timeZone, Locale locale) {
|
||||
return format(new Date(millis), pattern, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern in a timezone and locale.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param pattern the pattern to use to format the date
|
||||
* @param timeZone the timezone to use, may be null
|
||||
* @param locale the locale to use, may be null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(Date date, String pattern, TimeZone timeZone, Locale locale) {
|
||||
FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
|
||||
return df.format(date);
|
||||
}
|
||||
|
||||
}
|
|
@ -53,209 +53,491 @@
|
|||
*/
|
||||
package org.apache.commons.lang.time;
|
||||
|
||||
import java.text.ChoiceFormat;
|
||||
import java.text.DateFormat;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Helper methods to deal with date/time formatting. [Relies heavily on
|
||||
* code taken from the DateUtils class of the jakarata-ant project.]
|
||||
* A suite of utilities surrounding the use of the Calendar and Date object.
|
||||
*
|
||||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
|
||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
|
||||
* @since 2.1
|
||||
* @version $Id: DateUtils.java,v 1.2 2003/02/04 22:19:33 scolebourne Exp $
|
||||
* @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
|
||||
* @author Stephen Colebourne
|
||||
* @since 2.0
|
||||
* @version $Id: DateUtils.java,v 1.3 2003/06/08 23:14:23 scolebourne Exp $
|
||||
*/
|
||||
public final class DateUtils {
|
||||
public class DateUtils {
|
||||
|
||||
/**
|
||||
* ISO8601-like pattern for date-time. It does not support timezone.
|
||||
* <tt>yyyy-MM-ddTHH:mm:ss</tt>
|
||||
* The UTC timezone (often referred to as GMT).
|
||||
*/
|
||||
public static final String ISO8601_DATETIME_PATTERN
|
||||
= "yyyy-MM-dd'T'HH:mm:ss";
|
||||
public static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("GMT");
|
||||
/**
|
||||
* Number of milliseconds in a standard second.
|
||||
*/
|
||||
public static final int MILLIS_IN_SECOND = 1000;
|
||||
/**
|
||||
* Number of milliseconds in a standard minute.
|
||||
*/
|
||||
public static final int MILLIS_IN_MINUTE = 60 * 1000;
|
||||
/**
|
||||
* Number of milliseconds in a standard hour.
|
||||
*/
|
||||
public static final int MILLIS_IN_HOUR = 60 * 60 * 1000;
|
||||
/**
|
||||
* Number of milliseconds in a standard day.
|
||||
*/
|
||||
public static final int MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||
|
||||
/**
|
||||
* ISO8601-like pattern for date. <tt>yyyy-MM-dd</tt>
|
||||
* This is half a month, so this represents whether a date is in the top
|
||||
* or bottom half of the month.
|
||||
*/
|
||||
public static final String ISO8601_DATE_PATTERN
|
||||
= "yyyy-MM-dd";
|
||||
public final static int SEMI_MONTH = 1001;
|
||||
|
||||
private static final int[][] fields = {
|
||||
{Calendar.MILLISECOND},
|
||||
{Calendar.SECOND},
|
||||
{Calendar.MINUTE},
|
||||
{Calendar.HOUR_OF_DAY, Calendar.HOUR},
|
||||
{Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */},
|
||||
{Calendar.MONTH, DateUtils.SEMI_MONTH},
|
||||
{Calendar.YEAR},
|
||||
{Calendar.ERA}};
|
||||
|
||||
private static DateFormat[] dateFormats = {
|
||||
//3/31/92 10:00:07 PST
|
||||
new SimpleDateFormat("M/dd/yy h:mm:ss z"),
|
||||
//January 23, 1987 10:05pm
|
||||
new SimpleDateFormat("MMM d, yyyy h:mm a"),
|
||||
//22:00 GMT
|
||||
new SimpleDateFormat("h:mm z")};
|
||||
|
||||
/**
|
||||
* ISO8601-like pattern for time. <tt>HH:mm:ss</tt>
|
||||
* A week range, starting on Sunday.
|
||||
*/
|
||||
public static final String ISO8601_TIME_PATTERN
|
||||
= "HH:mm:ss";
|
||||
public final static int RANGE_WEEK_SUNDAY = 1;
|
||||
|
||||
/**
|
||||
* Format used for SMTP (and probably other) Date headers.
|
||||
* A week range, starting on Monday.
|
||||
*/
|
||||
public static final DateFormat DATE_HEADER_FORMAT
|
||||
= new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ", Locale.US);
|
||||
public final static int RANGE_WEEK_MONDAY = 2;
|
||||
|
||||
/**
|
||||
* A week range, starting on the day focused.
|
||||
*/
|
||||
public final static int RANGE_WEEK_RELATIVE = 3;
|
||||
|
||||
// code from Magesh moved from DefaultLogger and slightly modified
|
||||
private static final MessageFormat MINUTE_SECONDS
|
||||
= new MessageFormat("{0}{1}");
|
||||
/**
|
||||
* A week range, centered around the day focused.
|
||||
*/
|
||||
public final static int RANGE_WEEK_CENTER = 4;
|
||||
|
||||
private static final double[] LIMITS = {0, 1, 2};
|
||||
/**
|
||||
* A month range, the week starting on Sunday.
|
||||
*/
|
||||
public final static int RANGE_MONTH_SUNDAY = 5;
|
||||
|
||||
private static final String[] MINUTES_PART =
|
||||
{"", "1 minute ", "{0,number} minutes "};
|
||||
/**
|
||||
* A month range, the week starting on Monday.
|
||||
*/
|
||||
public final static int RANGE_MONTH_MONDAY = 6;
|
||||
|
||||
private static final String[] SECONDS_PART =
|
||||
{"0 seconds", "1 second", "{1,number} seconds"};
|
||||
|
||||
private static final ChoiceFormat MINUTES_FORMAT =
|
||||
new ChoiceFormat(LIMITS, MINUTES_PART);
|
||||
|
||||
private static final ChoiceFormat SECONDS_FORMAT =
|
||||
new ChoiceFormat(LIMITS, SECONDS_PART);
|
||||
|
||||
static {
|
||||
MINUTE_SECONDS.setFormat(0, MINUTES_FORMAT);
|
||||
MINUTE_SECONDS.setFormat(1, SECONDS_FORMAT);
|
||||
/**
|
||||
* See the other round method. Works with a Date object.
|
||||
*/
|
||||
public static Date round(Date val, int field) {
|
||||
GregorianCalendar gval = new GregorianCalendar();
|
||||
gval.setTime(val);
|
||||
modify(gval, field, true);
|
||||
return gval.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>DateUtils instances should NOT be constructed in standard programming.</p>
|
||||
*
|
||||
* <p>This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.</p>
|
||||
* Round this date, leaving the field specified as the most significant
|
||||
* field. For example, if you had the datetime of 28 Mar 2002
|
||||
* 13:45:01.231, if this was passed with HOUR, it would return 28 Mar
|
||||
* 2002 14:00:00.000. If this was passed with MONTH, it would return
|
||||
* 1 April 2002 0:00:00.000.
|
||||
*/
|
||||
public DateUtils() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern.
|
||||
* @param date the date to format expressed in milliseconds.
|
||||
* @param pattern the pattern to use to format the date.
|
||||
* @return the formatted date.
|
||||
*/
|
||||
public static String format(long date, String pattern) {
|
||||
return format(new Date(date), pattern);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format a date/time into a specific pattern.
|
||||
* @param date the date to format expressed in milliseconds.
|
||||
* @param pattern the pattern to use to format the date.
|
||||
* @return the formatted date.
|
||||
*/
|
||||
public static String format(Date date, String pattern) {
|
||||
DateFormat df = createDateFormat(pattern);
|
||||
return df.format(date);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format an elapsed time into a plurialization correct string.
|
||||
* It is limited only to report elapsed time in minutes and
|
||||
* seconds and has the following behavior.
|
||||
* <ul>
|
||||
* <li>minutes are not displayed when 0. (ie: "45 seconds")</li>
|
||||
* <li>seconds are always displayed in plural form (ie "0 seconds" or
|
||||
* "10 seconds") except for 1 (ie "1 second")</li>
|
||||
* </ul>
|
||||
* @param time the elapsed time to report in milliseconds.
|
||||
* @return the formatted text in minutes/seconds.
|
||||
*/
|
||||
public static String formatElapsedTime(long millis) {
|
||||
long seconds = millis / 1000;
|
||||
long minutes = seconds / 60;
|
||||
Object[] args = {new Long(minutes), new Long(seconds % 60)};
|
||||
return MINUTE_SECONDS.format(args);
|
||||
public static Calendar round(Calendar val, int field) {
|
||||
Calendar rounded = (Calendar) val.clone();
|
||||
modify(rounded, field, true);
|
||||
return rounded;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a lenient date format set to GMT time zone.
|
||||
* @param pattern the pattern used for date/time formatting.
|
||||
* @return the configured format for this pattern.
|
||||
* See the other round method. Works with an Object, trying to
|
||||
* use it as either a Date or Calendar.
|
||||
*/
|
||||
private static DateFormat createDateFormat(String pattern) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
|
||||
TimeZone gmt = TimeZone.getTimeZone("GMT");
|
||||
sdf.setTimeZone(gmt);
|
||||
sdf.setLenient(true);
|
||||
return sdf;
|
||||
public static Date round(Object val, int field) {
|
||||
if (val instanceof Date) {
|
||||
return round((Date) val, field);
|
||||
} else if (val instanceof Calendar) {
|
||||
return round((Calendar) val, field).getTime();
|
||||
} else {
|
||||
throw new ClassCastException("Could not round " + val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the phase of the moon for a given date.
|
||||
*
|
||||
* <p>Code heavily influenced by hacklib.c in <a
|
||||
* href="http://www.nethack.org/">Nethack</a></p>
|
||||
*
|
||||
* <p>The Algorithm:
|
||||
*
|
||||
* <pre>
|
||||
* moon period = 29.53058 days ~= 30, year = 365.2422 days
|
||||
*
|
||||
* days moon phase advances on first day of year compared to preceding year
|
||||
* = 365.2422 - 12*29.53058 ~= 11
|
||||
*
|
||||
* years in Metonic cycle (time until same phases fall on the same days of
|
||||
* the month) = 18.6 ~= 19
|
||||
*
|
||||
* moon phase on first day of year (epact) ~= (11*(year%19) + 18) % 30
|
||||
* (18 as initial condition for 1900)
|
||||
*
|
||||
* current phase in days = first day phase + days elapsed in year
|
||||
*
|
||||
* 6 moons ~= 177 days
|
||||
* 177 ~= 8 reported phases * 22
|
||||
* + 11/22 for rounding
|
||||
* </pre>
|
||||
*
|
||||
* @return The phase of the moon as a number between 0 and 7 with
|
||||
* 0 meaning new moon and 4 meaning full moon.
|
||||
*
|
||||
* @since 1.2, Ant 1.5
|
||||
* See the other trunc method. Works with a Date.
|
||||
*/
|
||||
public static int getPhaseOfMoon(Calendar cal) {
|
||||
int dayOfTheYear = cal.get(Calendar.DAY_OF_YEAR);
|
||||
int yearInMetonicCycle = ((cal.get(Calendar.YEAR) - 1900) % 19) + 1;
|
||||
int epact = (11 * yearInMetonicCycle + 18) % 30;
|
||||
if ((epact == 25 && yearInMetonicCycle > 11) || epact == 24) {
|
||||
epact++;
|
||||
}
|
||||
return (((((dayOfTheYear + epact) * 6) + 11) % 177) / 22) & 7;
|
||||
public static Date trunc(Date val, int field) {
|
||||
GregorianCalendar gval = new GregorianCalendar();
|
||||
gval.setTime(val);
|
||||
modify(gval, field, false);
|
||||
return gval.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current Date in a format suitable for a SMTP date
|
||||
* header.
|
||||
*
|
||||
* @since Ant 1.5.2
|
||||
* Truncate this date, leaving the field specified as the most significant
|
||||
* field. For example, if you had the datetime of 28 Mar 2002
|
||||
* 13:45:01.231, if you passed with HOUR, it would return 28 Mar
|
||||
* 2002 13:00:00.000. If this was passed with MONTH, it would return
|
||||
* 1 Mar 2002 0:00:00.000.
|
||||
*/
|
||||
public static String getDateForHeader() {
|
||||
public static Calendar trunc(Calendar val, int field) {
|
||||
Calendar truncated = (Calendar) val.clone();
|
||||
modify(truncated, field, false);
|
||||
return truncated;
|
||||
}
|
||||
|
||||
/**
|
||||
* See the other trunc method. Works with an Object, trying to
|
||||
* use it as either a Date or Calendar.
|
||||
*/
|
||||
public static Date trunc(Object val, int field) {
|
||||
if (val instanceof Date) {
|
||||
return trunc((Date) val, field);
|
||||
} else if (val instanceof Calendar) {
|
||||
return trunc((Calendar) val, field).getTime();
|
||||
} else {
|
||||
throw new ClassCastException("Could not trunc " + val);
|
||||
}
|
||||
}
|
||||
|
||||
private static void modify(Calendar val, int field, boolean round) {
|
||||
boolean roundUp = false;
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
for (int j = 0; j < fields[i].length; j++) {
|
||||
if (fields[i][j] == field) {
|
||||
//This is our field... we stop looping
|
||||
if (round && roundUp) {
|
||||
if (field == DateUtils.SEMI_MONTH) {
|
||||
//This is a special case that's hard to generalize
|
||||
//If the date is 1, we round up to 16, otherwise
|
||||
// we subtract 15 days and add 1 month
|
||||
if (val.get(Calendar.DATE) == 1) {
|
||||
val.add(Calendar.DATE, 15);
|
||||
} else {
|
||||
val.add(Calendar.DATE, -15);
|
||||
val.add(Calendar.MONTH, 1);
|
||||
}
|
||||
} else {
|
||||
//We need at add one to this field since the
|
||||
// last number causes us to round up
|
||||
val.add(fields[i][0], 1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
//We have various fields that are not easy roundings
|
||||
int offset = 0;
|
||||
boolean offsetSet = false;
|
||||
//These are special types of fields that require different rounding rules
|
||||
switch (field) {
|
||||
case DateUtils.SEMI_MONTH:
|
||||
if (fields[i][0] == Calendar.DATE) {
|
||||
//If we're going to drop the DATE field's value,
|
||||
// we want to do this our own way.
|
||||
//We need to subtrace 1 since the date has a minimum of 1
|
||||
offset = val.get(Calendar.DATE) - 1;
|
||||
//If we're above 15 days adjustment, that means we're in the
|
||||
// bottom half of the month and should stay accordingly.
|
||||
if (offset >= 15) {
|
||||
offset -= 15;
|
||||
}
|
||||
//Record whether we're in the top or bottom half of that range
|
||||
roundUp = offset > 7;
|
||||
offsetSet = true;
|
||||
}
|
||||
break;
|
||||
case Calendar.AM_PM:
|
||||
if (fields[i][0] == Calendar.HOUR) {
|
||||
//If we're going to drop the HOUR field's value,
|
||||
// we want to do this our own way.
|
||||
offset = val.get(Calendar.HOUR);
|
||||
if (offset >= 12) {
|
||||
offset -= 12;
|
||||
}
|
||||
roundUp = offset > 6;
|
||||
offsetSet = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!offsetSet) {
|
||||
int min = val.getActualMinimum(fields[i][0]);
|
||||
int max = val.getActualMaximum(fields[i][0]);
|
||||
//Calculate the offset from the minimum allowed value
|
||||
offset = val.get(fields[i][0]) - min;
|
||||
//Set roundUp if this is more than half way between the minimum and maximum
|
||||
roundUp = offset > ((max - min) / 2);
|
||||
}
|
||||
//We need to remove this field
|
||||
val.add(fields[i][0], -offset);
|
||||
}
|
||||
throw new RuntimeException("We do not support that field.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses strings the way that CVS supports it (very human readable).
|
||||
*/
|
||||
public static Calendar parse(String original) {
|
||||
return parse(original, Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses strings the way that CVS supports it (very human readable).
|
||||
*/
|
||||
public static Calendar parse(String original, Locale locale) {
|
||||
//Get the symbol names
|
||||
DateFormatSymbols symbols = new DateFormatSymbols(locale);
|
||||
|
||||
//Prep the string to parse
|
||||
String value = original.toLowerCase().trim();
|
||||
|
||||
//Get the current date/time
|
||||
Calendar now = Calendar.getInstance();
|
||||
if (value.endsWith(" ago")) {
|
||||
//If this was a date that was "ago" the current time...
|
||||
//Strip out the ' ago' part
|
||||
value = value.substring(0, value.length() - 4);
|
||||
|
||||
//Split the value and unit
|
||||
int start = value.indexOf(" ");
|
||||
if (start < 0) {
|
||||
throw new RuntimeException("Could not find space in between value and unit");
|
||||
}
|
||||
String unit = value.substring(start + 1);
|
||||
value = value.substring(0, start);
|
||||
//We support "a week", so we need to parse the value as "a"
|
||||
int val = 0;
|
||||
if (value.equals("a") || value.equals("an")) {
|
||||
val = 1;
|
||||
} else {
|
||||
val = Integer.parseInt(value);
|
||||
}
|
||||
|
||||
//Determine the unit
|
||||
if (unit.equals("milliseconds") || unit.equals("millisecond")) {
|
||||
now.add(Calendar.MILLISECOND, -val);
|
||||
} else if (unit.equals("seconds") || unit.equals("second")) {
|
||||
now.add(Calendar.SECOND, -val);
|
||||
} else if (unit.equals("minutes") || unit.equals("minute")) {
|
||||
now.add(Calendar.MINUTE, -val);
|
||||
} else if (unit.equals("hours") || unit.equals("hour")) {
|
||||
now.add(Calendar.HOUR, -val);
|
||||
} else if (unit.equals("days") || unit.equals("day")) {
|
||||
now.add(Calendar.DATE, -val);
|
||||
} else if (unit.equals("weeks") || unit.equals("week")) {
|
||||
now.add(Calendar.DATE, -val * 7);
|
||||
} else if (unit.equals("fortnights") || unit.equals("fortnight")) {
|
||||
now.add(Calendar.DATE, -val * 14);
|
||||
} else if (unit.equals("months") || unit.equals("month")) {
|
||||
now.add(Calendar.MONTH, -val);
|
||||
} else if (unit.equals("years") || unit.equals("year")) {
|
||||
now.add(Calendar.YEAR, -val);
|
||||
} else {
|
||||
throw new RuntimeException("We do not understand that many units ago");
|
||||
}
|
||||
return now;
|
||||
} else if (value.startsWith("last ")) {
|
||||
//If this was the last time a certain field was met
|
||||
//Strip out the 'last ' part
|
||||
value = value.substring(5);
|
||||
//Get the current date/time
|
||||
String[] strings = symbols.getWeekdays();
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
if (value.equalsIgnoreCase(strings[i])) {
|
||||
//How many days after Sunday
|
||||
int daysAgo = now.get(Calendar.DAY_OF_WEEK) - i;
|
||||
if (daysAgo <= 0) {
|
||||
daysAgo += 7;
|
||||
}
|
||||
now.add(Calendar.DATE, -daysAgo);
|
||||
return now;
|
||||
}
|
||||
}
|
||||
strings = symbols.getMonths();
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
if (value.equalsIgnoreCase(strings[i])) {
|
||||
//How many days after January
|
||||
int monthsAgo = now.get(Calendar.MONTH) - i;
|
||||
if (monthsAgo <= 0) {
|
||||
monthsAgo += 12;
|
||||
}
|
||||
now.add(Calendar.MONTH, -monthsAgo);
|
||||
return now;
|
||||
}
|
||||
}
|
||||
if (value.equals("week")) {
|
||||
now.add(Calendar.DATE, -7);
|
||||
return now;
|
||||
}
|
||||
} else if (value.equals("yesterday")) {
|
||||
now.add(Calendar.DATE, -1);
|
||||
return now;
|
||||
} else if (value.equals("tomorrow")) {
|
||||
now.add(Calendar.DATE, 1);
|
||||
return now;
|
||||
}
|
||||
//Try to parse the date a number of different ways
|
||||
for (int i = 0; i < dateFormats.length; i++) {
|
||||
try {
|
||||
Date datetime = dateFormats[i].parse(original);
|
||||
Calendar cal = Calendar.getInstance();
|
||||
TimeZone tz = cal.getTimeZone();
|
||||
int offset = tz.getOffset(cal.get(Calendar.ERA),
|
||||
cal.get(Calendar.YEAR),
|
||||
cal.get(Calendar.MONTH),
|
||||
cal.get(Calendar.DAY_OF_MONTH),
|
||||
cal.get(Calendar.DAY_OF_WEEK),
|
||||
cal.get(Calendar.MILLISECOND));
|
||||
StringBuffer tzMarker = new StringBuffer(offset < 0 ? "-" : "+");
|
||||
offset = Math.abs(offset);
|
||||
int hours = offset / (60 * 60 * 1000);
|
||||
int minutes = offset / (60 * 1000) - 60 * hours;
|
||||
if (hours < 10) {
|
||||
tzMarker.append("0");
|
||||
}
|
||||
tzMarker.append(hours);
|
||||
if (minutes < 10) {
|
||||
tzMarker.append("0");
|
||||
}
|
||||
tzMarker.append(minutes);
|
||||
return DATE_HEADER_FORMAT.format(cal.getTime()) + tzMarker.toString();
|
||||
cal.setTime(datetime);
|
||||
return cal;
|
||||
} catch (ParseException pe) {
|
||||
//we ignore this and just keep trying
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unable to parse '" + original + "'.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructs an Iterator that will start and stop over a date
|
||||
* range based on the focused date and the range style. For instance,
|
||||
* passing Thursday, July 4, 2002 and a RANGE_MONTH_SUNDAY will return
|
||||
* an Iterator that starts with Sunday, June 30, 2002 and ends with
|
||||
* Saturday, August 3, 2002.
|
||||
*/
|
||||
public static Iterator getCalendarIterator(Calendar focus, int rangeStyle) {
|
||||
Calendar start = null;
|
||||
Calendar end = null;
|
||||
int startCutoff = Calendar.SUNDAY;
|
||||
int endCutoff = Calendar.SATURDAY;
|
||||
switch (rangeStyle) {
|
||||
case RANGE_MONTH_SUNDAY:
|
||||
case RANGE_MONTH_MONDAY:
|
||||
//Set start to the first of the month
|
||||
start = trunc(focus, Calendar.MONTH);
|
||||
//Set end to the last of the month
|
||||
end = (Calendar) start.clone();
|
||||
end.add(Calendar.MONTH, 1);
|
||||
end.add(Calendar.DATE, -1);
|
||||
//Loop start back to the previous sunday or monday
|
||||
if (rangeStyle == RANGE_MONTH_MONDAY) {
|
||||
startCutoff = Calendar.MONDAY;
|
||||
endCutoff = Calendar.SUNDAY;
|
||||
}
|
||||
break;
|
||||
case RANGE_WEEK_SUNDAY:
|
||||
case RANGE_WEEK_MONDAY:
|
||||
case RANGE_WEEK_RELATIVE:
|
||||
case RANGE_WEEK_CENTER:
|
||||
//Set start and end to the current date
|
||||
start = trunc(focus, Calendar.DATE);
|
||||
end = trunc(focus, Calendar.DATE);
|
||||
switch (rangeStyle) {
|
||||
case RANGE_WEEK_SUNDAY:
|
||||
//already set by default
|
||||
break;
|
||||
case RANGE_WEEK_MONDAY:
|
||||
startCutoff = Calendar.MONDAY;
|
||||
endCutoff = Calendar.SUNDAY;
|
||||
break;
|
||||
case RANGE_WEEK_RELATIVE:
|
||||
startCutoff = focus.get(Calendar.DAY_OF_WEEK);
|
||||
endCutoff = startCutoff - 1;
|
||||
break;
|
||||
case RANGE_WEEK_CENTER:
|
||||
startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3;
|
||||
endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("The range style " + rangeStyle + " is not valid.");
|
||||
}
|
||||
if (startCutoff < Calendar.SUNDAY) {
|
||||
startCutoff += 7;
|
||||
}
|
||||
if (startCutoff > Calendar.SATURDAY) {
|
||||
startCutoff -= 7;
|
||||
}
|
||||
if (endCutoff < Calendar.SUNDAY) {
|
||||
endCutoff += 7;
|
||||
}
|
||||
if (endCutoff > Calendar.SATURDAY) {
|
||||
endCutoff -= 7;
|
||||
}
|
||||
while (start.get(Calendar.DAY_OF_WEEK) != startCutoff) {
|
||||
start.add(Calendar.DATE, -1);
|
||||
}
|
||||
while (end.get(Calendar.DAY_OF_WEEK) != endCutoff) {
|
||||
end.add(Calendar.DATE, 1);
|
||||
}
|
||||
final Calendar startFinal = start;
|
||||
final Calendar endFinal = end;
|
||||
Iterator it = new Iterator() {
|
||||
Calendar spot = null;
|
||||
{
|
||||
spot = startFinal;
|
||||
spot.add(Calendar.DATE, -1);
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return spot.before(endFinal);
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
if (spot.equals(endFinal)) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
spot.add(Calendar.DATE, 1);
|
||||
return spot.clone();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
return it;
|
||||
}
|
||||
|
||||
/**
|
||||
* See the other getCalendarIterator. Works with a Date.
|
||||
*/
|
||||
public static Iterator getCalendarIterator(Date focus, int rangeStyle) {
|
||||
GregorianCalendar gval = new GregorianCalendar();
|
||||
gval.setTime(focus);
|
||||
return getCalendarIterator(gval, rangeStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the other getCalendarIterator. Works with an Object, trying
|
||||
* to use it as a Date or Calendar.
|
||||
*/
|
||||
public static Iterator getCalendarIterator(Object focus, int rangeStyle) {
|
||||
if (focus instanceof Date) {
|
||||
return getCalendarIterator((Date) focus, rangeStyle);
|
||||
} else if (focus instanceof Calendar) {
|
||||
return getCalendarIterator((Calendar) focus, rangeStyle);
|
||||
} else {
|
||||
throw new ClassCastException("Could not iterate based on " + focus);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution, if
|
||||
* any, must include the following acknowlegement:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowlegement may appear in the software itself,
|
||||
* if and wherever such third-party acknowlegements normally appear.
|
||||
*
|
||||
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
|
||||
* Foundation" must not be used to endorse or promote products derived
|
||||
* from this software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache"
|
||||
* nor may "Apache" appear in their names without prior written
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
package org.apache.commons.lang.time;
|
||||
|
||||
/**
|
||||
* Duration formatting utilites and constants.
|
||||
*
|
||||
* @author Apache Ant - DateUtils
|
||||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
|
||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
|
||||
* @author Stephen Colebourne
|
||||
* @since 2.0
|
||||
* @version $Id: DurationFormatUtils.java,v 1.1 2003/06/08 23:14:23 scolebourne Exp $
|
||||
*/
|
||||
public final class DurationFormatUtils {
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* DurationFormatUtils instances should NOT be constructed in standard programming.
|
||||
* <p>
|
||||
* This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.
|
||||
*/
|
||||
public DurationFormatUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an elapsed time into a plurialization correct string.
|
||||
* It is limited only to report elapsed time in minutes and
|
||||
* seconds and has the following behavior.
|
||||
* <ul>
|
||||
* <li>minutes are not displayed when 0. (ie: "45 seconds")</li>
|
||||
* <li>seconds are always displayed in plural form (ie "0 seconds" or
|
||||
* "10 seconds") except for 1 (ie "1 second")</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param millis the elapsed time to report in milliseconds
|
||||
* @return the formatted text in minutes/seconds
|
||||
*/
|
||||
public static String formatWords(long millis, boolean supressLeadingZeroElements, boolean supressTrailingZeroElements) {
|
||||
long[] values = new long[4];
|
||||
values[0] = millis / DateUtils.MILLIS_IN_DAY;
|
||||
values[1] = (millis / DateUtils.MILLIS_IN_HOUR) % 24;
|
||||
values[2] = (millis / DateUtils.MILLIS_IN_MINUTE) % 60;
|
||||
values[3] = (millis / DateUtils.MILLIS_IN_SECOND) % 60;
|
||||
String[] fieldsOne = {" day ", " hour ", " minute ", " second"};
|
||||
String[] fieldsPlural = {" days ", " hours ", " minutes ", " seconds"};
|
||||
|
||||
StringBuffer buf = new StringBuffer(64);
|
||||
boolean valueOutput = false;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
long value = values[i];
|
||||
if (value == 0) {
|
||||
// handle zero
|
||||
if (valueOutput) {
|
||||
if (supressTrailingZeroElements == false) {
|
||||
buf.append('0').append(fieldsPlural[i]);
|
||||
}
|
||||
} else {
|
||||
if (supressLeadingZeroElements == false) {
|
||||
buf.append('0').append(fieldsPlural[i]);
|
||||
}
|
||||
}
|
||||
} else if (value == 1) {
|
||||
// one
|
||||
valueOutput = true;
|
||||
buf.append('1').append(fieldsOne[i]);
|
||||
} else {
|
||||
// other
|
||||
valueOutput = true;
|
||||
buf.append(value).append(fieldsPlural[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the time gap as a string.</p>
|
||||
*
|
||||
* <p>The format used is ISO8601-like.
|
||||
* <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.</p>
|
||||
*
|
||||
* @param millis the duration to format
|
||||
* @return the time as a String
|
||||
*/
|
||||
public static String formatISO(long millis) {
|
||||
int hours, minutes, seconds, milliseconds;
|
||||
hours = (int) (millis / DateUtils.MILLIS_IN_HOUR);
|
||||
millis = millis - (hours * DateUtils.MILLIS_IN_HOUR);
|
||||
minutes = (int) (millis / DateUtils.MILLIS_IN_MINUTE);
|
||||
millis = millis - (minutes * DateUtils.MILLIS_IN_MINUTE);
|
||||
seconds = (int) (millis / DateUtils.MILLIS_IN_SECOND);
|
||||
millis = millis - (seconds * DateUtils.MILLIS_IN_SECOND);
|
||||
milliseconds = (int) millis;
|
||||
|
||||
StringBuffer buf = new StringBuffer(32);
|
||||
buf.append(hours);
|
||||
buf.append(':');
|
||||
buf.append((char)(minutes / 10 + '0'));
|
||||
buf.append((char)(minutes % 10 + '0'));
|
||||
buf.append(':');
|
||||
buf.append((char)(seconds / 10 + '0'));
|
||||
buf.append((char)(seconds % 10 + '0'));
|
||||
buf.append('.');
|
||||
if (milliseconds < 10) {
|
||||
buf.append('0').append('0');
|
||||
} else if (milliseconds < 100) {
|
||||
buf.append('0');
|
||||
}
|
||||
buf.append(milliseconds);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -53,7 +53,6 @@
|
|||
*/
|
||||
package org.apache.commons.lang.time;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.DateFormat;
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.FieldPosition;
|
||||
|
@ -71,11 +70,18 @@ import java.util.Map;
|
|||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* FastDateFormat is similar to {@link java.text.SimpleDateFormat}, but
|
||||
* faster and thread-safe.
|
||||
* FastDateFormat is a fast and thread-safe version of {@link java.text.SimpleDateFormat}.
|
||||
* <p>
|
||||
* Only formatting is supported, but all patterns are compatible with
|
||||
* SimpleDateFormat.
|
||||
* SimpleDateFormat (except timezones - see below).
|
||||
* <p>
|
||||
* Java 1.4 introduced a new pattern letter, 'Z', to represent time zones in
|
||||
* RFC822 format (eg. +0800 or -1100). This pattern letter can be used here (on
|
||||
* all JDK versions).
|
||||
* <p>
|
||||
* In addition, the pattern 'ZZ' has been made to represent ISO8601 full format
|
||||
* time zones (eg. +08:00 or -11:00). This introduces a minor incompatability with
|
||||
* Java 1.4, but at a gain of useful functionality.
|
||||
* <p>
|
||||
* NOTE: Code originally taken from the open source TreeTrove project.
|
||||
*
|
||||
|
@ -84,24 +90,34 @@ import java.util.TimeZone;
|
|||
* @author Gary Gregory
|
||||
* @author Stephen Colebourne
|
||||
* @since 2.0
|
||||
* @version $Id: FastDateFormat.java,v 1.5 2003/05/21 23:39:53 scolebourne Exp $
|
||||
* @version $Id: FastDateFormat.java,v 1.6 2003/06/08 23:14:23 scolebourne Exp $
|
||||
*/
|
||||
public class FastDateFormat extends Format {
|
||||
// A lot of the speed in this class comes from caching, but some comes
|
||||
// from the special int to StringBuffer conversion.
|
||||
//
|
||||
// The following produces a padded 2 digit number:
|
||||
// buffer.append((char)(value / 10 + '0'));
|
||||
// buffer.append((char)(value % 10 + '0'));
|
||||
//
|
||||
// Note that the fastest append to StringBuffer is a single char (used here).
|
||||
// Note that Integer.toString() is not called, the conversion is simply
|
||||
// taking the value and adding (mathematically) the ASCII value for '0'.
|
||||
// So, don't change this code! It works and is vary fast.
|
||||
|
||||
/** FULL date or time style */
|
||||
/** FULL locale dependent date or time style */
|
||||
public static final int FULL = SimpleDateFormat.FULL;
|
||||
/** LONG date or time style */
|
||||
/** LONG locale dependent date or time style */
|
||||
public static final int LONG = SimpleDateFormat.LONG;
|
||||
/** MEDIUM date or time style */
|
||||
/** MEDIUM locale dependent date or time style */
|
||||
public static final int MEDIUM = SimpleDateFormat.MEDIUM;
|
||||
/** SHORT date or time style */
|
||||
/** SHORT locale dependent date or time style */
|
||||
public static final int SHORT = SimpleDateFormat.SHORT;
|
||||
|
||||
// package scoped as used by inner class
|
||||
static final double LOG_10 = Math.log(10);
|
||||
|
||||
private static String cDefaultPattern;
|
||||
private static TimeZone cDefaultTimeZone = TimeZone.getDefault();
|
||||
|
||||
private static Map cInstanceCache = new HashMap(7);
|
||||
private static Map cDateInstanceCache = new HashMap(7);
|
||||
|
@ -113,12 +129,16 @@ public class FastDateFormat extends Format {
|
|||
private final String mPattern;
|
||||
/** The time zone */
|
||||
private final TimeZone mTimeZone;
|
||||
/** Whether the time zone overrides any on Calendars */
|
||||
private final boolean mTimeZoneForced;
|
||||
/** The locale */
|
||||
private final Locale mLocale;
|
||||
/** Whether the locale overrides the default */
|
||||
private final boolean mLocaleForced;
|
||||
/** The parsed rules */
|
||||
private final Rule[] mRules;
|
||||
private Rule[] mRules;
|
||||
/** The estimated maximum length */
|
||||
private final int mMaxLengthEstimate;
|
||||
private int mMaxLengthEstimate;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
|
@ -172,25 +192,15 @@ public class FastDateFormat extends Format {
|
|||
* @param timeZone optional time zone, overrides time zone of formatted date
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a pattern based date/time formatter
|
||||
* @throws IllegalArgumentException if pattern is invalid
|
||||
* @throws IllegalArgumentException if pattern is invalid or null
|
||||
*/
|
||||
public static synchronized FastDateFormat getInstance(String pattern, TimeZone timeZone, Locale locale) {
|
||||
Object key = pattern;
|
||||
if (timeZone != null) {
|
||||
key = new Pair(key, timeZone);
|
||||
}
|
||||
if (locale != null) {
|
||||
key = new Pair(key, locale);
|
||||
}
|
||||
|
||||
FastDateFormat format = (FastDateFormat) cInstanceCache.get(key);
|
||||
FastDateFormat emptyFormat = new FastDateFormat(pattern, timeZone, locale);
|
||||
FastDateFormat format = (FastDateFormat) cInstanceCache.get(emptyFormat);
|
||||
if (format == null) {
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
|
||||
format = new FastDateFormat(pattern, timeZone, locale, new DateFormatSymbols(locale));
|
||||
cInstanceCache.put(key, format);
|
||||
format = emptyFormat;
|
||||
format.init(); // convert shell format into usable one
|
||||
cInstanceCache.put(format, format); // this is OK!
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
@ -342,17 +352,62 @@ public class FastDateFormat extends Format {
|
|||
return cDefaultPattern;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Constructs a new FastDateFormat.
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern
|
||||
* @param timeZone time zone to use, null means use default for Date and
|
||||
* value within for Calendar
|
||||
* @param locale locale, null means use system default
|
||||
* @throws IllegalArgumentException if pattern is invalid or null
|
||||
*/
|
||||
protected FastDateFormat(String pattern, TimeZone timeZone, Locale locale) {
|
||||
super();
|
||||
if (pattern == null) {
|
||||
throw new IllegalArgumentException("The pattern must not be null");
|
||||
}
|
||||
mPattern = pattern;
|
||||
|
||||
mTimeZoneForced = (timeZone != null);
|
||||
if (timeZone == null) {
|
||||
timeZone = TimeZone.getDefault();
|
||||
}
|
||||
mTimeZone = timeZone;
|
||||
|
||||
mLocaleForced = (locale != null);
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
mLocale = locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the instance for first use.
|
||||
*/
|
||||
protected void init() {
|
||||
List rulesList = parsePattern();
|
||||
mRules = (Rule[]) rulesList.toArray(new Rule[rulesList.size()]);
|
||||
|
||||
int len = 0;
|
||||
for (int i=mRules.length; --i >= 0; ) {
|
||||
len += mRules[i].estimateLength();
|
||||
}
|
||||
|
||||
mMaxLengthEstimate = len;
|
||||
}
|
||||
|
||||
// Parse the pattern
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a list of Rules given a pattern.
|
||||
*
|
||||
* @param pattern the pattern to parse
|
||||
* @param timeZone the time zone to use
|
||||
* @param locale the locale to use
|
||||
* @param symbols the symbols to use
|
||||
* @return a List of Rule objects
|
||||
* @throws IllegalArgumentException if pattern is invalid
|
||||
*/
|
||||
private static List parse(String pattern, TimeZone timeZone, Locale locale, DateFormatSymbols symbols) {
|
||||
protected List parsePattern() {
|
||||
DateFormatSymbols symbols = new DateFormatSymbols(mLocale);
|
||||
List rules = new ArrayList();
|
||||
|
||||
String[] ERAs = symbols.getEras();
|
||||
|
@ -362,12 +417,12 @@ public class FastDateFormat extends Format {
|
|||
String[] shortWeekdays = symbols.getShortWeekdays();
|
||||
String[] AmPmStrings = symbols.getAmPmStrings();
|
||||
|
||||
int length = pattern.length();
|
||||
int length = mPattern.length();
|
||||
int[] indexRef = new int[1];
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
indexRef[0] = i;
|
||||
String token = parseToken(pattern, indexRef);
|
||||
String token = parseToken(mPattern, indexRef);
|
||||
i = indexRef[0];
|
||||
|
||||
int tokenLen = token.length();
|
||||
|
@ -384,9 +439,9 @@ public class FastDateFormat extends Format {
|
|||
break;
|
||||
case 'y': // year (number)
|
||||
if (tokenLen >= 4) {
|
||||
rule = new UnpaddedNumberField(Calendar.YEAR);
|
||||
rule = UnpaddedNumberField.INSTANCE_YEAR;
|
||||
} else {
|
||||
rule = new TwoDigitYearField();
|
||||
rule = TwoDigitYearField.INSTANCE;
|
||||
}
|
||||
break;
|
||||
case 'M': // month in year (text and number)
|
||||
|
@ -395,9 +450,9 @@ public class FastDateFormat extends Format {
|
|||
} else if (tokenLen == 3) {
|
||||
rule = new TextField(Calendar.MONTH, shortMonths);
|
||||
} else if (tokenLen == 2) {
|
||||
rule = new TwoDigitMonthField();
|
||||
rule = TwoDigitMonthField.INSTANCE;
|
||||
} else {
|
||||
rule = new UnpaddedMonthField();
|
||||
rule = UnpaddedMonthField.INSTANCE;
|
||||
}
|
||||
break;
|
||||
case 'd': // day in month (number)
|
||||
|
@ -444,9 +499,16 @@ public class FastDateFormat extends Format {
|
|||
break;
|
||||
case 'z': // time zone (text)
|
||||
if (tokenLen >= 4) {
|
||||
rule = new TimeZoneRule(timeZone, locale, TimeZone.LONG);
|
||||
rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.LONG);
|
||||
} else {
|
||||
rule = new TimeZoneRule(timeZone, locale, TimeZone.SHORT);
|
||||
rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.SHORT);
|
||||
}
|
||||
break;
|
||||
case 'Z': // time zone (value)
|
||||
if (tokenLen == 1) {
|
||||
rule = TimeZoneNumberRule.INSTANCE_NO_COLON;
|
||||
} else {
|
||||
rule = TimeZoneNumberRule.INSTANCE_COLON;
|
||||
}
|
||||
break;
|
||||
case '\'': // literal text
|
||||
|
@ -474,7 +536,7 @@ public class FastDateFormat extends Format {
|
|||
* @param indexRef index references
|
||||
* @return parsed token
|
||||
*/
|
||||
private static String parseToken(String pattern, int[] indexRef) {
|
||||
protected String parseToken(String pattern, int[] indexRef) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
int i = indexRef[0];
|
||||
|
@ -533,7 +595,7 @@ public class FastDateFormat extends Format {
|
|||
* @param padding the padding required
|
||||
* @return a new rule with the correct padding
|
||||
*/
|
||||
private static NumberRule selectNumberRule(int field, int padding) {
|
||||
protected NumberRule selectNumberRule(int field, int padding) {
|
||||
switch (padding) {
|
||||
case 1:
|
||||
return new UnpaddedNumberField(field);
|
||||
|
@ -544,40 +606,7 @@ public class FastDateFormat extends Format {
|
|||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Constructs a new FastDateFormat.
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @param symbols optional date format symbols, overrides symbols for provided locale
|
||||
* @throws IllegalArgumentException if pattern is invalid
|
||||
*/
|
||||
private FastDateFormat(String pattern, TimeZone timeZone, Locale locale, DateFormatSymbols symbols) {
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
|
||||
mPattern = pattern;
|
||||
mTimeZone = timeZone;
|
||||
mLocale = locale;
|
||||
|
||||
if (symbols == null) {
|
||||
symbols = new DateFormatSymbols(locale);
|
||||
}
|
||||
|
||||
List rulesList = parse(pattern, timeZone, locale, symbols);
|
||||
mRules = (Rule[]) rulesList.toArray(new Rule[rulesList.size()]);
|
||||
|
||||
int len = 0;
|
||||
for (int i=mRules.length; --i >= 0; ) {
|
||||
len += mRules[i].estimateLength();
|
||||
}
|
||||
|
||||
mMaxLengthEstimate = len;
|
||||
}
|
||||
|
||||
// Format methods
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Format either a Date or a Calendar object.
|
||||
|
@ -605,11 +634,8 @@ public class FastDateFormat extends Format {
|
|||
* @return the formatted string
|
||||
*/
|
||||
public String format(Date date) {
|
||||
Calendar c = new GregorianCalendar(cDefaultTimeZone);
|
||||
Calendar c = new GregorianCalendar(mTimeZone);
|
||||
c.setTime(date);
|
||||
if (mTimeZone != null) {
|
||||
c.setTimeZone(mTimeZone);
|
||||
}
|
||||
return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString();
|
||||
}
|
||||
|
||||
|
@ -631,11 +657,8 @@ public class FastDateFormat extends Format {
|
|||
* @return the specified string buffer
|
||||
*/
|
||||
public StringBuffer format(Date date, StringBuffer buf) {
|
||||
Calendar c = new GregorianCalendar(cDefaultTimeZone);
|
||||
Calendar c = new GregorianCalendar(mTimeZone);
|
||||
c.setTime(date);
|
||||
if (mTimeZone != null) {
|
||||
c.setTimeZone(mTimeZone);
|
||||
}
|
||||
return applyRules(c, buf);
|
||||
}
|
||||
|
||||
|
@ -647,7 +670,7 @@ public class FastDateFormat extends Format {
|
|||
* @return the specified string buffer
|
||||
*/
|
||||
public StringBuffer format(Calendar calendar, StringBuffer buf) {
|
||||
if (mTimeZone != null) {
|
||||
if (mTimeZoneForced) {
|
||||
calendar = (Calendar) calendar.clone();
|
||||
calendar.setTimeZone(mTimeZone);
|
||||
}
|
||||
|
@ -661,7 +684,7 @@ public class FastDateFormat extends Format {
|
|||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
*/
|
||||
private StringBuffer applyRules(Calendar calendar, StringBuffer buf) {
|
||||
protected StringBuffer applyRules(Calendar calendar, StringBuffer buf) {
|
||||
Rule[] rules = mRules;
|
||||
int len = mRules.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
@ -670,6 +693,7 @@ public class FastDateFormat extends Format {
|
|||
return buf;
|
||||
}
|
||||
|
||||
// Parsing
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Parsing not supported.
|
||||
|
@ -684,6 +708,7 @@ public class FastDateFormat extends Format {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the pattern used by this formatter.
|
||||
|
@ -695,8 +720,11 @@ public class FastDateFormat extends Format {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the time zone used by this formatter, or null if time zone of
|
||||
* formatted dates is used instead.
|
||||
* Gets the time zone used by this formatter.
|
||||
* <p>
|
||||
* This zone is always used for Date formatting.
|
||||
* If a Calendar is passed in to be formatted, the time zone on that may
|
||||
* be used depending on {@link #getTimeZoneOverridesCalendar()}.
|
||||
*
|
||||
* @return the time zone
|
||||
*/
|
||||
|
@ -704,6 +732,16 @@ public class FastDateFormat extends Format {
|
|||
return mTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the time zone of the calendar overrides the time zone
|
||||
* of the formatter
|
||||
*
|
||||
* @return true if time zone of formatter overridden for calendars
|
||||
*/
|
||||
public boolean getTimeZoneOverridesCalendar() {
|
||||
return mTimeZoneForced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the locale used by this formatter.
|
||||
*
|
||||
|
@ -723,6 +761,56 @@ public class FastDateFormat extends Format {
|
|||
return mMaxLengthEstimate;
|
||||
}
|
||||
|
||||
// Basics
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Compare two objects for equality.
|
||||
*
|
||||
* @param obj the object to compare to
|
||||
* @return true if equal
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof FastDateFormat == false) {
|
||||
return false;
|
||||
}
|
||||
FastDateFormat other = (FastDateFormat) obj;
|
||||
if (
|
||||
(mPattern == other.mPattern || mPattern.equals(other.mPattern)) &&
|
||||
(mTimeZone == other.mTimeZone || mTimeZone.equals(other.mTimeZone)) &&
|
||||
(mLocale == other.mLocale || mLocale.equals(other.mLocale)) &&
|
||||
(mTimeZoneForced == other.mTimeZoneForced) &&
|
||||
(mLocaleForced == other.mLocaleForced)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A suitable hashcode.
|
||||
*
|
||||
* @return a hashcode compatable with equals
|
||||
*/
|
||||
public int hashCode() {
|
||||
int total = 0;
|
||||
total += mPattern.hashCode();
|
||||
total += mTimeZone.hashCode();
|
||||
total += (mTimeZoneForced ? 1 : 0);
|
||||
total += mLocale.hashCode();
|
||||
total += (mLocaleForced ? 1 : 0);
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a debugging string version of this formatter.
|
||||
*
|
||||
* @return a debugging string
|
||||
*/
|
||||
public String toString() {
|
||||
return "FastDateFormat[" + mPattern + "]";
|
||||
}
|
||||
|
||||
// Rules
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Inner class defining a rule.
|
||||
|
@ -809,6 +897,8 @@ public class FastDateFormat extends Format {
|
|||
* Inner class to output an unpadded number.
|
||||
*/
|
||||
private static class UnpaddedNumberField implements NumberRule {
|
||||
static final UnpaddedNumberField INSTANCE_YEAR = new UnpaddedNumberField(Calendar.YEAR);
|
||||
|
||||
private final int mField;
|
||||
|
||||
UnpaddedNumberField(int field) {
|
||||
|
@ -826,12 +916,10 @@ public class FastDateFormat extends Format {
|
|||
public final void appendTo(StringBuffer buffer, int value) {
|
||||
if (value < 10) {
|
||||
buffer.append((char)(value + '0'));
|
||||
}
|
||||
else if (value < 100) {
|
||||
} else if (value < 100) {
|
||||
buffer.append((char)(value / 10 + '0'));
|
||||
buffer.append((char)(value % 10 + '0'));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
buffer.append(Integer.toString(value));
|
||||
}
|
||||
}
|
||||
|
@ -841,6 +929,8 @@ public class FastDateFormat extends Format {
|
|||
* Inner class to output an unpadded month.
|
||||
*/
|
||||
private static class UnpaddedMonthField implements NumberRule {
|
||||
static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField();
|
||||
|
||||
UnpaddedMonthField() {
|
||||
}
|
||||
|
||||
|
@ -855,8 +945,7 @@ public class FastDateFormat extends Format {
|
|||
public final void appendTo(StringBuffer buffer, int value) {
|
||||
if (value < 10) {
|
||||
buffer.append((char)(value + '0'));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
buffer.append((char)(value / 10 + '0'));
|
||||
buffer.append((char)(value % 10 + '0'));
|
||||
}
|
||||
|
@ -894,13 +983,11 @@ public class FastDateFormat extends Format {
|
|||
}
|
||||
buffer.append((char)(value / 10 + '0'));
|
||||
buffer.append((char)(value % 10 + '0'));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
int digits;
|
||||
if (value < 1000) {
|
||||
digits = 3;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
digits = (int)(Math.log(value) / LOG_10) + 1;
|
||||
}
|
||||
for (int i = mSize; --i >= digits; ) {
|
||||
|
@ -933,8 +1020,7 @@ public class FastDateFormat extends Format {
|
|||
if (value < 100) {
|
||||
buffer.append((char)(value / 10 + '0'));
|
||||
buffer.append((char)(value % 10 + '0'));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
buffer.append(Integer.toString(value));
|
||||
}
|
||||
}
|
||||
|
@ -944,6 +1030,8 @@ public class FastDateFormat extends Format {
|
|||
* Inner class to output a two digit year.
|
||||
*/
|
||||
private static class TwoDigitYearField implements NumberRule {
|
||||
static final TwoDigitYearField INSTANCE = new TwoDigitYearField();
|
||||
|
||||
TwoDigitYearField() {
|
||||
}
|
||||
|
||||
|
@ -965,6 +1053,8 @@ public class FastDateFormat extends Format {
|
|||
* Inner class to output a two digit month.
|
||||
*/
|
||||
private static class TwoDigitMonthField implements NumberRule {
|
||||
static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField();
|
||||
|
||||
TwoDigitMonthField() {
|
||||
}
|
||||
|
||||
|
@ -1037,71 +1127,101 @@ public class FastDateFormat extends Format {
|
|||
}
|
||||
|
||||
/**
|
||||
* Inner class to output a time zone.
|
||||
* Inner class to output a time zone name.
|
||||
*/
|
||||
private static class TimeZoneRule implements Rule {
|
||||
private static class TimeZoneNameRule implements Rule {
|
||||
private final TimeZone mTimeZone;
|
||||
private final boolean mTimeZoneForced;
|
||||
private final Locale mLocale;
|
||||
private final int mStyle;
|
||||
private final String mStandard;
|
||||
private final String mDaylight;
|
||||
|
||||
TimeZoneRule(TimeZone timeZone, Locale locale, int style) {
|
||||
TimeZoneNameRule(TimeZone timeZone, boolean timeZoneForced, Locale locale, int style) {
|
||||
mTimeZone = timeZone;
|
||||
mTimeZoneForced = timeZoneForced;
|
||||
mLocale = locale;
|
||||
mStyle = style;
|
||||
|
||||
if (timeZone != null) {
|
||||
if (timeZoneForced) {
|
||||
mStandard = getTimeZoneDisplay(timeZone, false, style, locale);
|
||||
mDaylight = getTimeZoneDisplay(timeZone, true, style, locale);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
mStandard = null;
|
||||
mDaylight = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int estimateLength() {
|
||||
if (mTimeZone != null) {
|
||||
if (mTimeZoneForced) {
|
||||
return Math.max(mStandard.length(), mDaylight.length());
|
||||
}
|
||||
else if (mStyle == TimeZone.SHORT) {
|
||||
} else if (mStyle == TimeZone.SHORT) {
|
||||
return 4;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return 40;
|
||||
}
|
||||
}
|
||||
|
||||
public void appendTo(StringBuffer buffer, Calendar calendar) {
|
||||
TimeZone timeZone;
|
||||
if ((timeZone = mTimeZone) != null) {
|
||||
if (timeZone.useDaylightTime() &&
|
||||
calendar.get(Calendar.DST_OFFSET) != 0) {
|
||||
|
||||
if (mTimeZoneForced) {
|
||||
if (mTimeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) {
|
||||
buffer.append(mDaylight);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
buffer.append(mStandard);
|
||||
}
|
||||
}
|
||||
else {
|
||||
timeZone = calendar.getTimeZone();
|
||||
if (timeZone.useDaylightTime() &&
|
||||
calendar.get(Calendar.DST_OFFSET) != 0) {
|
||||
|
||||
buffer.append(getTimeZoneDisplay
|
||||
(timeZone, true, mStyle, mLocale));
|
||||
}
|
||||
else {
|
||||
buffer.append(getTimeZoneDisplay
|
||||
(timeZone, false, mStyle, mLocale));
|
||||
} else {
|
||||
TimeZone timeZone = calendar.getTimeZone();
|
||||
if (timeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) {
|
||||
buffer.append(getTimeZoneDisplay(timeZone, true, mStyle, mLocale));
|
||||
} else {
|
||||
buffer.append(getTimeZoneDisplay(timeZone, false, mStyle, mLocale));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
/**
|
||||
* Inner class to output a time zone as a number +/-HHMM or +/-HH:MM.
|
||||
*/
|
||||
private static class TimeZoneNumberRule implements Rule {
|
||||
static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true);
|
||||
static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false);
|
||||
|
||||
final boolean mColon;
|
||||
|
||||
TimeZoneNumberRule(boolean colon) {
|
||||
mColon = colon;
|
||||
}
|
||||
|
||||
public int estimateLength() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
public void appendTo(StringBuffer buffer, Calendar calendar) {
|
||||
int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
|
||||
|
||||
if (offset < 0) {
|
||||
buffer.append('-');
|
||||
offset = -offset;
|
||||
} else {
|
||||
buffer.append('+');
|
||||
}
|
||||
|
||||
int hours = offset / (60 * 60 * 1000);
|
||||
buffer.append((char)(hours / 10 + '0'));
|
||||
buffer.append((char)(hours % 10 + '0'));
|
||||
|
||||
if (mColon) {
|
||||
buffer.append(':');
|
||||
}
|
||||
|
||||
int minutes = offset / (60 * 1000) - 60 * hours;
|
||||
buffer.append((char)(minutes / 10 + '0'));
|
||||
buffer.append((char)(minutes % 10 + '0'));
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Inner class that acts as a compound key for time zone names.
|
||||
*/
|
||||
|
@ -1139,12 +1259,12 @@ public class FastDateFormat extends Format {
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------
|
||||
/**
|
||||
* Helper class for creating compound objects. One use for this class is to create a
|
||||
* hashtable key out of multiple objects.
|
||||
*/
|
||||
private static class Pair implements Comparable, Serializable {
|
||||
private static class Pair {
|
||||
private final Object mObj1;
|
||||
private final Object mObj2;
|
||||
|
||||
|
@ -1153,56 +1273,6 @@ public class FastDateFormat extends Format {
|
|||
mObj2 = obj2;
|
||||
}
|
||||
|
||||
public int compareTo(Object obj) {
|
||||
if (this == obj) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Pair other = (Pair)obj;
|
||||
|
||||
Object a = mObj1;
|
||||
Object b = other.mObj1;
|
||||
|
||||
firstTest: {
|
||||
if (a == null) {
|
||||
if (b != null) {
|
||||
return 1;
|
||||
}
|
||||
// Both a and b are null.
|
||||
break firstTest;
|
||||
}
|
||||
else {
|
||||
if (b == null) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int result = ((Comparable)a).compareTo(b);
|
||||
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
a = mObj2;
|
||||
b = other.mObj2;
|
||||
|
||||
if (a == null) {
|
||||
if (b != null) {
|
||||
return 1;
|
||||
}
|
||||
// Both a and b are null.
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if (b == null) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ((Comparable)a).compareTo(b);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 1999-2003 The Apache Software Foundation. All rights
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -77,13 +77,10 @@ package org.apache.commons.lang.time;
|
|||
* @author Henri Yandell
|
||||
* @author Stephen Colebourne
|
||||
* @since 2.0
|
||||
* @version $Id: StopWatch.java,v 1.3 2003/05/21 23:37:20 scolebourne Exp $
|
||||
* @version $Id: StopWatch.java,v 1.4 2003/06/08 23:14:23 scolebourne Exp $
|
||||
*/
|
||||
public class StopWatch {
|
||||
|
||||
private static final int MILLIS_IN_HOUR = 60 * 60 * 1000;
|
||||
private static final int MILLIS_IN_MINUTE = 60 * 1000;
|
||||
|
||||
/** The start time */
|
||||
private long startTime = -1;
|
||||
/** The stop time */
|
||||
|
@ -187,53 +184,13 @@ public class StopWatch {
|
|||
/**
|
||||
* <p>Gets a summary of the time that the stopwatch recorded as a string.</p>
|
||||
*
|
||||
* <p>The format used is ISO8601,
|
||||
* <p>The format used is ISO8601-like,
|
||||
* <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.</p>
|
||||
*
|
||||
* @return the time as a String
|
||||
*/
|
||||
public String toString() {
|
||||
return StopWatch.toString(getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get the time gap as a string.</p>
|
||||
*
|
||||
* <p>The format used is ISO8601,
|
||||
* <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.</p>
|
||||
*
|
||||
* @return the time as a String
|
||||
*/
|
||||
public static String toString(long time) {
|
||||
int hours, minutes, seconds, milliseconds;
|
||||
hours = (int) (time / MILLIS_IN_HOUR);
|
||||
time = time - (hours * MILLIS_IN_HOUR);
|
||||
minutes = (int) (time / MILLIS_IN_MINUTE);
|
||||
time = time - (minutes * MILLIS_IN_MINUTE);
|
||||
seconds = (int) (time / 1000);
|
||||
time = time - (seconds * 1000);
|
||||
milliseconds = (int) time;
|
||||
|
||||
StringBuffer buf = new StringBuffer(32);
|
||||
buf.append(hours);
|
||||
buf.append(':');
|
||||
if (minutes < 10) {
|
||||
buf.append('0');
|
||||
}
|
||||
buf.append(minutes);
|
||||
buf.append(':');
|
||||
if (seconds < 10) {
|
||||
buf.append('0');
|
||||
}
|
||||
buf.append(seconds);
|
||||
buf.append('.');
|
||||
if (milliseconds < 10) {
|
||||
buf.append("00");
|
||||
} else if (milliseconds < 100) {
|
||||
buf.append('0');
|
||||
}
|
||||
buf.append(milliseconds);
|
||||
return buf.toString();
|
||||
return DurationFormatUtils.formatISO(getTime());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,379 +0,0 @@
|
|||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution, if
|
||||
* any, must include the following acknowlegement:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowlegement may appear in the software itself,
|
||||
* if and wherever such third-party acknowlegements normally appear.
|
||||
*
|
||||
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
|
||||
* Foundation" must not be used to endorse or promote products derived
|
||||
* from this software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache"
|
||||
* nor may "Apache" appear in their names without prior written
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
package org.apache.commons.lang.time;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
/**
|
||||
* Unit tests {@link org.apache.commons.lang.CalendarUtils}.
|
||||
*
|
||||
* @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
|
||||
*/
|
||||
public class CalendarUtilsTest extends TestCase {
|
||||
DateFormat parser = null;
|
||||
Date date1 = null;
|
||||
Date date2 = null;
|
||||
|
||||
public CalendarUtilsTest(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestRunner.run(suite());
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite(CalendarUtilsTest.class);
|
||||
suite.setName("CalendarUtilsTest Tests");
|
||||
return suite;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
parser = new java.text.SimpleDateFormat("MMM dd, yyyy H:mm:ss.SSS");
|
||||
|
||||
date1 = parser.parse("February 12, 2002 12:34:56.789");
|
||||
date2 = parser.parse("November 18, 2001 1:23:11.321");
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Tests various values with the round method
|
||||
*/
|
||||
public void testRound() throws Exception {
|
||||
assertEquals("round year-1 failed",
|
||||
new Date("2002 January 1"),
|
||||
CalendarUtils.round(date1, Calendar.YEAR));
|
||||
assertEquals("round year-2 failed",
|
||||
new Date("2002 January 1"),
|
||||
CalendarUtils.round(date2, Calendar.YEAR));
|
||||
assertEquals("round month-1 failed",
|
||||
new Date("2002 February 1"),
|
||||
CalendarUtils.round(date1, Calendar.MONTH));
|
||||
assertEquals("round month-2 failed",
|
||||
new Date("2001 December 1"),
|
||||
CalendarUtils.round(date2, Calendar.MONTH));
|
||||
assertEquals("round semimonth-1 failed",
|
||||
new Date("2002 February 16"),
|
||||
CalendarUtils.round(date1, CalendarUtils.SEMI_MONTH));
|
||||
assertEquals("round semimonth-2 failed",
|
||||
new Date("2001 November 16"),
|
||||
CalendarUtils.round(date2, CalendarUtils.SEMI_MONTH));
|
||||
assertEquals("round date-1 failed",
|
||||
new Date("2002 February 13"),
|
||||
CalendarUtils.round(date1, Calendar.DATE));
|
||||
assertEquals("round date-2 failed",
|
||||
new Date("2001 November 18"),
|
||||
CalendarUtils.round(date2, Calendar.DATE));
|
||||
assertEquals("round hour-1 failed",
|
||||
parser.parse("February 12, 2002 13:00:00.000"),
|
||||
CalendarUtils.round(date1, Calendar.HOUR));
|
||||
assertEquals("round hour-2 failed",
|
||||
parser.parse("November 18, 2001 1:00:00.000"),
|
||||
CalendarUtils.round(date2, Calendar.HOUR));
|
||||
assertEquals("round minute-1 failed",
|
||||
parser.parse("February 12, 2002 12:35:00.000"),
|
||||
CalendarUtils.round(date1, Calendar.MINUTE));
|
||||
assertEquals("round minute-2 failed",
|
||||
parser.parse("November 18, 2001 1:23:00.000"),
|
||||
CalendarUtils.round(date2, Calendar.MINUTE));
|
||||
assertEquals("round second-1 failed",
|
||||
parser.parse("February 12, 2002 12:34:57.000"),
|
||||
CalendarUtils.round(date1, Calendar.SECOND));
|
||||
assertEquals("round second-2 failed",
|
||||
parser.parse("November 18, 2001 1:23:11.000"),
|
||||
CalendarUtils.round(date2, Calendar.SECOND));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests various values with the trunc method
|
||||
*/
|
||||
public void testTrunc() throws Exception {
|
||||
assertEquals("trunc year-1 failed",
|
||||
new Date("2002 January 1"),
|
||||
CalendarUtils.trunc(date1, Calendar.YEAR));
|
||||
assertEquals("trunc year-2 failed",
|
||||
new Date("2001 January 1"),
|
||||
CalendarUtils.trunc(date2, Calendar.YEAR));
|
||||
assertEquals("trunc month-1 failed",
|
||||
new Date("2002 February 1"),
|
||||
CalendarUtils.trunc(date1, Calendar.MONTH));
|
||||
assertEquals("trunc month-2 failed",
|
||||
new Date("2001 November 1"),
|
||||
CalendarUtils.trunc(date2, Calendar.MONTH));
|
||||
assertEquals("trunc semimonth-1 failed",
|
||||
new Date("2002 February 1"),
|
||||
CalendarUtils.trunc(date1, CalendarUtils.SEMI_MONTH));
|
||||
assertEquals("trunc semimonth-2 failed",
|
||||
new Date("2001 November 16"),
|
||||
CalendarUtils.trunc(date2, CalendarUtils.SEMI_MONTH));
|
||||
assertEquals("trunc date-1 failed",
|
||||
new Date("2002 February 12"),
|
||||
CalendarUtils.trunc(date1, Calendar.DATE));
|
||||
assertEquals("trunc date-2 failed",
|
||||
new Date("2001 November 18"),
|
||||
CalendarUtils.trunc(date2, Calendar.DATE));
|
||||
assertEquals("trunc hour-1 failed",
|
||||
parser.parse("February 12, 2002 12:00:00.000"),
|
||||
CalendarUtils.trunc(date1, Calendar.HOUR));
|
||||
assertEquals("trunc hour-2 failed",
|
||||
parser.parse("November 18, 2001 1:00:00.000"),
|
||||
CalendarUtils.trunc(date2, Calendar.HOUR));
|
||||
assertEquals("trunc minute-1 failed",
|
||||
parser.parse("February 12, 2002 12:34:00.000"),
|
||||
CalendarUtils.trunc(date1, Calendar.MINUTE));
|
||||
assertEquals("trunc minute-2 failed",
|
||||
parser.parse("November 18, 2001 1:23:00.000"),
|
||||
CalendarUtils.trunc(date2, Calendar.MINUTE));
|
||||
assertEquals("trunc second-1 failed",
|
||||
parser.parse("February 12, 2002 12:34:56.000"),
|
||||
CalendarUtils.trunc(date1, Calendar.SECOND));
|
||||
assertEquals("trunc second-2 failed",
|
||||
parser.parse("November 18, 2001 1:23:11.000"),
|
||||
CalendarUtils.trunc(date2, Calendar.SECOND));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the parse method, which is supposed to handle various strings
|
||||
* as flexibly as CVS supports.
|
||||
*/
|
||||
public void testParse() throws Exception {
|
||||
//This is difficult to test since the "now" used in the
|
||||
// parse function cannot be controlled. We could possibly control
|
||||
// it by trying before and after and making sure the value we expect
|
||||
// is between the two values calculated.
|
||||
//For now we're just using the custom assertEquals that takes a delta
|
||||
|
||||
Calendar now = null;
|
||||
|
||||
now = Calendar.getInstance();
|
||||
now.add(Calendar.MINUTE, -1);
|
||||
assertEquals("parse 1 minute ago",
|
||||
now, CalendarUtils.parse("1 minute ago"), 50);
|
||||
now = Calendar.getInstance();
|
||||
now.add(Calendar.MINUTE, -8);
|
||||
assertEquals("parse 8 minutes ago",
|
||||
now, CalendarUtils.parse("8 minutes ago"), 50);
|
||||
|
||||
now = Calendar.getInstance();
|
||||
now.add(Calendar.DATE, -1);
|
||||
assertEquals("parse yesterday",
|
||||
now, CalendarUtils.parse("yesterday"), 50);
|
||||
|
||||
now = Calendar.getInstance();
|
||||
now.add(Calendar.DATE, 1);
|
||||
assertEquals("parse tomorrow",
|
||||
now, CalendarUtils.parse("tomorrow"), 50);
|
||||
|
||||
now = Calendar.getInstance();
|
||||
//Sunday would be 1, Saturday would be 7, so we walk back up to 6 days.
|
||||
if (now.get(Calendar.DATE) == 1) {
|
||||
//If Sunday already, we go back a full week
|
||||
now.add(Calendar.DATE, -7);
|
||||
} else {
|
||||
now.add(Calendar.DATE, 1 - now.get(Calendar.DAY_OF_WEEK));
|
||||
}
|
||||
assertEquals("parse last Sunday",
|
||||
now, CalendarUtils.parse("last Sunday"), 50);
|
||||
|
||||
now = Calendar.getInstance();
|
||||
now.add(Calendar.DATE, -7);
|
||||
assertEquals("parse last week",
|
||||
now, CalendarUtils.parse("last week"), 50);
|
||||
|
||||
now = Calendar.getInstance();
|
||||
//January would be 0, December would be 11, so we walk back up to 11 months
|
||||
if (now.get(Calendar.MONTH) == 0) {
|
||||
//If January already, we go back a full year
|
||||
now.add(Calendar.MONTH, -12);
|
||||
} else {
|
||||
now.add(Calendar.MONTH, 0 - now.get(Calendar.MONTH));
|
||||
}
|
||||
assertEquals("parse last January",
|
||||
now, CalendarUtils.parse("last January"), 50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the calendar iterator for week ranges
|
||||
*/
|
||||
public void testWeekIterator() throws Exception {
|
||||
Calendar now = Calendar.getInstance();
|
||||
Calendar today = CalendarUtils.trunc(now, Calendar.DATE);
|
||||
Calendar sunday = CalendarUtils.trunc(now, Calendar.DATE);
|
||||
sunday.add(Calendar.DATE, 1 - sunday.get(Calendar.DAY_OF_WEEK));
|
||||
Calendar monday = CalendarUtils.trunc(now, Calendar.DATE);
|
||||
if (monday.get(Calendar.DATE) == 1) {
|
||||
//This is sunday... roll back 6 days
|
||||
monday.add(Calendar.DATE, -6);
|
||||
} else {
|
||||
monday.add(Calendar.DATE, 2 - monday.get(Calendar.DAY_OF_WEEK));
|
||||
}
|
||||
Calendar centered = CalendarUtils.trunc(now, Calendar.DATE);
|
||||
centered.add(Calendar.DATE, -3);
|
||||
|
||||
Iterator it = CalendarUtils.getCalendarIterator(now, CalendarUtils.RANGE_WEEK_SUNDAY);
|
||||
assertWeekIterator(it, sunday);
|
||||
it = CalendarUtils.getCalendarIterator(now, CalendarUtils.RANGE_WEEK_MONDAY);
|
||||
assertWeekIterator(it, monday);
|
||||
it = CalendarUtils.getCalendarIterator(now, CalendarUtils.RANGE_WEEK_RELATIVE);
|
||||
assertWeekIterator(it, today);
|
||||
it = CalendarUtils.getCalendarIterator(now, CalendarUtils.RANGE_WEEK_CENTER);
|
||||
assertWeekIterator(it, centered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the calendar iterator for month-based ranges
|
||||
*/
|
||||
public void testMonthIterator() throws Exception {
|
||||
Iterator it = CalendarUtils.getCalendarIterator(date1, CalendarUtils.RANGE_MONTH_SUNDAY);
|
||||
assertWeekIterator(it,
|
||||
new Date("January 27, 2002"),
|
||||
new Date("March 2, 2002"));
|
||||
|
||||
it = CalendarUtils.getCalendarIterator(date1, CalendarUtils.RANGE_MONTH_MONDAY);
|
||||
assertWeekIterator(it,
|
||||
new Date("January 28, 2002"),
|
||||
new Date("March 3, 2002"));
|
||||
|
||||
it = CalendarUtils.getCalendarIterator(date2, CalendarUtils.RANGE_MONTH_SUNDAY);
|
||||
assertWeekIterator(it,
|
||||
new Date("October 28, 2001"),
|
||||
new Date("December 1, 2001"));
|
||||
|
||||
it = CalendarUtils.getCalendarIterator(date2, CalendarUtils.RANGE_MONTH_MONDAY);
|
||||
assertWeekIterator(it,
|
||||
new Date("October 29, 2001"),
|
||||
new Date("December 2, 2001"));
|
||||
}
|
||||
|
||||
/**
|
||||
* This checks that this is a 7 element iterator of Calendar objects
|
||||
* that are dates (no time), and exactly 1 day spaced after each other.
|
||||
*/
|
||||
private static void assertWeekIterator(Iterator it, Calendar start) {
|
||||
Calendar end = (Calendar) start.clone();
|
||||
end.add(Calendar.DATE, 6);
|
||||
|
||||
assertWeekIterator(it, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for when working with Date objects
|
||||
*/
|
||||
private static void assertWeekIterator(Iterator it, Date start, Date end) {
|
||||
Calendar calStart = Calendar.getInstance();
|
||||
calStart.setTime(start);
|
||||
Calendar calEnd = Calendar.getInstance();
|
||||
calEnd.setTime(end);
|
||||
|
||||
assertWeekIterator(it, calStart, calEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* This checks that this is a 7 divisble iterator of Calendar objects
|
||||
* that are dates (no time), and exactly 1 day spaced after each other
|
||||
* (in addition to the proper start and stop dates)
|
||||
*/
|
||||
private static void assertWeekIterator(Iterator it, Calendar start, Calendar end) {
|
||||
Calendar cal = (Calendar) it.next();
|
||||
assertEquals("", start, cal, 0);
|
||||
Calendar last = null;
|
||||
int count = 1;
|
||||
while (it.hasNext()) {
|
||||
//Check this is just a date (no time component)
|
||||
assertEquals("", cal, CalendarUtils.trunc(cal, Calendar.DATE), 0);
|
||||
|
||||
last = cal;
|
||||
cal = (Calendar) it.next();
|
||||
count++;
|
||||
|
||||
//Check that this is one day more than the last date
|
||||
last.add(Calendar.DATE, 1);
|
||||
assertEquals("", last, cal, 0);
|
||||
}
|
||||
if (count % 7 != 0) {
|
||||
throw new AssertionFailedError("There were " + count + " days in this iterator");
|
||||
}
|
||||
assertEquals("", end, cal, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check that Calendar objects are close enough
|
||||
* delta is in milliseconds
|
||||
*/
|
||||
public static void assertEquals(String message, Calendar cal1, Calendar cal2, long delta) {
|
||||
if (Math.abs(cal1.getTime().getTime() - cal2.getTime().getTime()) > delta) {
|
||||
throw new AssertionFailedError(
|
||||
message + " expected " + cal1.getTime() + " but got " + cal2.getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution, if
|
||||
* any, must include the following acknowlegement:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowlegement may appear in the software itself,
|
||||
* if and wherever such third-party acknowlegements normally appear.
|
||||
*
|
||||
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
|
||||
* Foundation" must not be used to endorse or promote products derived
|
||||
* from this software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache"
|
||||
* nor may "Apache" appear in their names without prior written
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
package org.apache.commons.lang.time;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
/**
|
||||
* TestCase for DateFormatUtils.
|
||||
*
|
||||
* @author Apache Ant - DateUtilsTest
|
||||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
|
||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public class DateFormatUtilsTest extends TestCase {
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestRunner.run(suite());
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite(DateFormatUtilsTest.class);
|
||||
suite.setName("DateFormatUtils Tests");
|
||||
return suite;
|
||||
}
|
||||
|
||||
public DateFormatUtilsTest(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public void testDateTimeISO(){
|
||||
TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
|
||||
Calendar cal = Calendar.getInstance(timeZone);
|
||||
cal.set(2002,1,23,9,11,12);
|
||||
String text = DateFormatUtils.format(cal.getTime(),
|
||||
DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("2002-02-23T09:11:12", text);
|
||||
text = DateFormatUtils.format(cal.getTime().getTime(),
|
||||
DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("2002-02-23T09:11:12", text);
|
||||
text = DateFormatUtils.ISO_DATETIME_FORMAT.format(cal);
|
||||
assertEquals("2002-02-23T09:11:12", text);
|
||||
|
||||
text = DateFormatUtils.format(cal.getTime(),
|
||||
DateFormatUtils.ISO_DATETIME_TIMEZONE_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("2002-02-23T09:11:12-03:00", text);
|
||||
text = DateFormatUtils.format(cal.getTime().getTime(),
|
||||
DateFormatUtils.ISO_DATETIME_TIMEZONE_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("2002-02-23T09:11:12-03:00", text);
|
||||
text = DateFormatUtils.ISO_DATETIME_TIMEZONE_FORMAT.format(cal);
|
||||
assertEquals("2002-02-23T09:11:12-03:00", text);
|
||||
}
|
||||
|
||||
public void testDateISO(){
|
||||
TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
|
||||
Calendar cal = Calendar.getInstance(timeZone);
|
||||
cal.set(2002,1,23,10,11,12);
|
||||
String text = DateFormatUtils.format(cal.getTime(),
|
||||
DateFormatUtils.ISO_DATE_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("2002-02-23", text);
|
||||
text = DateFormatUtils.format(cal.getTime().getTime(),
|
||||
DateFormatUtils.ISO_DATE_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("2002-02-23", text);
|
||||
text = DateFormatUtils.ISO_DATE_FORMAT.format(cal);
|
||||
assertEquals("2002-02-23", text);
|
||||
|
||||
text = DateFormatUtils.format(cal.getTime(),
|
||||
DateFormatUtils.ISO_DATE_TIMEZONE_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("2002-02-23-03:00", text);
|
||||
text = DateFormatUtils.format(cal.getTime().getTime(),
|
||||
DateFormatUtils.ISO_DATE_TIMEZONE_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("2002-02-23-03:00", text);
|
||||
text = DateFormatUtils.ISO_DATE_TIMEZONE_FORMAT.format(cal);
|
||||
assertEquals("2002-02-23-03:00", text);
|
||||
}
|
||||
|
||||
public void testTimeISO(){
|
||||
TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
|
||||
Calendar cal = Calendar.getInstance(timeZone);
|
||||
cal.set(2002,1,23,10,11,12);
|
||||
String text = DateFormatUtils.format(cal.getTime(),
|
||||
DateFormatUtils.ISO_TIME_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("T10:11:12", text);
|
||||
text = DateFormatUtils.format(cal.getTime().getTime(),
|
||||
DateFormatUtils.ISO_TIME_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("T10:11:12", text);
|
||||
text = DateFormatUtils.ISO_TIME_FORMAT.format(cal);
|
||||
assertEquals("T10:11:12", text);
|
||||
|
||||
text = DateFormatUtils.format(cal.getTime(),
|
||||
DateFormatUtils.ISO_TIME_TIMEZONE_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("T10:11:12-03:00", text);
|
||||
text = DateFormatUtils.format(cal.getTime().getTime(),
|
||||
DateFormatUtils.ISO_TIME_TIMEZONE_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("T10:11:12-03:00", text);
|
||||
text = DateFormatUtils.ISO_TIME_TIMEZONE_FORMAT.format(cal);
|
||||
assertEquals("T10:11:12-03:00", text);
|
||||
}
|
||||
|
||||
public void testTimeNoTISO(){
|
||||
TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
|
||||
Calendar cal = Calendar.getInstance(timeZone);
|
||||
cal.set(2002,1,23,10,11,12);
|
||||
String text = DateFormatUtils.format(cal.getTime(),
|
||||
DateFormatUtils.ISO_TIME_NO_T_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("10:11:12", text);
|
||||
text = DateFormatUtils.format(cal.getTime().getTime(),
|
||||
DateFormatUtils.ISO_TIME_NO_T_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("10:11:12", text);
|
||||
text = DateFormatUtils.ISO_TIME_NO_T_FORMAT.format(cal);
|
||||
assertEquals("10:11:12", text);
|
||||
|
||||
text = DateFormatUtils.format(cal.getTime(),
|
||||
DateFormatUtils.ISO_TIME_NO_T_TIMEZONE_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("10:11:12-03:00", text);
|
||||
text = DateFormatUtils.format(cal.getTime().getTime(),
|
||||
DateFormatUtils.ISO_TIME_NO_T_TIMEZONE_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("10:11:12-03:00", text);
|
||||
text = DateFormatUtils.ISO_TIME_NO_T_TIMEZONE_FORMAT.format(cal);
|
||||
assertEquals("10:11:12-03:00", text);
|
||||
}
|
||||
|
||||
public void testSMTP(){
|
||||
TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
|
||||
Calendar cal = Calendar.getInstance(timeZone);
|
||||
cal.set(2003,5,8,10,11,12);
|
||||
String text = DateFormatUtils.format(cal.getTime(),
|
||||
DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text);
|
||||
text = DateFormatUtils.format(cal.getTime().getTime(),
|
||||
DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), timeZone);
|
||||
assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text);
|
||||
text = DateFormatUtils.SMTP_DATETIME_FORMAT.format(cal);
|
||||
assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text);
|
||||
|
||||
// format UTC
|
||||
text = DateFormatUtils.formatUTC(cal.getTime().getTime(),
|
||||
DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern());
|
||||
assertEquals("Sun, 08 Jun 2003 13:11:12 +0000", text);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002 The Apache Software Foundation. All rights
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -23,14 +23,14 @@
|
|||
* Alternately, this acknowlegement may appear in the software itself,
|
||||
* if and wherever such third-party acknowlegements normally appear.
|
||||
*
|
||||
* 4. The names "The Jakarta Project", "Ant", and "Apache Software
|
||||
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
|
||||
* Foundation" must not be used to endorse or promote products derived
|
||||
* from this software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache"
|
||||
* nor may "Apache" appear in their names without prior written
|
||||
* permission of the Apache Group.
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
|
@ -53,22 +53,32 @@
|
|||
*/
|
||||
package org.apache.commons.lang.time;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
/**
|
||||
* TestCase for DateUtils. [Relies heavily on code taken from the
|
||||
* DateUtilsTest class of the jakarata-ant project.]
|
||||
* Unit tests {@link org.apache.commons.lang.CalendarUtils}.
|
||||
*
|
||||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
|
||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
|
||||
* @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
|
||||
*/
|
||||
public class DateUtilsTest extends TestCase {
|
||||
DateFormat dateParser = null;
|
||||
DateFormat dateTimeParser = null;
|
||||
Date date1 = null;
|
||||
Date date2 = null;
|
||||
|
||||
public DateUtilsTest(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestRunner.run(suite());
|
||||
|
@ -76,69 +86,300 @@ public class DateUtilsTest extends TestCase {
|
|||
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite(DateUtilsTest.class);
|
||||
suite.setName("DateUtils Tests");
|
||||
suite.setName("CalendarUtilsTest Tests");
|
||||
return suite;
|
||||
}
|
||||
|
||||
public DateUtilsTest(String s) {
|
||||
super(s);
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
dateParser = new SimpleDateFormat("MMM dd, yyyy");
|
||||
dateTimeParser = new SimpleDateFormat("MMM dd, yyyy H:mm:ss.SSS");
|
||||
|
||||
date1 = dateTimeParser.parse("February 12, 2002 12:34:56.789");
|
||||
date2 = dateTimeParser.parse("November 18, 2001 1:23:11.321");
|
||||
}
|
||||
|
||||
public void testElapsedTime(){
|
||||
String text = DateUtils.formatElapsedTime(50*1000);
|
||||
assertEquals("50 seconds", text);
|
||||
text = DateUtils.formatElapsedTime(65*1000);
|
||||
assertEquals("1 minute 5 seconds", text);
|
||||
text = DateUtils.formatElapsedTime(120*1000);
|
||||
assertEquals("2 minutes 0 seconds", text);
|
||||
text = DateUtils.formatElapsedTime(121*1000);
|
||||
assertEquals("2 minutes 1 second", text);
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testDateTimeISO(){
|
||||
TimeZone timeZone = TimeZone.getTimeZone("GMT+1");
|
||||
Calendar cal = Calendar.getInstance(timeZone);
|
||||
cal.set(2002,1,23,10,11,12);
|
||||
String text = DateUtils.format(cal.getTime(),
|
||||
DateUtils.ISO8601_DATETIME_PATTERN);
|
||||
assertEquals("2002-02-23T09:11:12", text);
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Tests various values with the round method
|
||||
*/
|
||||
public void testRound() throws Exception {
|
||||
assertEquals("round year-1 failed",
|
||||
dateParser.parse("January 1, 2002"),
|
||||
DateUtils.round(date1, Calendar.YEAR));
|
||||
assertEquals("round year-2 failed",
|
||||
dateParser.parse("January 1, 2002"),
|
||||
DateUtils.round(date2, Calendar.YEAR));
|
||||
assertEquals("round month-1 failed",
|
||||
dateParser.parse("February 1, 2002"),
|
||||
DateUtils.round(date1, Calendar.MONTH));
|
||||
assertEquals("round month-2 failed",
|
||||
dateParser.parse("December 1, 2001"),
|
||||
DateUtils.round(date2, Calendar.MONTH));
|
||||
assertEquals("round semimonth-1 failed",
|
||||
dateParser.parse("February 16, 2002"),
|
||||
DateUtils.round(date1, DateUtils.SEMI_MONTH));
|
||||
assertEquals("round semimonth-2 failed",
|
||||
dateParser.parse("November 16, 2001"),
|
||||
DateUtils.round(date2, DateUtils.SEMI_MONTH));
|
||||
assertEquals("round date-1 failed",
|
||||
dateParser.parse("February 13, 2002"),
|
||||
DateUtils.round(date1, Calendar.DATE));
|
||||
assertEquals("round date-2 failed",
|
||||
dateParser.parse("November 18, 2001"),
|
||||
DateUtils.round(date2, Calendar.DATE));
|
||||
assertEquals("round hour-1 failed",
|
||||
dateTimeParser.parse("February 12, 2002 13:00:00.000"),
|
||||
DateUtils.round(date1, Calendar.HOUR));
|
||||
assertEquals("round hour-2 failed",
|
||||
dateTimeParser.parse("November 18, 2001 1:00:00.000"),
|
||||
DateUtils.round(date2, Calendar.HOUR));
|
||||
assertEquals("round minute-1 failed",
|
||||
dateTimeParser.parse("February 12, 2002 12:35:00.000"),
|
||||
DateUtils.round(date1, Calendar.MINUTE));
|
||||
assertEquals("round minute-2 failed",
|
||||
dateTimeParser.parse("November 18, 2001 1:23:00.000"),
|
||||
DateUtils.round(date2, Calendar.MINUTE));
|
||||
assertEquals("round second-1 failed",
|
||||
dateTimeParser.parse("February 12, 2002 12:34:57.000"),
|
||||
DateUtils.round(date1, Calendar.SECOND));
|
||||
assertEquals("round second-2 failed",
|
||||
dateTimeParser.parse("November 18, 2001 1:23:11.000"),
|
||||
DateUtils.round(date2, Calendar.SECOND));
|
||||
}
|
||||
|
||||
public void testDateISO(){
|
||||
TimeZone timeZone = TimeZone.getTimeZone("GMT");
|
||||
Calendar cal = Calendar.getInstance(timeZone);
|
||||
cal.set(2002,1,23);
|
||||
String text = DateUtils.format(cal.getTime(),
|
||||
DateUtils.ISO8601_DATE_PATTERN);
|
||||
assertEquals("2002-02-23", text);
|
||||
/**
|
||||
* Tests various values with the trunc method
|
||||
*/
|
||||
public void testTrunc() throws Exception {
|
||||
assertEquals("trunc year-1 failed",
|
||||
dateParser.parse("January 1, 2002"),
|
||||
DateUtils.trunc(date1, Calendar.YEAR));
|
||||
assertEquals("trunc year-2 failed",
|
||||
dateParser.parse("January 1, 2001"),
|
||||
DateUtils.trunc(date2, Calendar.YEAR));
|
||||
assertEquals("trunc month-1 failed",
|
||||
dateParser.parse("February 1, 2002"),
|
||||
DateUtils.trunc(date1, Calendar.MONTH));
|
||||
assertEquals("trunc month-2 failed",
|
||||
dateParser.parse("November 1, 2001"),
|
||||
DateUtils.trunc(date2, Calendar.MONTH));
|
||||
assertEquals("trunc semimonth-1 failed",
|
||||
dateParser.parse("February 1, 2002"),
|
||||
DateUtils.trunc(date1, DateUtils.SEMI_MONTH));
|
||||
assertEquals("trunc semimonth-2 failed",
|
||||
dateParser.parse("November 16, 2001"),
|
||||
DateUtils.trunc(date2, DateUtils.SEMI_MONTH));
|
||||
assertEquals("trunc date-1 failed",
|
||||
dateParser.parse("February 12, 2002"),
|
||||
DateUtils.trunc(date1, Calendar.DATE));
|
||||
assertEquals("trunc date-2 failed",
|
||||
dateParser.parse("November 18, 2001"),
|
||||
DateUtils.trunc(date2, Calendar.DATE));
|
||||
assertEquals("trunc hour-1 failed",
|
||||
dateTimeParser.parse("February 12, 2002 12:00:00.000"),
|
||||
DateUtils.trunc(date1, Calendar.HOUR));
|
||||
assertEquals("trunc hour-2 failed",
|
||||
dateTimeParser.parse("November 18, 2001 1:00:00.000"),
|
||||
DateUtils.trunc(date2, Calendar.HOUR));
|
||||
assertEquals("trunc minute-1 failed",
|
||||
dateTimeParser.parse("February 12, 2002 12:34:00.000"),
|
||||
DateUtils.trunc(date1, Calendar.MINUTE));
|
||||
assertEquals("trunc minute-2 failed",
|
||||
dateTimeParser.parse("November 18, 2001 1:23:00.000"),
|
||||
DateUtils.trunc(date2, Calendar.MINUTE));
|
||||
assertEquals("trunc second-1 failed",
|
||||
dateTimeParser.parse("February 12, 2002 12:34:56.000"),
|
||||
DateUtils.trunc(date1, Calendar.SECOND));
|
||||
assertEquals("trunc second-2 failed",
|
||||
dateTimeParser.parse("November 18, 2001 1:23:11.000"),
|
||||
DateUtils.trunc(date2, Calendar.SECOND));
|
||||
|
||||
}
|
||||
|
||||
public void testTimeISODate(){
|
||||
// make sure that elapsed time in set via date works
|
||||
TimeZone timeZone = TimeZone.getTimeZone("GMT+1");
|
||||
Calendar cal = Calendar.getInstance(timeZone);
|
||||
cal.set(2002,1,23, 21, 11, 12);
|
||||
String text = DateUtils.format(cal.getTime(),
|
||||
DateUtils.ISO8601_TIME_PATTERN);
|
||||
assertEquals("20:11:12", text);
|
||||
/**
|
||||
* Tests the parse method, which is supposed to handle various strings
|
||||
* as flexibly as CVS supports.
|
||||
*/
|
||||
public void testParse() throws Exception {
|
||||
//This is difficult to test since the "now" used in the
|
||||
// parse function cannot be controlled. We could possibly control
|
||||
// it by trying before and after and making sure the value we expect
|
||||
// is between the two values calculated.
|
||||
//For now we're just using the custom assertEquals that takes a delta
|
||||
|
||||
Calendar now = null;
|
||||
|
||||
now = Calendar.getInstance();
|
||||
now.add(Calendar.MINUTE, -1);
|
||||
assertEquals("parse 1 minute ago",
|
||||
now, DateUtils.parse("1 minute ago"), 50);
|
||||
now = Calendar.getInstance();
|
||||
now.add(Calendar.MINUTE, -8);
|
||||
assertEquals("parse 8 minutes ago",
|
||||
now, DateUtils.parse("8 minutes ago"), 50);
|
||||
|
||||
now = Calendar.getInstance();
|
||||
now.add(Calendar.DATE, -1);
|
||||
assertEquals("parse yesterday",
|
||||
now, DateUtils.parse("yesterday"), 50);
|
||||
|
||||
now = Calendar.getInstance();
|
||||
now.add(Calendar.DATE, 1);
|
||||
assertEquals("parse tomorrow",
|
||||
now, DateUtils.parse("tomorrow"), 50);
|
||||
|
||||
now = Calendar.getInstance();
|
||||
//Sunday would be 1, Saturday would be 7, so we walk back up to 6 days.
|
||||
if (now.get(Calendar.DAY_OF_WEEK) == 1) {
|
||||
//If Sunday already, we go back a full week
|
||||
now.add(Calendar.DATE, -7);
|
||||
} else {
|
||||
now.add(Calendar.DATE, 1 - now.get(Calendar.DAY_OF_WEEK));
|
||||
}
|
||||
assertEquals("parse last Sunday",
|
||||
now, DateUtils.parse("last Sunday"), 50);
|
||||
|
||||
now = Calendar.getInstance();
|
||||
now.add(Calendar.DATE, -7);
|
||||
assertEquals("parse last week",
|
||||
now, DateUtils.parse("last week"), 50);
|
||||
|
||||
now = Calendar.getInstance();
|
||||
//January would be 0, December would be 11, so we walk back up to 11 months
|
||||
if (now.get(Calendar.MONTH) == 0) {
|
||||
//If January already, we go back a full year
|
||||
now.add(Calendar.MONTH, -12);
|
||||
} else {
|
||||
now.add(Calendar.MONTH, 0 - now.get(Calendar.MONTH));
|
||||
}
|
||||
assertEquals("parse last January",
|
||||
now, DateUtils.parse("last January"), 50);
|
||||
}
|
||||
|
||||
public void testTimeISO(){
|
||||
// make sure that elapsed time in ms works
|
||||
long ms = (20*3600 + 11*60 + 12)*1000;
|
||||
String text = DateUtils.format(ms,
|
||||
DateUtils.ISO8601_TIME_PATTERN);
|
||||
assertEquals("20:11:12", text);
|
||||
/**
|
||||
* Tests the calendar iterator for week ranges
|
||||
*/
|
||||
public void testWeekIterator() throws Exception {
|
||||
Calendar now = Calendar.getInstance();
|
||||
for (int i = 0; i< 7; i++) {
|
||||
Calendar today = DateUtils.trunc(now, Calendar.DATE);
|
||||
Calendar sunday = DateUtils.trunc(now, Calendar.DATE);
|
||||
sunday.add(Calendar.DATE, 1 - sunday.get(Calendar.DAY_OF_WEEK));
|
||||
Calendar monday = DateUtils.trunc(now, Calendar.DATE);
|
||||
if (monday.get(Calendar.DAY_OF_WEEK) == 1) {
|
||||
//This is sunday... roll back 6 days
|
||||
monday.add(Calendar.DATE, -6);
|
||||
} else {
|
||||
monday.add(Calendar.DATE, 2 - monday.get(Calendar.DAY_OF_WEEK));
|
||||
}
|
||||
Calendar centered = DateUtils.trunc(now, Calendar.DATE);
|
||||
centered.add(Calendar.DATE, -3);
|
||||
|
||||
Iterator it = DateUtils.getCalendarIterator(now, DateUtils.RANGE_WEEK_SUNDAY);
|
||||
assertWeekIterator(it, sunday);
|
||||
it = DateUtils.getCalendarIterator(now, DateUtils.RANGE_WEEK_MONDAY);
|
||||
assertWeekIterator(it, monday);
|
||||
it = DateUtils.getCalendarIterator(now, DateUtils.RANGE_WEEK_RELATIVE);
|
||||
assertWeekIterator(it, today);
|
||||
it = DateUtils.getCalendarIterator(now, DateUtils.RANGE_WEEK_CENTER);
|
||||
assertWeekIterator(it, centered);
|
||||
now.add(Calendar.DATE,1);
|
||||
}
|
||||
}
|
||||
|
||||
public void testPhaseOfMoon() {
|
||||
TimeZone timeZone = TimeZone.getTimeZone("GMT");
|
||||
Calendar cal = Calendar.getInstance(timeZone);
|
||||
// should be full moon
|
||||
cal.set(2002, 2, 27);
|
||||
assertEquals(4, DateUtils.getPhaseOfMoon(cal));
|
||||
// should be new moon
|
||||
cal.set(2002, 2, 12);
|
||||
assertEquals(0, DateUtils.getPhaseOfMoon(cal));
|
||||
/**
|
||||
* Tests the calendar iterator for month-based ranges
|
||||
*/
|
||||
public void testMonthIterator() throws Exception {
|
||||
Iterator it = DateUtils.getCalendarIterator(date1, DateUtils.RANGE_MONTH_SUNDAY);
|
||||
assertWeekIterator(it,
|
||||
dateParser.parse("January 27, 2002"),
|
||||
dateParser.parse("March 2, 2002"));
|
||||
|
||||
it = DateUtils.getCalendarIterator(date1, DateUtils.RANGE_MONTH_MONDAY);
|
||||
assertWeekIterator(it,
|
||||
dateParser.parse("January 28, 2002"),
|
||||
dateParser.parse("March 3, 2002"));
|
||||
|
||||
it = DateUtils.getCalendarIterator(date2, DateUtils.RANGE_MONTH_SUNDAY);
|
||||
assertWeekIterator(it,
|
||||
dateParser.parse("October 28, 2001"),
|
||||
dateParser.parse("December 1, 2001"));
|
||||
|
||||
it = DateUtils.getCalendarIterator(date2, DateUtils.RANGE_MONTH_MONDAY);
|
||||
assertWeekIterator(it,
|
||||
dateParser.parse("October 29, 2001"),
|
||||
dateParser.parse("December 2, 2001"));
|
||||
}
|
||||
|
||||
/**
|
||||
* This checks that this is a 7 element iterator of Calendar objects
|
||||
* that are dates (no time), and exactly 1 day spaced after each other.
|
||||
*/
|
||||
private static void assertWeekIterator(Iterator it, Calendar start) {
|
||||
Calendar end = (Calendar) start.clone();
|
||||
end.add(Calendar.DATE, 6);
|
||||
|
||||
assertWeekIterator(it, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for when working with Date objects
|
||||
*/
|
||||
private static void assertWeekIterator(Iterator it, Date start, Date end) {
|
||||
Calendar calStart = Calendar.getInstance();
|
||||
calStart.setTime(start);
|
||||
Calendar calEnd = Calendar.getInstance();
|
||||
calEnd.setTime(end);
|
||||
|
||||
assertWeekIterator(it, calStart, calEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* This checks that this is a 7 divisble iterator of Calendar objects
|
||||
* that are dates (no time), and exactly 1 day spaced after each other
|
||||
* (in addition to the proper start and stop dates)
|
||||
*/
|
||||
private static void assertWeekIterator(Iterator it, Calendar start, Calendar end) {
|
||||
Calendar cal = (Calendar) it.next();
|
||||
assertEquals("", start, cal, 0);
|
||||
Calendar last = null;
|
||||
int count = 1;
|
||||
while (it.hasNext()) {
|
||||
//Check this is just a date (no time component)
|
||||
assertEquals("", cal, DateUtils.trunc(cal, Calendar.DATE), 0);
|
||||
|
||||
last = cal;
|
||||
cal = (Calendar) it.next();
|
||||
count++;
|
||||
|
||||
//Check that this is one day more than the last date
|
||||
last.add(Calendar.DATE, 1);
|
||||
assertEquals("", last, cal, 0);
|
||||
}
|
||||
if (count % 7 != 0) {
|
||||
throw new AssertionFailedError("There were " + count + " days in this iterator");
|
||||
}
|
||||
assertEquals("", end, cal, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check that Calendar objects are close enough
|
||||
* delta is in milliseconds
|
||||
*/
|
||||
public static void assertEquals(String message, Calendar cal1, Calendar cal2, long delta) {
|
||||
if (Math.abs(cal1.getTime().getTime() - cal2.getTime().getTime()) > delta) {
|
||||
throw new AssertionFailedError(
|
||||
message + " expected " + cal1.getTime() + " but got " + cal2.getTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution, if
|
||||
* any, must include the following acknowlegement:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.apache.org/)."
|
||||
* Alternately, this acknowlegement may appear in the software itself,
|
||||
* if and wherever such third-party acknowlegements normally appear.
|
||||
*
|
||||
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
|
||||
* Foundation" must not be used to endorse or promote products derived
|
||||
* from this software without prior written permission. For written
|
||||
* permission, please contact apache@apache.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache"
|
||||
* nor may "Apache" appear in their names without prior written
|
||||
* permission of the Apache Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.apache.org/>.
|
||||
*/
|
||||
package org.apache.commons.lang.time;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
/**
|
||||
* TestCase for DurationFormatUtils.
|
||||
*
|
||||
* @author Apache Ant - DateUtilsTest
|
||||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
|
||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
|
||||
* @author Stephen Colebourne
|
||||
*/
|
||||
public class DurationFormatUtilsTest extends TestCase {
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestRunner.run(suite());
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite(DurationFormatUtilsTest.class);
|
||||
suite.setName("DurationFormatUtils Tests");
|
||||
return suite;
|
||||
}
|
||||
|
||||
public DurationFormatUtilsTest(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public void testFormatWords(){
|
||||
String text = null;
|
||||
|
||||
text = DurationFormatUtils.formatWords(50*1000, true, false);
|
||||
assertEquals("50 seconds", text);
|
||||
text = DurationFormatUtils.formatWords(65*1000, true, false);
|
||||
assertEquals("1 minute 5 seconds", text);
|
||||
text = DurationFormatUtils.formatWords(120*1000, true, false);
|
||||
assertEquals("2 minutes 0 seconds", text);
|
||||
text = DurationFormatUtils.formatWords(121*1000, true, false);
|
||||
assertEquals("2 minutes 1 second", text);
|
||||
text = DurationFormatUtils.formatWords(72*60*1000, true, false);
|
||||
assertEquals("1 hour 12 minutes 0 seconds", text);
|
||||
|
||||
text = DurationFormatUtils.formatWords(50*1000, true, true);
|
||||
assertEquals("50 seconds", text);
|
||||
text = DurationFormatUtils.formatWords(65*1000, true, true);
|
||||
assertEquals("1 minute 5 seconds", text);
|
||||
text = DurationFormatUtils.formatWords(120*1000, true, true);
|
||||
assertEquals("2 minutes", text);
|
||||
text = DurationFormatUtils.formatWords(121*1000, true, true);
|
||||
assertEquals("2 minutes 1 second", text);
|
||||
text = DurationFormatUtils.formatWords(72*60*1000, true, true);
|
||||
assertEquals("1 hour 12 minutes", text);
|
||||
|
||||
text = DurationFormatUtils.formatWords(50*1000, false, true);
|
||||
assertEquals("0 days 0 hours 0 minutes 50 seconds", text);
|
||||
text = DurationFormatUtils.formatWords(65*1000, false, true);
|
||||
assertEquals("0 days 0 hours 1 minute 5 seconds", text);
|
||||
text = DurationFormatUtils.formatWords(120*1000, false, true);
|
||||
assertEquals("0 days 0 hours 2 minutes", text);
|
||||
text = DurationFormatUtils.formatWords(121*1000, false, true);
|
||||
assertEquals("0 days 0 hours 2 minutes 1 second", text);
|
||||
text = DurationFormatUtils.formatWords(72*60*1000, false, true);
|
||||
assertEquals("0 days 1 hour 12 minutes", text);
|
||||
|
||||
text = DurationFormatUtils.formatWords(50*1000, false, false);
|
||||
assertEquals("0 days 0 hours 0 minutes 50 seconds", text);
|
||||
text = DurationFormatUtils.formatWords(65*1000, false, false);
|
||||
assertEquals("0 days 0 hours 1 minute 5 seconds", text);
|
||||
text = DurationFormatUtils.formatWords(120*1000, false, false);
|
||||
assertEquals("0 days 0 hours 2 minutes 0 seconds", text);
|
||||
text = DurationFormatUtils.formatWords(121*1000, false, false);
|
||||
assertEquals("0 days 0 hours 2 minutes 1 second", text);
|
||||
text = DurationFormatUtils.formatWords(72*60*1000, false, false);
|
||||
assertEquals("0 days 1 hour 12 minutes 0 seconds", text);
|
||||
}
|
||||
|
||||
public void testFormatISOStyle(){
|
||||
long time = 0;
|
||||
assertEquals("0:00:00.000", DurationFormatUtils.formatISO(time));
|
||||
|
||||
time = 1;
|
||||
assertEquals("0:00:00.001", DurationFormatUtils.formatISO(time));
|
||||
|
||||
time = 15;
|
||||
assertEquals("0:00:00.015", DurationFormatUtils.formatISO(time));
|
||||
|
||||
time = 165;
|
||||
assertEquals("0:00:00.165", DurationFormatUtils.formatISO(time));
|
||||
|
||||
time = 1675;
|
||||
assertEquals("0:00:01.675", DurationFormatUtils.formatISO(time));
|
||||
|
||||
time = 13465;
|
||||
assertEquals("0:00:13.465", DurationFormatUtils.formatISO(time));
|
||||
|
||||
time = 72789;
|
||||
assertEquals("0:01:12.789", DurationFormatUtils.formatISO(time));
|
||||
|
||||
time = 12789 + 32 * 60000;
|
||||
assertEquals("0:32:12.789", DurationFormatUtils.formatISO(time));
|
||||
|
||||
time = 12789 + 62 * 60000;
|
||||
assertEquals("1:02:12.789", DurationFormatUtils.formatISO(time));
|
||||
}
|
||||
|
||||
}
|
|
@ -54,6 +54,8 @@
|
|||
package org.apache.commons.lang.time;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
|
@ -67,7 +69,7 @@ import junit.textui.TestRunner;
|
|||
*
|
||||
* @author Sean Schofield
|
||||
* @since 2.0
|
||||
* @version $Id: FastDateFormatTest.java,v 1.3 2003/05/21 23:41:21 scolebourne Exp $
|
||||
* @version $Id: FastDateFormatTest.java,v 1.4 2003/06/08 23:14:23 scolebourne Exp $
|
||||
*/
|
||||
public class FastDateFormatTest extends TestCase {
|
||||
|
||||
|
@ -106,9 +108,15 @@ public class FastDateFormatTest extends TestCase {
|
|||
public void test_getInstance_String() {
|
||||
FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy");
|
||||
FastDateFormat format2 = FastDateFormat.getInstance("MM-DD-yyyy");
|
||||
FastDateFormat format3 = FastDateFormat.getInstance("MM-DD-yyyy");
|
||||
|
||||
assertTrue(format1 != format2); // -- junit 3.8 version -- assertFalse(format1 == format2);
|
||||
assertSame(format1, FastDateFormat.getInstance("MM/DD/yyyy"));
|
||||
assertSame(format2, format3);
|
||||
assertEquals("MM/DD/yyyy", format1.getPattern());
|
||||
assertEquals(TimeZone.getDefault(), format1.getTimeZone());
|
||||
assertEquals(TimeZone.getDefault(), format2.getTimeZone());
|
||||
assertEquals(false, format1.getTimeZoneOverridesCalendar());
|
||||
assertEquals(false, format2.getTimeZoneOverridesCalendar());
|
||||
}
|
||||
|
||||
public void test_getInstance_String_TimeZone() {
|
||||
|
@ -124,12 +132,16 @@ public class FastDateFormatTest extends TestCase {
|
|||
FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
|
||||
FastDateFormat format4 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
|
||||
FastDateFormat format5 = FastDateFormat.getInstance("MM-DD-yyyy", TimeZone.getDefault());
|
||||
FastDateFormat format6 = FastDateFormat.getInstance("MM-DD-yyyy");
|
||||
|
||||
assertTrue(format1 != format2); // -- junit 3.8 version -- assertFalse(format1 == format2);
|
||||
assertTrue(format1.getTimeZone().equals(TimeZone.getTimeZone("Atlantic/Reykjavik")));
|
||||
assertNull(format2.getTimeZone());
|
||||
assertEquals(TimeZone.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
|
||||
assertEquals(true, format1.getTimeZoneOverridesCalendar());
|
||||
assertEquals(TimeZone.getDefault(), format2.getTimeZone());
|
||||
assertEquals(false, format2.getTimeZoneOverridesCalendar());
|
||||
assertSame(format3, format4);
|
||||
assertTrue(format3 != format5); // -- junit 3.8 version -- assertFalse(format3 == format5);
|
||||
assertTrue(format4 != format6); // -- junit 3.8 version -- assertFalse(format3 == format5);
|
||||
|
||||
} finally {
|
||||
Locale.setDefault(realDefaultLocale);
|
||||
|
@ -168,10 +180,66 @@ public class FastDateFormatTest extends TestCase {
|
|||
TimeZone.getDefault(), Locale.GERMANY);
|
||||
|
||||
assertTrue(format1 != format2); // -- junit 3.8 version -- assertNotSame(format1, format2);
|
||||
assertEquals(format1.getTimeZone(), TimeZone.getTimeZone("Atlantic/Reykjavik"));
|
||||
assertNull(format2.getTimeZone());
|
||||
assertEquals(format3.getTimeZone(), TimeZone.getDefault());
|
||||
assertEquals(format3.getTimeZone(), TimeZone.getTimeZone("America/New_York"));
|
||||
assertEquals(TimeZone.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
|
||||
assertEquals(TimeZone.getDefault(), format2.getTimeZone());
|
||||
assertEquals(TimeZone.getDefault(), format3.getTimeZone());
|
||||
assertEquals(true, format1.getTimeZoneOverridesCalendar());
|
||||
assertEquals(false, format2.getTimeZoneOverridesCalendar());
|
||||
assertEquals(true, format3.getTimeZoneOverridesCalendar());
|
||||
assertEquals(Locale.GERMANY, format1.getLocale());
|
||||
assertEquals(Locale.GERMANY, format2.getLocale());
|
||||
assertEquals(Locale.GERMANY, format3.getLocale());
|
||||
|
||||
} finally {
|
||||
Locale.setDefault(realDefaultLocale);
|
||||
TimeZone.setDefault(realDefaultZone);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFormat() {
|
||||
Locale realDefaultLocale = Locale.getDefault();
|
||||
TimeZone realDefaultZone = TimeZone.getDefault();
|
||||
try {
|
||||
Locale.setDefault(Locale.US);
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
|
||||
FastDateFormat fdf = null;
|
||||
SimpleDateFormat sdf = null;
|
||||
|
||||
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();
|
||||
|
||||
fdf = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
|
||||
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-07-10T09:00:00", fdf.format(date2));
|
||||
assertEquals("2003-07-10T09:00:00", fdf.format(cal2));
|
||||
|
||||
fdf = FastDateFormat.getInstance("Z");
|
||||
assertEquals("-0500", fdf.format(date1));
|
||||
assertEquals("-0500", fdf.format(cal1));
|
||||
|
||||
fdf = FastDateFormat.getInstance("Z");
|
||||
assertEquals("-0400", fdf.format(date2));
|
||||
assertEquals("-0400", fdf.format(cal2));
|
||||
|
||||
fdf = FastDateFormat.getInstance("ZZ");
|
||||
assertEquals("-05:00", fdf.format(date1));
|
||||
assertEquals("-05:00", fdf.format(cal1));
|
||||
|
||||
fdf = FastDateFormat.getInstance("ZZ");
|
||||
assertEquals("-04:00", fdf.format(date2));
|
||||
assertEquals("-04:00", fdf.format(cal2));
|
||||
|
||||
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);
|
||||
assertEquals(sdf.format(date1), fdf.format(date1));
|
||||
assertEquals(sdf.format(date2), fdf.format(date2));
|
||||
|
||||
} finally {
|
||||
Locale.setDefault(realDefaultLocale);
|
||||
|
|
|
@ -62,7 +62,7 @@ import junit.textui.TestRunner;
|
|||
* TestCase for StopWatch.
|
||||
*
|
||||
* @author Stephen Colebourne
|
||||
* @version $Id: StopWatchTest.java,v 1.2 2003/05/21 23:40:24 scolebourne Exp $
|
||||
* @version $Id: StopWatchTest.java,v 1.3 2003/06/08 23:14:23 scolebourne Exp $
|
||||
*/
|
||||
public class StopWatchTest extends TestCase {
|
||||
|
||||
|
@ -80,35 +80,6 @@ public class StopWatchTest extends TestCase {
|
|||
super(s);
|
||||
}
|
||||
|
||||
public void testToString(){
|
||||
long time = 0;
|
||||
assertEquals("0:00:00.000", StopWatch.toString(time));
|
||||
|
||||
time = 1;
|
||||
assertEquals("0:00:00.001", StopWatch.toString(time));
|
||||
|
||||
time = 15;
|
||||
assertEquals("0:00:00.015", StopWatch.toString(time));
|
||||
|
||||
time = 165;
|
||||
assertEquals("0:00:00.165", StopWatch.toString(time));
|
||||
|
||||
time = 1675;
|
||||
assertEquals("0:00:01.675", StopWatch.toString(time));
|
||||
|
||||
time = 13465;
|
||||
assertEquals("0:00:13.465", StopWatch.toString(time));
|
||||
|
||||
time = 72789;
|
||||
assertEquals("0:01:12.789", StopWatch.toString(time));
|
||||
|
||||
time = 12789 + 32 * 60000;
|
||||
assertEquals("0:32:12.789", StopWatch.toString(time));
|
||||
|
||||
time = 12789 + 62 * 60000;
|
||||
assertEquals("1:02:12.789", StopWatch.toString(time));
|
||||
}
|
||||
|
||||
public void testStopWatchSimple(){
|
||||
StopWatch watch = new StopWatch();
|
||||
assertEquals(0, watch.getTime());
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* ====================================================================
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002 The Apache Software Foundation. All rights
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -57,11 +57,12 @@ import junit.framework.Test;
|
|||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
/**
|
||||
* Test suite for the Time package.
|
||||
*
|
||||
* @author Stephen Colebourne
|
||||
* @version $Id: TimeTestSuite.java,v 1.3 2003/01/10 03:55:01 bayard Exp $
|
||||
* @version $Id: TimeTestSuite.java,v 1.4 2003/06/08 23:14:23 scolebourne Exp $
|
||||
*/
|
||||
public class TimeTestSuite extends TestCase {
|
||||
|
||||
|
@ -85,8 +86,9 @@ public class TimeTestSuite extends TestCase {
|
|||
public static Test suite() {
|
||||
TestSuite suite = new TestSuite();
|
||||
suite.setName("Commons-Lang-Time Tests");
|
||||
suite.addTest(CalendarUtilsTest.suite());
|
||||
suite.addTest(DateUtilsTest.suite());
|
||||
suite.addTest(DateFormatUtilsTest.suite());
|
||||
suite.addTest(DurationFormatUtilsTest.suite());
|
||||
suite.addTest(StopWatchTest.suite());
|
||||
suite.addTest(FastDateFormatTest.suite());
|
||||
return suite;
|
||||
|
|
Loading…
Reference in New Issue