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;
|
package org.apache.commons.lang.time;
|
||||||
|
|
||||||
import java.text.ChoiceFormat;
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.MessageFormat;
|
import java.text.DateFormatSymbols;
|
||||||
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper methods to deal with date/time formatting. [Relies heavily on
|
* A suite of utilities surrounding the use of the Calendar and Date object.
|
||||||
* code taken from the DateUtils class of the jakarata-ant project.]
|
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
|
* @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
|
||||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
|
* @author Stephen Colebourne
|
||||||
* @since 2.1
|
* @since 2.0
|
||||||
* @version $Id: DateUtils.java,v 1.2 2003/02/04 22:19:33 scolebourne Exp $
|
* @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.
|
* The UTC timezone (often referred to as GMT).
|
||||||
* <tt>yyyy-MM-ddTHH:mm:ss</tt>
|
|
||||||
*/
|
*/
|
||||||
public static final String ISO8601_DATETIME_PATTERN
|
public static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("GMT");
|
||||||
= "yyyy-MM-dd'T'HH:mm:ss";
|
/**
|
||||||
|
* 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
|
public final static int SEMI_MONTH = 1001;
|
||||||
= "yyyy-MM-dd";
|
|
||||||
|
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
|
public final static int RANGE_WEEK_SUNDAY = 1;
|
||||||
= "HH:mm:ss";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format used for SMTP (and probably other) Date headers.
|
* A week range, starting on Monday.
|
||||||
*/
|
*/
|
||||||
public static final DateFormat DATE_HEADER_FORMAT
|
public final static int RANGE_WEEK_MONDAY = 2;
|
||||||
= new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ", Locale.US);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* A week range, centered around the day focused.
|
||||||
= new MessageFormat("{0}{1}");
|
*/
|
||||||
|
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"};
|
* See the other round method. Works with a Date object.
|
||||||
|
*/
|
||||||
private static final ChoiceFormat MINUTES_FORMAT =
|
public static Date round(Date val, int field) {
|
||||||
new ChoiceFormat(LIMITS, MINUTES_PART);
|
GregorianCalendar gval = new GregorianCalendar();
|
||||||
|
gval.setTime(val);
|
||||||
private static final ChoiceFormat SECONDS_FORMAT =
|
modify(gval, field, true);
|
||||||
new ChoiceFormat(LIMITS, SECONDS_PART);
|
return gval.getTime();
|
||||||
|
|
||||||
static {
|
|
||||||
MINUTE_SECONDS.setFormat(0, MINUTES_FORMAT);
|
|
||||||
MINUTE_SECONDS.setFormat(1, SECONDS_FORMAT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>DateUtils instances should NOT be constructed in standard programming.</p>
|
* Round this date, leaving the field specified as the most significant
|
||||||
*
|
* field. For example, if you had the datetime of 28 Mar 2002
|
||||||
* <p>This constructor is public to permit tools that require a JavaBean instance
|
* 13:45:01.231, if this was passed with HOUR, it would return 28 Mar
|
||||||
* to operate.</p>
|
* 2002 14:00:00.000. If this was passed with MONTH, it would return
|
||||||
|
* 1 April 2002 0:00:00.000.
|
||||||
*/
|
*/
|
||||||
public DateUtils() {
|
public static Calendar round(Calendar val, int field) {
|
||||||
}
|
Calendar rounded = (Calendar) val.clone();
|
||||||
|
modify(rounded, field, true);
|
||||||
|
return rounded;
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return a lenient date format set to GMT time zone.
|
* See the other round method. Works with an Object, trying to
|
||||||
* @param pattern the pattern used for date/time formatting.
|
* use it as either a Date or Calendar.
|
||||||
* @return the configured format for this pattern.
|
|
||||||
*/
|
*/
|
||||||
private static DateFormat createDateFormat(String pattern) {
|
public static Date round(Object val, int field) {
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
|
if (val instanceof Date) {
|
||||||
TimeZone gmt = TimeZone.getTimeZone("GMT");
|
return round((Date) val, field);
|
||||||
sdf.setTimeZone(gmt);
|
} else if (val instanceof Calendar) {
|
||||||
sdf.setLenient(true);
|
return round((Calendar) val, field).getTime();
|
||||||
return sdf;
|
} else {
|
||||||
|
throw new ClassCastException("Could not round " + val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the phase of the moon for a given date.
|
* See the other trunc method. Works with a 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
|
|
||||||
*/
|
*/
|
||||||
public static int getPhaseOfMoon(Calendar cal) {
|
public static Date trunc(Date val, int field) {
|
||||||
int dayOfTheYear = cal.get(Calendar.DAY_OF_YEAR);
|
GregorianCalendar gval = new GregorianCalendar();
|
||||||
int yearInMetonicCycle = ((cal.get(Calendar.YEAR) - 1900) % 19) + 1;
|
gval.setTime(val);
|
||||||
int epact = (11 * yearInMetonicCycle + 18) % 30;
|
modify(gval, field, false);
|
||||||
if ((epact == 25 && yearInMetonicCycle > 11) || epact == 24) {
|
return gval.getTime();
|
||||||
epact++;
|
|
||||||
}
|
|
||||||
return (((((dayOfTheYear + epact) * 6) + 11) % 177) / 22) & 7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current Date in a format suitable for a SMTP date
|
* Truncate this date, leaving the field specified as the most significant
|
||||||
* header.
|
* 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
|
||||||
* @since Ant 1.5.2
|
* 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();
|
Calendar cal = Calendar.getInstance();
|
||||||
TimeZone tz = cal.getTimeZone();
|
cal.setTime(datetime);
|
||||||
int offset = tz.getOffset(cal.get(Calendar.ERA),
|
return cal;
|
||||||
cal.get(Calendar.YEAR),
|
} catch (ParseException pe) {
|
||||||
cal.get(Calendar.MONTH),
|
//we ignore this and just keep trying
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
package org.apache.commons.lang.time;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.DateFormatSymbols;
|
import java.text.DateFormatSymbols;
|
||||||
import java.text.FieldPosition;
|
import java.text.FieldPosition;
|
||||||
|
@ -71,11 +70,18 @@ import java.util.Map;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FastDateFormat is similar to {@link java.text.SimpleDateFormat}, but
|
* FastDateFormat is a fast and thread-safe version of {@link java.text.SimpleDateFormat}.
|
||||||
* faster and thread-safe.
|
|
||||||
* <p>
|
* <p>
|
||||||
* Only formatting is supported, but all patterns are compatible with
|
* 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>
|
* <p>
|
||||||
* NOTE: Code originally taken from the open source TreeTrove project.
|
* NOTE: Code originally taken from the open source TreeTrove project.
|
||||||
*
|
*
|
||||||
|
@ -84,24 +90,34 @@ import java.util.TimeZone;
|
||||||
* @author Gary Gregory
|
* @author Gary Gregory
|
||||||
* @author Stephen Colebourne
|
* @author Stephen Colebourne
|
||||||
* @since 2.0
|
* @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 {
|
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;
|
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;
|
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;
|
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;
|
public static final int SHORT = SimpleDateFormat.SHORT;
|
||||||
|
|
||||||
// package scoped as used by inner class
|
// package scoped as used by inner class
|
||||||
static final double LOG_10 = Math.log(10);
|
static final double LOG_10 = Math.log(10);
|
||||||
|
|
||||||
private static String cDefaultPattern;
|
private static String cDefaultPattern;
|
||||||
private static TimeZone cDefaultTimeZone = TimeZone.getDefault();
|
|
||||||
|
|
||||||
private static Map cInstanceCache = new HashMap(7);
|
private static Map cInstanceCache = new HashMap(7);
|
||||||
private static Map cDateInstanceCache = new HashMap(7);
|
private static Map cDateInstanceCache = new HashMap(7);
|
||||||
|
@ -113,12 +129,16 @@ public class FastDateFormat extends Format {
|
||||||
private final String mPattern;
|
private final String mPattern;
|
||||||
/** The time zone */
|
/** The time zone */
|
||||||
private final TimeZone mTimeZone;
|
private final TimeZone mTimeZone;
|
||||||
|
/** Whether the time zone overrides any on Calendars */
|
||||||
|
private final boolean mTimeZoneForced;
|
||||||
/** The locale */
|
/** The locale */
|
||||||
private final Locale mLocale;
|
private final Locale mLocale;
|
||||||
|
/** Whether the locale overrides the default */
|
||||||
|
private final boolean mLocaleForced;
|
||||||
/** The parsed rules */
|
/** The parsed rules */
|
||||||
private final Rule[] mRules;
|
private Rule[] mRules;
|
||||||
/** The estimated maximum length */
|
/** 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 timeZone optional time zone, overrides time zone of formatted date
|
||||||
* @param locale optional locale, overrides system locale
|
* @param locale optional locale, overrides system locale
|
||||||
* @return a pattern based date/time formatter
|
* @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) {
|
public static synchronized FastDateFormat getInstance(String pattern, TimeZone timeZone, Locale locale) {
|
||||||
Object key = pattern;
|
FastDateFormat emptyFormat = new FastDateFormat(pattern, timeZone, locale);
|
||||||
if (timeZone != null) {
|
FastDateFormat format = (FastDateFormat) cInstanceCache.get(emptyFormat);
|
||||||
key = new Pair(key, timeZone);
|
|
||||||
}
|
|
||||||
if (locale != null) {
|
|
||||||
key = new Pair(key, locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
FastDateFormat format = (FastDateFormat) cInstanceCache.get(key);
|
|
||||||
if (format == null) {
|
if (format == null) {
|
||||||
if (locale == null) {
|
format = emptyFormat;
|
||||||
locale = Locale.getDefault();
|
format.init(); // convert shell format into usable one
|
||||||
}
|
cInstanceCache.put(format, format); // this is OK!
|
||||||
|
|
||||||
format = new FastDateFormat(pattern, timeZone, locale, new DateFormatSymbols(locale));
|
|
||||||
cInstanceCache.put(key, format);
|
|
||||||
}
|
}
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
@ -342,17 +352,62 @@ public class FastDateFormat extends Format {
|
||||||
return cDefaultPattern;
|
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.
|
* 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
|
* @return a List of Rule objects
|
||||||
* @throws IllegalArgumentException if pattern is invalid
|
* @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();
|
List rules = new ArrayList();
|
||||||
|
|
||||||
String[] ERAs = symbols.getEras();
|
String[] ERAs = symbols.getEras();
|
||||||
|
@ -362,12 +417,12 @@ public class FastDateFormat extends Format {
|
||||||
String[] shortWeekdays = symbols.getShortWeekdays();
|
String[] shortWeekdays = symbols.getShortWeekdays();
|
||||||
String[] AmPmStrings = symbols.getAmPmStrings();
|
String[] AmPmStrings = symbols.getAmPmStrings();
|
||||||
|
|
||||||
int length = pattern.length();
|
int length = mPattern.length();
|
||||||
int[] indexRef = new int[1];
|
int[] indexRef = new int[1];
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
indexRef[0] = i;
|
indexRef[0] = i;
|
||||||
String token = parseToken(pattern, indexRef);
|
String token = parseToken(mPattern, indexRef);
|
||||||
i = indexRef[0];
|
i = indexRef[0];
|
||||||
|
|
||||||
int tokenLen = token.length();
|
int tokenLen = token.length();
|
||||||
|
@ -384,9 +439,9 @@ public class FastDateFormat extends Format {
|
||||||
break;
|
break;
|
||||||
case 'y': // year (number)
|
case 'y': // year (number)
|
||||||
if (tokenLen >= 4) {
|
if (tokenLen >= 4) {
|
||||||
rule = new UnpaddedNumberField(Calendar.YEAR);
|
rule = UnpaddedNumberField.INSTANCE_YEAR;
|
||||||
} else {
|
} else {
|
||||||
rule = new TwoDigitYearField();
|
rule = TwoDigitYearField.INSTANCE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'M': // month in year (text and number)
|
case 'M': // month in year (text and number)
|
||||||
|
@ -395,9 +450,9 @@ public class FastDateFormat extends Format {
|
||||||
} else if (tokenLen == 3) {
|
} else if (tokenLen == 3) {
|
||||||
rule = new TextField(Calendar.MONTH, shortMonths);
|
rule = new TextField(Calendar.MONTH, shortMonths);
|
||||||
} else if (tokenLen == 2) {
|
} else if (tokenLen == 2) {
|
||||||
rule = new TwoDigitMonthField();
|
rule = TwoDigitMonthField.INSTANCE;
|
||||||
} else {
|
} else {
|
||||||
rule = new UnpaddedMonthField();
|
rule = UnpaddedMonthField.INSTANCE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'd': // day in month (number)
|
case 'd': // day in month (number)
|
||||||
|
@ -444,9 +499,16 @@ public class FastDateFormat extends Format {
|
||||||
break;
|
break;
|
||||||
case 'z': // time zone (text)
|
case 'z': // time zone (text)
|
||||||
if (tokenLen >= 4) {
|
if (tokenLen >= 4) {
|
||||||
rule = new TimeZoneRule(timeZone, locale, TimeZone.LONG);
|
rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.LONG);
|
||||||
} else {
|
} 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;
|
break;
|
||||||
case '\'': // literal text
|
case '\'': // literal text
|
||||||
|
@ -474,7 +536,7 @@ public class FastDateFormat extends Format {
|
||||||
* @param indexRef index references
|
* @param indexRef index references
|
||||||
* @return parsed token
|
* @return parsed token
|
||||||
*/
|
*/
|
||||||
private static String parseToken(String pattern, int[] indexRef) {
|
protected String parseToken(String pattern, int[] indexRef) {
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
|
|
||||||
int i = indexRef[0];
|
int i = indexRef[0];
|
||||||
|
@ -533,7 +595,7 @@ public class FastDateFormat extends Format {
|
||||||
* @param padding the padding required
|
* @param padding the padding required
|
||||||
* @return a new rule with the correct padding
|
* @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) {
|
switch (padding) {
|
||||||
case 1:
|
case 1:
|
||||||
return new UnpaddedNumberField(field);
|
return new UnpaddedNumberField(field);
|
||||||
|
@ -544,40 +606,7 @@ public class FastDateFormat extends Format {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
// Format methods
|
||||||
/**
|
|
||||||
* 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 either a Date or a Calendar object.
|
* Format either a Date or a Calendar object.
|
||||||
|
@ -605,11 +634,8 @@ public class FastDateFormat extends Format {
|
||||||
* @return the formatted string
|
* @return the formatted string
|
||||||
*/
|
*/
|
||||||
public String format(Date date) {
|
public String format(Date date) {
|
||||||
Calendar c = new GregorianCalendar(cDefaultTimeZone);
|
Calendar c = new GregorianCalendar(mTimeZone);
|
||||||
c.setTime(date);
|
c.setTime(date);
|
||||||
if (mTimeZone != null) {
|
|
||||||
c.setTimeZone(mTimeZone);
|
|
||||||
}
|
|
||||||
return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString();
|
return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,11 +657,8 @@ public class FastDateFormat extends Format {
|
||||||
* @return the specified string buffer
|
* @return the specified string buffer
|
||||||
*/
|
*/
|
||||||
public StringBuffer format(Date date, StringBuffer buf) {
|
public StringBuffer format(Date date, StringBuffer buf) {
|
||||||
Calendar c = new GregorianCalendar(cDefaultTimeZone);
|
Calendar c = new GregorianCalendar(mTimeZone);
|
||||||
c.setTime(date);
|
c.setTime(date);
|
||||||
if (mTimeZone != null) {
|
|
||||||
c.setTimeZone(mTimeZone);
|
|
||||||
}
|
|
||||||
return applyRules(c, buf);
|
return applyRules(c, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,7 +670,7 @@ public class FastDateFormat extends Format {
|
||||||
* @return the specified string buffer
|
* @return the specified string buffer
|
||||||
*/
|
*/
|
||||||
public StringBuffer format(Calendar calendar, StringBuffer buf) {
|
public StringBuffer format(Calendar calendar, StringBuffer buf) {
|
||||||
if (mTimeZone != null) {
|
if (mTimeZoneForced) {
|
||||||
calendar = (Calendar) calendar.clone();
|
calendar = (Calendar) calendar.clone();
|
||||||
calendar.setTimeZone(mTimeZone);
|
calendar.setTimeZone(mTimeZone);
|
||||||
}
|
}
|
||||||
|
@ -661,7 +684,7 @@ public class FastDateFormat extends Format {
|
||||||
* @param buf the buffer to format into
|
* @param buf the buffer to format into
|
||||||
* @return the specified string buffer
|
* @return the specified string buffer
|
||||||
*/
|
*/
|
||||||
private StringBuffer applyRules(Calendar calendar, StringBuffer buf) {
|
protected StringBuffer applyRules(Calendar calendar, StringBuffer buf) {
|
||||||
Rule[] rules = mRules;
|
Rule[] rules = mRules;
|
||||||
int len = mRules.length;
|
int len = mRules.length;
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
|
@ -670,6 +693,7 @@ public class FastDateFormat extends Format {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parsing
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* Parsing not supported.
|
* Parsing not supported.
|
||||||
|
@ -684,6 +708,7 @@ public class FastDateFormat extends Format {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Accessors
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* Gets the pattern used by this formatter.
|
* 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
|
* Gets the time zone used by this formatter.
|
||||||
* formatted dates is used instead.
|
* <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
|
* @return the time zone
|
||||||
*/
|
*/
|
||||||
|
@ -704,6 +732,16 @@ public class FastDateFormat extends Format {
|
||||||
return mTimeZone;
|
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.
|
* Gets the locale used by this formatter.
|
||||||
*
|
*
|
||||||
|
@ -723,6 +761,56 @@ public class FastDateFormat extends Format {
|
||||||
return mMaxLengthEstimate;
|
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.
|
* Inner class defining a rule.
|
||||||
|
@ -809,6 +897,8 @@ public class FastDateFormat extends Format {
|
||||||
* Inner class to output an unpadded number.
|
* Inner class to output an unpadded number.
|
||||||
*/
|
*/
|
||||||
private static class UnpaddedNumberField implements NumberRule {
|
private static class UnpaddedNumberField implements NumberRule {
|
||||||
|
static final UnpaddedNumberField INSTANCE_YEAR = new UnpaddedNumberField(Calendar.YEAR);
|
||||||
|
|
||||||
private final int mField;
|
private final int mField;
|
||||||
|
|
||||||
UnpaddedNumberField(int field) {
|
UnpaddedNumberField(int field) {
|
||||||
|
@ -826,12 +916,10 @@ public class FastDateFormat extends Format {
|
||||||
public final void appendTo(StringBuffer buffer, int value) {
|
public final void appendTo(StringBuffer buffer, int value) {
|
||||||
if (value < 10) {
|
if (value < 10) {
|
||||||
buffer.append((char)(value + '0'));
|
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'));
|
||||||
buffer.append((char)(value % 10 + '0'));
|
buffer.append((char)(value % 10 + '0'));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
buffer.append(Integer.toString(value));
|
buffer.append(Integer.toString(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -841,6 +929,8 @@ public class FastDateFormat extends Format {
|
||||||
* Inner class to output an unpadded month.
|
* Inner class to output an unpadded month.
|
||||||
*/
|
*/
|
||||||
private static class UnpaddedMonthField implements NumberRule {
|
private static class UnpaddedMonthField implements NumberRule {
|
||||||
|
static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField();
|
||||||
|
|
||||||
UnpaddedMonthField() {
|
UnpaddedMonthField() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -855,8 +945,7 @@ public class FastDateFormat extends Format {
|
||||||
public final void appendTo(StringBuffer buffer, int value) {
|
public final void appendTo(StringBuffer buffer, int value) {
|
||||||
if (value < 10) {
|
if (value < 10) {
|
||||||
buffer.append((char)(value + '0'));
|
buffer.append((char)(value + '0'));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
buffer.append((char)(value / 10 + '0'));
|
buffer.append((char)(value / 10 + '0'));
|
||||||
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'));
|
||||||
buffer.append((char)(value % 10 + '0'));
|
buffer.append((char)(value % 10 + '0'));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int digits;
|
int digits;
|
||||||
if (value < 1000) {
|
if (value < 1000) {
|
||||||
digits = 3;
|
digits = 3;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
digits = (int)(Math.log(value) / LOG_10) + 1;
|
digits = (int)(Math.log(value) / LOG_10) + 1;
|
||||||
}
|
}
|
||||||
for (int i = mSize; --i >= digits; ) {
|
for (int i = mSize; --i >= digits; ) {
|
||||||
|
@ -933,8 +1020,7 @@ public class FastDateFormat extends Format {
|
||||||
if (value < 100) {
|
if (value < 100) {
|
||||||
buffer.append((char)(value / 10 + '0'));
|
buffer.append((char)(value / 10 + '0'));
|
||||||
buffer.append((char)(value % 10 + '0'));
|
buffer.append((char)(value % 10 + '0'));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
buffer.append(Integer.toString(value));
|
buffer.append(Integer.toString(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -944,6 +1030,8 @@ public class FastDateFormat extends Format {
|
||||||
* Inner class to output a two digit year.
|
* Inner class to output a two digit year.
|
||||||
*/
|
*/
|
||||||
private static class TwoDigitYearField implements NumberRule {
|
private static class TwoDigitYearField implements NumberRule {
|
||||||
|
static final TwoDigitYearField INSTANCE = new TwoDigitYearField();
|
||||||
|
|
||||||
TwoDigitYearField() {
|
TwoDigitYearField() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,6 +1053,8 @@ public class FastDateFormat extends Format {
|
||||||
* Inner class to output a two digit month.
|
* Inner class to output a two digit month.
|
||||||
*/
|
*/
|
||||||
private static class TwoDigitMonthField implements NumberRule {
|
private static class TwoDigitMonthField implements NumberRule {
|
||||||
|
static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField();
|
||||||
|
|
||||||
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 TimeZone mTimeZone;
|
||||||
|
private final boolean mTimeZoneForced;
|
||||||
private final Locale mLocale;
|
private final Locale mLocale;
|
||||||
private final int mStyle;
|
private final int mStyle;
|
||||||
private final String mStandard;
|
private final String mStandard;
|
||||||
private final String mDaylight;
|
private final String mDaylight;
|
||||||
|
|
||||||
TimeZoneRule(TimeZone timeZone, Locale locale, int style) {
|
TimeZoneNameRule(TimeZone timeZone, boolean timeZoneForced, Locale locale, int style) {
|
||||||
mTimeZone = timeZone;
|
mTimeZone = timeZone;
|
||||||
|
mTimeZoneForced = timeZoneForced;
|
||||||
mLocale = locale;
|
mLocale = locale;
|
||||||
mStyle = style;
|
mStyle = style;
|
||||||
|
|
||||||
if (timeZone != null) {
|
if (timeZoneForced) {
|
||||||
mStandard = getTimeZoneDisplay(timeZone, false, style, locale);
|
mStandard = getTimeZoneDisplay(timeZone, false, style, locale);
|
||||||
mDaylight = getTimeZoneDisplay(timeZone, true, style, locale);
|
mDaylight = getTimeZoneDisplay(timeZone, true, style, locale);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
mStandard = null;
|
mStandard = null;
|
||||||
mDaylight = null;
|
mDaylight = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int estimateLength() {
|
public int estimateLength() {
|
||||||
if (mTimeZone != null) {
|
if (mTimeZoneForced) {
|
||||||
return Math.max(mStandard.length(), mDaylight.length());
|
return Math.max(mStandard.length(), mDaylight.length());
|
||||||
}
|
} else if (mStyle == TimeZone.SHORT) {
|
||||||
else if (mStyle == TimeZone.SHORT) {
|
|
||||||
return 4;
|
return 4;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return 40;
|
return 40;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void appendTo(StringBuffer buffer, Calendar calendar) {
|
public void appendTo(StringBuffer buffer, Calendar calendar) {
|
||||||
TimeZone timeZone;
|
if (mTimeZoneForced) {
|
||||||
if ((timeZone = mTimeZone) != null) {
|
if (mTimeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) {
|
||||||
if (timeZone.useDaylightTime() &&
|
|
||||||
calendar.get(Calendar.DST_OFFSET) != 0) {
|
|
||||||
|
|
||||||
buffer.append(mDaylight);
|
buffer.append(mDaylight);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
buffer.append(mStandard);
|
buffer.append(mStandard);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
TimeZone timeZone = calendar.getTimeZone();
|
||||||
timeZone = calendar.getTimeZone();
|
if (timeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) {
|
||||||
if (timeZone.useDaylightTime() &&
|
buffer.append(getTimeZoneDisplay(timeZone, true, mStyle, mLocale));
|
||||||
calendar.get(Calendar.DST_OFFSET) != 0) {
|
} else {
|
||||||
|
buffer.append(getTimeZoneDisplay(timeZone, false, mStyle, mLocale));
|
||||||
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.
|
* 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
|
* Helper class for creating compound objects. One use for this class is to create a
|
||||||
* hashtable key out of multiple objects.
|
* hashtable key out of multiple objects.
|
||||||
*/
|
*/
|
||||||
private static class Pair implements Comparable, Serializable {
|
private static class Pair {
|
||||||
private final Object mObj1;
|
private final Object mObj1;
|
||||||
private final Object mObj2;
|
private final Object mObj2;
|
||||||
|
|
||||||
|
@ -1153,56 +1273,6 @@ public class FastDateFormat extends Format {
|
||||||
mObj2 = obj2;
|
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) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
* The Apache Software License, Version 1.1
|
* 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.
|
* reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* 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 Henri Yandell
|
||||||
* @author Stephen Colebourne
|
* @author Stephen Colebourne
|
||||||
* @since 2.0
|
* @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 {
|
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 */
|
/** The start time */
|
||||||
private long startTime = -1;
|
private long startTime = -1;
|
||||||
/** The stop time */
|
/** 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>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>
|
* <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.</p>
|
||||||
*
|
*
|
||||||
* @return the time as a String
|
* @return the time as a String
|
||||||
*/
|
*/
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return StopWatch.toString(getTime());
|
return DurationFormatUtils.formatISO(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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
* 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.
|
* reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -23,14 +23,14 @@
|
||||||
* Alternately, this acknowlegement may appear in the software itself,
|
* Alternately, this acknowlegement may appear in the software itself,
|
||||||
* if and wherever such third-party acknowlegements normally appear.
|
* 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
|
* Foundation" must not be used to endorse or promote products derived
|
||||||
* from this software without prior written permission. For written
|
* from this software without prior written permission. For written
|
||||||
* permission, please contact apache@apache.org.
|
* permission, please contact apache@apache.org.
|
||||||
*
|
*
|
||||||
* 5. Products derived from this software may not be called "Apache"
|
* 5. Products derived from this software may not be called "Apache"
|
||||||
* nor may "Apache" appear in their names without prior written
|
* 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
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
@ -53,22 +53,32 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.commons.lang.time;
|
package org.apache.commons.lang.time;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
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.Test;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
import junit.textui.TestRunner;
|
import junit.textui.TestRunner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TestCase for DateUtils. [Relies heavily on code taken from the
|
* Unit tests {@link org.apache.commons.lang.CalendarUtils}.
|
||||||
* DateUtilsTest class of the jakarata-ant project.]
|
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
|
* @author <a href="mailto:sergek@lokitech.com">Serge Knystautas</a>
|
||||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
|
|
||||||
*/
|
*/
|
||||||
public class DateUtilsTest extends TestCase {
|
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) {
|
public static void main(String[] args) {
|
||||||
TestRunner.run(suite());
|
TestRunner.run(suite());
|
||||||
|
@ -76,69 +86,300 @@ public class DateUtilsTest extends TestCase {
|
||||||
|
|
||||||
public static Test suite() {
|
public static Test suite() {
|
||||||
TestSuite suite = new TestSuite(DateUtilsTest.class);
|
TestSuite suite = new TestSuite(DateUtilsTest.class);
|
||||||
suite.setName("DateUtils Tests");
|
suite.setName("CalendarUtilsTest Tests");
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateUtilsTest(String s) {
|
protected void setUp() throws Exception {
|
||||||
super(s);
|
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(){
|
protected void tearDown() throws Exception {
|
||||||
String text = DateUtils.formatElapsedTime(50*1000);
|
super.tearDown();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(),
|
* Tests various values with the round method
|
||||||
DateUtils.ISO8601_DATETIME_PATTERN);
|
*/
|
||||||
assertEquals("2002-02-23T09:11:12", text);
|
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");
|
* Tests various values with the trunc method
|
||||||
Calendar cal = Calendar.getInstance(timeZone);
|
*/
|
||||||
cal.set(2002,1,23);
|
public void testTrunc() throws Exception {
|
||||||
String text = DateUtils.format(cal.getTime(),
|
assertEquals("trunc year-1 failed",
|
||||||
DateUtils.ISO8601_DATE_PATTERN);
|
dateParser.parse("January 1, 2002"),
|
||||||
assertEquals("2002-02-23", text);
|
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
|
* Tests the parse method, which is supposed to handle various strings
|
||||||
TimeZone timeZone = TimeZone.getTimeZone("GMT+1");
|
* as flexibly as CVS supports.
|
||||||
Calendar cal = Calendar.getInstance(timeZone);
|
*/
|
||||||
cal.set(2002,1,23, 21, 11, 12);
|
public void testParse() throws Exception {
|
||||||
String text = DateUtils.format(cal.getTime(),
|
//This is difficult to test since the "now" used in the
|
||||||
DateUtils.ISO8601_TIME_PATTERN);
|
// parse function cannot be controlled. We could possibly control
|
||||||
assertEquals("20:11:12", text);
|
// 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
|
* Tests the calendar iterator for week ranges
|
||||||
long ms = (20*3600 + 11*60 + 12)*1000;
|
*/
|
||||||
String text = DateUtils.format(ms,
|
public void testWeekIterator() throws Exception {
|
||||||
DateUtils.ISO8601_TIME_PATTERN);
|
Calendar now = Calendar.getInstance();
|
||||||
assertEquals("20:11:12", text);
|
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");
|
* Tests the calendar iterator for month-based ranges
|
||||||
Calendar cal = Calendar.getInstance(timeZone);
|
*/
|
||||||
// should be full moon
|
public void testMonthIterator() throws Exception {
|
||||||
cal.set(2002, 2, 27);
|
Iterator it = DateUtils.getCalendarIterator(date1, DateUtils.RANGE_MONTH_SUNDAY);
|
||||||
assertEquals(4, DateUtils.getPhaseOfMoon(cal));
|
assertWeekIterator(it,
|
||||||
// should be new moon
|
dateParser.parse("January 27, 2002"),
|
||||||
cal.set(2002, 2, 12);
|
dateParser.parse("March 2, 2002"));
|
||||||
assertEquals(0, DateUtils.getPhaseOfMoon(cal));
|
|
||||||
|
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;
|
package org.apache.commons.lang.time;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
@ -67,7 +69,7 @@ import junit.textui.TestRunner;
|
||||||
*
|
*
|
||||||
* @author Sean Schofield
|
* @author Sean Schofield
|
||||||
* @since 2.0
|
* @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 {
|
public class FastDateFormatTest extends TestCase {
|
||||||
|
|
||||||
|
@ -106,9 +108,15 @@ public class FastDateFormatTest extends TestCase {
|
||||||
public void test_getInstance_String() {
|
public void test_getInstance_String() {
|
||||||
FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy");
|
FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy");
|
||||||
FastDateFormat format2 = 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);
|
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("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() {
|
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 format3 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
|
||||||
FastDateFormat format4 = 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 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 != format2); // -- junit 3.8 version -- assertFalse(format1 == format2);
|
||||||
assertTrue(format1.getTimeZone().equals(TimeZone.getTimeZone("Atlantic/Reykjavik")));
|
assertEquals(TimeZone.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
|
||||||
assertNull(format2.getTimeZone());
|
assertEquals(true, format1.getTimeZoneOverridesCalendar());
|
||||||
|
assertEquals(TimeZone.getDefault(), format2.getTimeZone());
|
||||||
|
assertEquals(false, format2.getTimeZoneOverridesCalendar());
|
||||||
assertSame(format3, format4);
|
assertSame(format3, format4);
|
||||||
assertTrue(format3 != format5); // -- junit 3.8 version -- assertFalse(format3 == format5);
|
assertTrue(format3 != format5); // -- junit 3.8 version -- assertFalse(format3 == format5);
|
||||||
|
assertTrue(format4 != format6); // -- junit 3.8 version -- assertFalse(format3 == format5);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
Locale.setDefault(realDefaultLocale);
|
Locale.setDefault(realDefaultLocale);
|
||||||
|
@ -168,10 +180,66 @@ public class FastDateFormatTest extends TestCase {
|
||||||
TimeZone.getDefault(), Locale.GERMANY);
|
TimeZone.getDefault(), Locale.GERMANY);
|
||||||
|
|
||||||
assertTrue(format1 != format2); // -- junit 3.8 version -- assertNotSame(format1, format2);
|
assertTrue(format1 != format2); // -- junit 3.8 version -- assertNotSame(format1, format2);
|
||||||
assertEquals(format1.getTimeZone(), TimeZone.getTimeZone("Atlantic/Reykjavik"));
|
assertEquals(TimeZone.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
|
||||||
assertNull(format2.getTimeZone());
|
assertEquals(TimeZone.getDefault(), format2.getTimeZone());
|
||||||
assertEquals(format3.getTimeZone(), TimeZone.getDefault());
|
assertEquals(TimeZone.getDefault(), format3.getTimeZone());
|
||||||
assertEquals(format3.getTimeZone(), TimeZone.getTimeZone("America/New_York"));
|
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 {
|
} finally {
|
||||||
Locale.setDefault(realDefaultLocale);
|
Locale.setDefault(realDefaultLocale);
|
||||||
|
|
|
@ -62,7 +62,7 @@ import junit.textui.TestRunner;
|
||||||
* TestCase for StopWatch.
|
* TestCase for StopWatch.
|
||||||
*
|
*
|
||||||
* @author Stephen Colebourne
|
* @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 {
|
public class StopWatchTest extends TestCase {
|
||||||
|
|
||||||
|
@ -80,35 +80,6 @@ public class StopWatchTest extends TestCase {
|
||||||
super(s);
|
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(){
|
public void testStopWatchSimple(){
|
||||||
StopWatch watch = new StopWatch();
|
StopWatch watch = new StopWatch();
|
||||||
assertEquals(0, watch.getTime());
|
assertEquals(0, watch.getTime());
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
* The Apache Software License, Version 1.1
|
* 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.
|
* reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* 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.TestCase;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
import junit.textui.TestRunner;
|
import junit.textui.TestRunner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test suite for the Time package.
|
* Test suite for the Time package.
|
||||||
*
|
*
|
||||||
* @author Stephen Colebourne
|
* @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 {
|
public class TimeTestSuite extends TestCase {
|
||||||
|
|
||||||
|
@ -85,8 +86,9 @@ public class TimeTestSuite extends TestCase {
|
||||||
public static Test suite() {
|
public static Test suite() {
|
||||||
TestSuite suite = new TestSuite();
|
TestSuite suite = new TestSuite();
|
||||||
suite.setName("Commons-Lang-Time Tests");
|
suite.setName("Commons-Lang-Time Tests");
|
||||||
suite.addTest(CalendarUtilsTest.suite());
|
|
||||||
suite.addTest(DateUtilsTest.suite());
|
suite.addTest(DateUtilsTest.suite());
|
||||||
|
suite.addTest(DateFormatUtilsTest.suite());
|
||||||
|
suite.addTest(DurationFormatUtilsTest.suite());
|
||||||
suite.addTest(StopWatchTest.suite());
|
suite.addTest(StopWatchTest.suite());
|
||||||
suite.addTest(FastDateFormatTest.suite());
|
suite.addTest(FastDateFormatTest.suite());
|
||||||
return suite;
|
return suite;
|
||||||
|
|
Loading…
Reference in New Issue