/*
* Copyright 2001-2009 Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.joda.time;
import java.io.
Serializable;
import java.util.
Comparator;
import org.joda.time.convert.
ConverterManager;
import org.joda.time.convert.
InstantConverter;
/**
* DateTimeComparator provides comparators to compare one date with another.
* <p>
* Dates may be specified using any object recognised by the
* {@link org.joda.time.convert.ConverterManager ConverterManager} class.
* <p>
* The default objects recognised by the comparator are:
* <ul>
* <li>ReadableInstant
* <li>String
* <li>Calendar
* <li>Date
* <li>Long (milliseconds)
* <li>null (now)
* </ul>
*
* <p>
* DateTimeComparator is thread-safe and immutable.
*
* @author Guy Allard
* @author Stephen Colebourne
* @author Brian S O'Neill
* @since 1.0
*/
public class
DateTimeComparator implements
Comparator<
Object>,
Serializable {
/** Serialization lock */
private static final long
serialVersionUID = -6097339773320178364L;
/** Singleton instance */
private static final
DateTimeComparator ALL_INSTANCE = new
DateTimeComparator(null, null);
/** Singleton instance */
private static final
DateTimeComparator DATE_INSTANCE = new
DateTimeComparator(
DateTimeFieldType.
dayOfYear(), null);
/** Singleton instance */
private static final
DateTimeComparator TIME_INSTANCE = new
DateTimeComparator(null,
DateTimeFieldType.
dayOfYear());
/** The lower limit of fields to compare, null if no limit */
private final
DateTimeFieldType iLowerLimit;
/** The upper limit of fields to compare, null if no limit */
private final
DateTimeFieldType iUpperLimit;
//-----------------------------------------------------------------------
/**
* Returns a DateTimeComparator the compares the entire date time value.
*
* @return a comparator over all fields
*/
public static
DateTimeComparator getInstance() {
return
ALL_INSTANCE;
}
/**
* Returns a DateTimeComparator with a lower limit only. Fields of a
* magnitude less than the lower limit are excluded from comparisons.
* <p>
* The time-zone is considered when using this comparator.
* The input millis are truncated using the time-zone of that input value.
* Thus, two inputs with different time-zones will typically not be equal
*
* @param lowerLimit inclusive lower limit for fields to be compared, null means no limit
* @return a comparator over all fields above the lower limit
*/
public static
DateTimeComparator getInstance(
DateTimeFieldType lowerLimit) {
return
getInstance(
lowerLimit, null);
}
/**
* Returns a DateTimeComparator with a lower and upper limit. Fields of a
* magnitude less than the lower limit are excluded from comparisons.
* Fields of a magnitude greater than or equal to the upper limit are also
* excluded from comparisons. Either limit may be specified as null, which
* indicates an unbounded limit.
* <p>
* The time-zone is considered when using this comparator unless both limits are null.
* The input millis are rounded/truncated using the time-zone of that input value.
* Thus, two inputs with different time-zones will typically not be equal
*
* @param lowerLimit inclusive lower limit for fields to be compared, null means no limit
* @param upperLimit exclusive upper limit for fields to be compared, null means no limit
* @return a comparator over all fields between the limits
*/
public static
DateTimeComparator getInstance(
DateTimeFieldType lowerLimit,
DateTimeFieldType upperLimit) {
if (
lowerLimit == null &&
upperLimit == null) {
return
ALL_INSTANCE;
}
if (
lowerLimit ==
DateTimeFieldType.
dayOfYear() &&
upperLimit == null) {
return
DATE_INSTANCE;
}
if (
lowerLimit == null &&
upperLimit ==
DateTimeFieldType.
dayOfYear()) {
return
TIME_INSTANCE;
}
return new
DateTimeComparator(
lowerLimit,
upperLimit);
}
/**
* Returns a comparator that only considers date fields.
* Time of day is ignored.
* <p>
* The time-zone is considered when using this comparator.
* The input millis are rounded down to the start of the day
* in the time-zone of that input value. Thus, two inputs with
* different time-zones will typically not be equal
*
* @return a comparator over all date fields
*/
public static
DateTimeComparator getDateOnlyInstance() {
return
DATE_INSTANCE;
}
/**
* Returns a comparator that only considers time fields.
* Date is ignored.
* <p>
* The time-zone is considered when using this comparator.
* The input millis are truncated to be within the day
* in the time-zone of that input value. Thus, two inputs with
* different time-zones will typically not be equal
*
* @return a comparator over all time fields
*/
public static
DateTimeComparator getTimeOnlyInstance() {
return
TIME_INSTANCE;
}
/**
* Restricted constructor.
*
* @param lowerLimit the lower field limit, null means no limit
* @param upperLimit the upper field limit, null means no limit
*/
protected
DateTimeComparator(
DateTimeFieldType lowerLimit,
DateTimeFieldType upperLimit) {
super();
iLowerLimit =
lowerLimit;
iUpperLimit =
upperLimit;
}
//-----------------------------------------------------------------------
/**
* Gets the field type that represents the lower limit of comparison.
*
* @return the field type, null if no upper limit
*/
public
DateTimeFieldType getLowerLimit() {
return
iLowerLimit;
}
/**
* Gets the field type that represents the upper limit of comparison.
*
* @return the field type, null if no upper limit
*/
public
DateTimeFieldType getUpperLimit() {
return
iUpperLimit;
}
/**
* Compare two objects against only the range of date time fields as
* specified in the constructor.
*
* @param lhsObj the first object,
* logically on the left of a < comparison, null means now
* @param rhsObj the second object,
* logically on the right of a < comparison, null means now
* @return zero if order does not matter,
* negative value if lhsObj < rhsObj, positive value otherwise.
* @throws IllegalArgumentException if either argument is not supported
*/
public int
compare(
Object lhsObj,
Object rhsObj) {
InstantConverter conv =
ConverterManager.
getInstance().
getInstantConverter(
lhsObj);
Chronology lhsChrono =
conv.
getChronology(
lhsObj, (
Chronology) null);
long
lhsMillis =
conv.
getInstantMillis(
lhsObj,
lhsChrono);
// handle null==null and other cases where objects are the same
// but only do this after checking the input is valid
if (
lhsObj ==
rhsObj) {
return 0;
}
conv =
ConverterManager.
getInstance().
getInstantConverter(
rhsObj);
Chronology rhsChrono =
conv.
getChronology(
rhsObj, (
Chronology) null);
long
rhsMillis =
conv.
getInstantMillis(
rhsObj,
rhsChrono);
if (
iLowerLimit != null) {
lhsMillis =
iLowerLimit.
getField(
lhsChrono).
roundFloor(
lhsMillis);
rhsMillis =
iLowerLimit.
getField(
rhsChrono).
roundFloor(
rhsMillis);
}
if (
iUpperLimit != null) {
lhsMillis =
iUpperLimit.
getField(
lhsChrono).
remainder(
lhsMillis);
rhsMillis =
iUpperLimit.
getField(
rhsChrono).
remainder(
rhsMillis);
}
if (
lhsMillis <
rhsMillis) {
return -1;
} else if (
lhsMillis >
rhsMillis) {
return 1;
} else {
return 0;
}
}
//-----------------------------------------------------------------------
/**
* Support serialization singletons.
*
* @return the resolved singleton instance
*/
private
Object readResolve() {
return
getInstance(
iLowerLimit,
iUpperLimit);
}
/**
* Compares this comparator to another.
*
* @param object the object to compare to
* @return true if equal
*/
public boolean
equals(
Object object) {
if (
object instanceof
DateTimeComparator) {
DateTimeComparator other = (
DateTimeComparator)
object;
return (
iLowerLimit ==
other.
getLowerLimit() ||
(
iLowerLimit != null &&
iLowerLimit.
equals(
other.
getLowerLimit()))) &&
(
iUpperLimit ==
other.
getUpperLimit() ||
(
iUpperLimit != null &&
iUpperLimit.
equals(
other.
getUpperLimit())));
}
return false;
}
/**
* Gets a suitable hashcode.
*
* @return the hashcode
*/
public int
hashCode() {
return (
iLowerLimit == null ? 0 :
iLowerLimit.
hashCode()) +
(123 * (
iUpperLimit == null ? 0 :
iUpperLimit.
hashCode()));
}
/**
* Gets a debugging string.
*
* @return a debugging string
*/
public
String toString() {
if (
iLowerLimit ==
iUpperLimit) {
return "DateTimeComparator["
+ (
iLowerLimit == null ? "" :
iLowerLimit.
getName())
+ "]";
} else {
return "DateTimeComparator["
+ (
iLowerLimit == null ? "" :
iLowerLimit.
getName())
+ "-"
+ (
iUpperLimit == null ? "" :
iUpperLimit.
getName())
+ "]";
}
}
}