View Javadoc

1   /*
2    *  Copyright 2001-2009 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.time;
17  
18  import java.io.Serializable;
19  import java.util.Comparator;
20  
21  import org.joda.time.convert.ConverterManager;
22  import org.joda.time.convert.InstantConverter;
23  
24  /**
25   * DateTimeComparator provides comparators to compare one date with another.
26   * <p>
27   * Dates may be specified using any object recognised by the
28   * {@link org.joda.time.convert.ConverterManager ConverterManager} class.
29   * <p>
30   * The default objects recognised by the comparator are:
31   * <ul>
32   * <li>ReadableInstant
33   * <li>String
34   * <li>Calendar
35   * <li>Date
36   * <li>Long (milliseconds)
37   * <li>null (now)
38   * </ul>
39   *
40   * <p>
41   * DateTimeComparator is thread-safe and immutable.
42   *
43   * @author Guy Allard
44   * @author Stephen Colebourne
45   * @author Brian S O'Neill
46   * @since 1.0
47   */
48  public class DateTimeComparator implements Comparator<Object>, Serializable {
49  
50      /** Serialization lock */
51      private static final long serialVersionUID = -6097339773320178364L;
52  
53      /** Singleton instance */
54      private static final DateTimeComparator ALL_INSTANCE = new DateTimeComparator(null, null);
55      /** Singleton instance */
56      private static final DateTimeComparator DATE_INSTANCE = new DateTimeComparator(DateTimeFieldType.dayOfYear(), null);
57      /** Singleton instance */
58      private static final DateTimeComparator TIME_INSTANCE = new DateTimeComparator(null, DateTimeFieldType.dayOfYear());
59  
60      /** The lower limit of fields to compare, null if no limit */
61      private final DateTimeFieldType iLowerLimit;
62      /** The upper limit of fields to compare, null if no limit */
63      private final DateTimeFieldType iUpperLimit;
64  
65      //-----------------------------------------------------------------------
66      /**
67       * Returns a DateTimeComparator the compares the entire date time value.
68       * 
69       * @return a comparator over all fields
70       */
71      public static DateTimeComparator getInstance() {
72          return ALL_INSTANCE;
73      }
74  
75      /**
76       * Returns a DateTimeComparator with a lower limit only. Fields of a
77       * magnitude less than the lower limit are excluded from comparisons.
78       *
79       * @param lowerLimit  inclusive lower limit for fields to be compared, null means no limit
80       * @return a comparator over all fields above the lower limit
81       */
82      public static DateTimeComparator getInstance(DateTimeFieldType lowerLimit) {
83          return getInstance(lowerLimit, null);
84      }
85  
86      /**
87       * Returns a DateTimeComparator with a lower and upper limit. Fields of a
88       * magnitude less than the lower limit are excluded from comparisons.
89       * Fields of a magnitude greater than or equal to the upper limit are also
90       * excluded from comparisons. Either limit may be specified as null, which
91       * indicates an unbounded limit.
92       *
93       * @param lowerLimit  inclusive lower limit for fields to be compared, null means no limit
94       * @param upperLimit  exclusive upper limit for fields to be compared, null means no limit
95       * @return a comparator over all fields between the limits
96       */
97      public static DateTimeComparator getInstance(DateTimeFieldType lowerLimit, DateTimeFieldType upperLimit) {
98          if (lowerLimit == null && upperLimit == null) {
99              return ALL_INSTANCE;
100         }
101         if (lowerLimit == DateTimeFieldType.dayOfYear() && upperLimit == null) {
102             return DATE_INSTANCE;
103         }
104         if (lowerLimit == null && upperLimit == DateTimeFieldType.dayOfYear()) {
105             return TIME_INSTANCE;
106         }
107         return new DateTimeComparator(lowerLimit, upperLimit);
108     }
109 
110     /**
111      * Returns a comparator that only considers date fields.
112      * Time of day is ignored.
113      * 
114      * @return a comparator over all date fields
115      */
116     public static DateTimeComparator getDateOnlyInstance() {
117         return DATE_INSTANCE;
118     }
119 
120     /**
121      * Returns a comparator that only considers time fields.
122      * Date is ignored.
123      * 
124      * @return a comparator over all time fields
125      */
126     public static DateTimeComparator getTimeOnlyInstance() {
127         return TIME_INSTANCE;
128     }
129 
130     /**
131      * Restricted constructor.
132      * 
133      * @param lowerLimit  the lower field limit, null means no limit
134      * @param upperLimit  the upper field limit, null means no limit
135      */
136     protected DateTimeComparator(DateTimeFieldType lowerLimit, DateTimeFieldType upperLimit) {
137         super();
138         iLowerLimit = lowerLimit;
139         iUpperLimit = upperLimit;
140     }
141 
142     //-----------------------------------------------------------------------
143     /**
144      * Gets the field type that represents the lower limit of comparison.
145      * 
146      * @return the field type, null if no upper limit
147      */
148     public DateTimeFieldType getLowerLimit() {
149         return iLowerLimit;
150     }
151 
152     /**
153      * Gets the field type that represents the upper limit of comparison.
154      * 
155      * @return the field type, null if no upper limit
156      */
157     public DateTimeFieldType getUpperLimit() {
158         return iUpperLimit;
159     }
160 
161     /**
162      * Compare two objects against only the range of date time fields as
163      * specified in the constructor.
164      * 
165      * @param lhsObj  the first object,
166      *      logically on the left of a &lt; comparison, null means now
167      * @param rhsObj  the second object,
168      *      logically on the right of a &lt; comparison, null means now
169      * @return zero if order does not matter,
170      *      negative value if lhsObj &lt; rhsObj, positive value otherwise.
171      * @throws IllegalArgumentException if either argument is not supported
172      */
173     public int compare(Object lhsObj, Object rhsObj) {
174         InstantConverter conv = ConverterManager.getInstance().getInstantConverter(lhsObj);
175         Chronology lhsChrono = conv.getChronology(lhsObj, (Chronology) null);
176         long lhsMillis = conv.getInstantMillis(lhsObj, lhsChrono);
177         
178         conv = ConverterManager.getInstance().getInstantConverter(rhsObj);
179         Chronology rhsChrono = conv.getChronology(rhsObj, (Chronology) null);
180         long rhsMillis = conv.getInstantMillis(rhsObj, rhsChrono);
181 
182         if (iLowerLimit != null) {
183             lhsMillis = iLowerLimit.getField(lhsChrono).roundFloor(lhsMillis);
184             rhsMillis = iLowerLimit.getField(rhsChrono).roundFloor(rhsMillis);
185         }
186 
187         if (iUpperLimit != null) {
188             lhsMillis = iUpperLimit.getField(lhsChrono).remainder(lhsMillis);
189             rhsMillis = iUpperLimit.getField(rhsChrono).remainder(rhsMillis);
190         }
191 
192         if (lhsMillis < rhsMillis) {
193             return -1;
194         } else if (lhsMillis > rhsMillis) {
195             return 1;
196         } else {
197             return 0;
198         }
199     }
200 
201     //-----------------------------------------------------------------------
202     /**
203      * Support serialization singletons.
204      * 
205      * @return the resolved singleton instance
206      */
207     private Object readResolve() {
208         return getInstance(iLowerLimit, iUpperLimit);
209     }
210 
211     /**
212      * Compares this comparator to another.
213      * 
214      * @param object  the object to compare to
215      * @return true if equal
216      */
217     public boolean equals(Object object) {
218         if (object instanceof DateTimeComparator) {
219             DateTimeComparator other = (DateTimeComparator) object;
220             return (iLowerLimit == other.getLowerLimit() ||
221                     (iLowerLimit != null && iLowerLimit.equals(other.getLowerLimit()))) &&
222                    (iUpperLimit == other.getUpperLimit() ||
223                     (iUpperLimit != null && iUpperLimit.equals(other.getUpperLimit())));
224         }
225         return false;
226     }
227 
228     /**
229      * Gets a suitable hashcode.
230      * 
231      * @return the hashcode
232      */
233     public int hashCode() {
234         return (iLowerLimit == null ? 0 : iLowerLimit.hashCode()) +
235                (123 * (iUpperLimit == null ? 0 : iUpperLimit.hashCode()));
236     }
237 
238     /**
239      * Gets a debugging string.
240      * 
241      * @return a debugging string
242      */
243     public String toString() {
244         if (iLowerLimit == iUpperLimit) {
245             return "DateTimeComparator["
246                 + (iLowerLimit == null ? "" : iLowerLimit.getName())
247                 + "]";
248         } else {
249             return "DateTimeComparator["
250                 + (iLowerLimit == null ? "" : iLowerLimit.getName())
251                 + "-"
252                 + (iUpperLimit == null ? "" : iUpperLimit.getName())
253                 + "]";
254         }
255     }
256 
257 }