View Javadoc

1   /*
2    *  Copyright 2001-2010 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.base;
17  
18  import java.util.Date;
19  
20  import org.joda.convert.ToString;
21  import org.joda.time.Chronology;
22  import org.joda.time.DateTime;
23  import org.joda.time.DateTimeField;
24  import org.joda.time.DateTimeFieldType;
25  import org.joda.time.DateTimeUtils;
26  import org.joda.time.DateTimeZone;
27  import org.joda.time.Instant;
28  import org.joda.time.MutableDateTime;
29  import org.joda.time.ReadableInstant;
30  import org.joda.time.chrono.ISOChronology;
31  import org.joda.time.field.FieldUtils;
32  import org.joda.time.format.DateTimeFormatter;
33  import org.joda.time.format.ISODateTimeFormat;
34  
35  /**
36   * AbstractInstant provides the common behaviour for instant classes.
37   * <p>
38   * This class has no concept of a chronology, all methods work on the
39   * millisecond instant.
40   * <p>
41   * This class should generally not be used directly by API users. The 
42   * {@link ReadableInstant} interface should be used when different 
43   * kinds of date/time objects are to be referenced.
44   * <p>
45   * Whenever you want to implement <code>ReadableInstant</code> you should
46   * extend this class.
47   * <p>
48   * AbstractInstant itself is thread-safe and immutable, but subclasses may be
49   * mutable and not thread-safe.
50   *
51   * @author Stephen Colebourne
52   * @author Brian S O'Neill
53   * @since 1.0
54   */
55  public abstract class AbstractInstant implements ReadableInstant {
56  
57      /**
58       * Constructor.
59       */
60      protected AbstractInstant() {
61          super();
62      }
63  
64      //-----------------------------------------------------------------------
65      /**
66       * Gets the time zone of the instant from the chronology.
67       * 
68       * @return the DateTimeZone that the instant is using, never null
69       */
70      public DateTimeZone getZone() {
71          return getChronology().getZone();
72      }
73  
74      /**
75       * Get the value of one of the fields of a datetime using the chronology of the instant.
76       * <p>
77       * This method uses the chronology of the instant to obtain the value.
78       * For example:
79       * <pre>
80       * DateTime dt = new DateTime();
81       * int year = dt.get(DateTimeFieldType.year());
82       * </pre>
83       *
84       * @param type  a field type, usually obtained from DateTimeFieldType, not null
85       * @return the value of that field
86       * @throws IllegalArgumentException if the field type is null
87       */
88      public int get(DateTimeFieldType type) {
89          if (type == null) {
90              throw new IllegalArgumentException("The DateTimeFieldType must not be null");
91          }
92          return type.getField(getChronology()).get(getMillis());
93      }
94  
95      /**
96       * Checks if the field type specified is supported by this instant and chronology.
97       * This can be used to avoid exceptions in {@link #get(DateTimeFieldType)}.
98       *
99       * @param type  a field type, usually obtained from DateTimeFieldType
100      * @return true if the field type is supported
101      */
102     public boolean isSupported(DateTimeFieldType type) {
103         if (type == null) {
104             return false;
105         }
106         return type.getField(getChronology()).isSupported();
107     }
108 
109     /**
110      * Get the value of one of the fields of a datetime.
111      * <p>
112      * This could be used to get a field using a different Chronology.
113      * For example:
114      * <pre>
115      * Instant dt = new Instant();
116      * int gjYear = dt.get(Chronology.getCoptic().year());
117      * </pre>
118      * 
119      * @param field  the DateTimeField to use, not null
120      * @return the value
121      * @throws IllegalArgumentException if the field is null
122      */
123     public int get(DateTimeField field) {
124         if (field == null) {
125             throw new IllegalArgumentException("The DateTimeField must not be null");
126         }
127         return field.get(getMillis());
128     }
129 
130     //-----------------------------------------------------------------------
131     /**
132      * Get this object as an Instant.
133      * 
134      * @return an Instant using the same millis
135      */
136     public Instant toInstant() {
137         return new Instant(getMillis());
138     }
139 
140     /**
141      * Get this object as a DateTime in the same zone.
142      *
143      * @return a DateTime using the same millis
144      */
145     public DateTime toDateTime() {
146         return new DateTime(getMillis(), getZone());
147     }
148 
149     /**
150      * Get this object as a DateTime using ISOChronology in the same zone.
151      *
152      * @return a DateTime using the same millis with ISOChronology
153      */
154     public DateTime toDateTimeISO() {
155         return new DateTime(getMillis(), ISOChronology.getInstance(getZone()));
156     }
157 
158     /**
159      * Get this object as a DateTime using the same chronology but a different zone.
160      * 
161      * @param zone time zone to apply, or default if null
162      * @return a DateTime using the same millis
163      */
164     public DateTime toDateTime(DateTimeZone zone) {
165         Chronology chrono = DateTimeUtils.getChronology(getChronology());
166         chrono = chrono.withZone(zone);
167         return new DateTime(getMillis(), chrono);
168     }
169 
170     /**
171      * Get this object as a DateTime using the given chronology and its zone.
172      * 
173      * @param chronology chronology to apply, or ISOChronology if null
174      * @return a DateTime using the same millis
175      */
176     public DateTime toDateTime(Chronology chronology) {
177         return new DateTime(getMillis(), chronology);
178     }
179 
180     // NOTE: Although the toMutableDateTime methods could check to see if this
181     // is already a MutableDateTime and return this casted, it makes it too
182     // easy to mistakenly modify ReadableDateTime input parameters. Always
183     // returning a copy prevents this.
184 
185     /**
186      * Get this object as a MutableDateTime in the same zone.
187      *
188      * @return a MutableDateTime using the same millis
189      */
190     public MutableDateTime toMutableDateTime() {
191         return new MutableDateTime(getMillis(), getZone());
192     }
193 
194     /**
195      * Get this object as a MutableDateTime using ISOChronology in the same zone.
196      *
197      * @return a MutableDateTime using the same millis with ISOChronology
198      */
199     public MutableDateTime toMutableDateTimeISO() {
200         return new MutableDateTime(getMillis(), ISOChronology.getInstance(getZone()));
201     }
202 
203     /**
204      * Get this object as a MutableDateTime using the same chronology but a different zone.
205      * 
206      * @param zone time zone to apply, or default if null
207      * @return a MutableDateTime using the same millis
208      */
209     public MutableDateTime toMutableDateTime(DateTimeZone zone) {
210         Chronology chrono = DateTimeUtils.getChronology(getChronology());
211         chrono = chrono.withZone(zone);
212         return new MutableDateTime(getMillis(), chrono);
213     }
214 
215     /**
216      * Get this object as a MutableDateTime using the given chronology and its zone.
217      * 
218      * @param chronology chronology to apply, or ISOChronology if null
219      * @return a MutableDateTime using the same millis
220      */
221     public MutableDateTime toMutableDateTime(Chronology chronology) {
222         return new MutableDateTime(getMillis(), chronology);
223     }
224 
225     //-----------------------------------------------------------------------
226     /**
227      * Get the date time as a <code>java.util.Date</code>.
228      * <p>
229      * The <code>Date</code> object created has exactly the same millisecond
230      * instant as this object.
231      *
232      * @return a Date initialised with this datetime
233      */
234     public Date toDate() {
235         return new Date(getMillis());
236     }
237 
238     //-----------------------------------------------------------------------
239     /**
240      * Compares this object with the specified object for equality based
241      * on the millisecond instant, chronology and time zone.
242      * <p>
243      * Two objects which represent the same instant in time, but are in
244      * different time zones (based on time zone id), will be considered to
245      * be different. Only two objects with the same {@link DateTimeZone},
246      * {@link Chronology} and instant are equal.
247      * <p>
248      * See {@link #isEqual(ReadableInstant)} for an equals method that
249      * ignores the Chronology and time zone.
250      * <p>
251      * All ReadableInstant instances are accepted.
252      *
253      * @param readableInstant  a readable instant to check against
254      * @return true if millisecond and chronology are equal, false if
255      *  not or the instant is null or of an incorrect type
256      */
257     public boolean equals(Object readableInstant) {
258         // must be to fulfil ReadableInstant contract
259         if (this == readableInstant) {
260             return true;
261         }
262         if (readableInstant instanceof ReadableInstant == false) {
263             return false;
264         }
265         ReadableInstant otherInstant = (ReadableInstant) readableInstant;
266         return
267             getMillis() == otherInstant.getMillis() &&
268             FieldUtils.equals(getChronology(), otherInstant.getChronology());
269     }
270 
271     /**
272      * Gets a hash code for the instant as defined in <code>ReadableInstant</code>.
273      *
274      * @return a suitable hash code
275      */
276     public int hashCode() {
277         // must be to fulfil ReadableInstant contract
278         return
279             ((int) (getMillis() ^ (getMillis() >>> 32))) +
280             (getChronology().hashCode());
281     }
282 
283     /**
284      * Compares this object with the specified object for ascending
285      * millisecond instant order. This ordering is inconsistent with
286      * equals, as it ignores the Chronology.
287      * <p>
288      * All ReadableInstant instances are accepted.
289      *
290      * @param other  a readable instant to check against
291      * @return negative value if this is less, 0 if equal, or positive value if greater
292      * @throws NullPointerException if the object is null
293      * @throws ClassCastException if the object type is not supported
294      */
295     public int compareTo(ReadableInstant other) {
296         if (this == other) {
297             return 0;
298         }
299         
300         long otherMillis = other.getMillis();
301         long thisMillis = getMillis();
302         
303         // cannot do (thisMillis - otherMillis) as can overflow
304         if (thisMillis == otherMillis) {
305             return 0;
306         }
307         if (thisMillis < otherMillis) {
308             return -1;
309         } else {
310             return 1;
311         }
312     }
313 
314     //-----------------------------------------------------------------------
315     /**
316      * Is this instant after the millisecond instant passed in
317      * comparing solely by millisecond.
318      *
319      * @param instant  a millisecond instant to check against
320      * @return true if this instant is after the instant passed in
321      */
322     public boolean isAfter(long instant) {
323         return (getMillis() > instant);
324     }
325 
326     /**
327      * Is this instant after the current instant
328      * comparing solely by millisecond.
329      * 
330      * @return true if this instant is after the current instant
331      */
332     public boolean isAfterNow() {
333         return isAfter(DateTimeUtils.currentTimeMillis());
334     }
335 
336     /**
337      * Is this instant after the instant passed in
338      * comparing solely by millisecond.
339      *
340      * @param instant  an instant to check against, null means now
341      * @return true if the instant is after the instant passed in
342      */
343     public boolean isAfter(ReadableInstant instant) {
344         long instantMillis = DateTimeUtils.getInstantMillis(instant);
345         return isAfter(instantMillis);
346     }
347 
348     //-----------------------------------------------------------------------
349     /**
350      * Is this instant before the millisecond instant passed in
351      * comparing solely by millisecond.
352      *
353      * @param instant  a millisecond instant to check against
354      * @return true if this instant is before the instant passed in
355      */
356     public boolean isBefore(long instant) {
357         return (getMillis() < instant);
358     }
359 
360     /**
361      * Is this instant before the current instant
362      * comparing solely by millisecond.
363      * 
364      * @return true if this instant is before the current instant
365      */
366     public boolean isBeforeNow() {
367         return isBefore(DateTimeUtils.currentTimeMillis());
368     }
369 
370     /**
371      * Is this instant before the instant passed in
372      * comparing solely by millisecond.
373      *
374      * @param instant  an instant to check against, null means now
375      * @return true if the instant is before the instant passed in
376      */
377     public boolean isBefore(ReadableInstant instant) {
378         long instantMillis = DateTimeUtils.getInstantMillis(instant);
379         return isBefore(instantMillis);
380     }
381 
382     //-----------------------------------------------------------------------
383     /**
384      * Is this instant equal to the millisecond instant passed in
385      * comparing solely by millisecond.
386      *
387      * @param instant  a millisecond instant to check against
388      * @return true if this instant is before the instant passed in
389      */
390     public boolean isEqual(long instant) {
391         return (getMillis() == instant);
392     }
393 
394     /**
395      * Is this instant equal to the current instant
396      * comparing solely by millisecond.
397      * 
398      * @return true if this instant is before the current instant
399      */
400     public boolean isEqualNow() {
401         return isEqual(DateTimeUtils.currentTimeMillis());
402     }
403 
404     /**
405      * Is this instant equal to the instant passed in
406      * comparing solely by millisecond.
407      *
408      * @param instant  an instant to check against, null means now
409      * @return true if the instant is equal to the instant passed in
410      */
411     public boolean isEqual(ReadableInstant instant) {
412         long instantMillis = DateTimeUtils.getInstantMillis(instant);
413         return isEqual(instantMillis);
414     }
415 
416     //-----------------------------------------------------------------------
417     /**
418      * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ).
419      * 
420      * @return ISO8601 time formatted string.
421      */
422     @ToString
423     public String toString() {
424         return ISODateTimeFormat.dateTime().print(this);
425     }
426 
427     //-----------------------------------------------------------------------
428     /**
429      * Uses the specified formatter to convert this partial to a String.
430      *
431      * @param formatter  the formatter to use, null means use <code>toString()</code>.
432      * @return the formatted string
433      * @since 1.1
434      */
435     public String toString(DateTimeFormatter formatter) {
436         if (formatter == null) {
437             return toString();
438         }
439         return formatter.print(this);
440     }
441 
442 }