001: /*
002: * Copyright 2001-2006 Stephen Colebourne
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.joda.time.base;
017:
018: import java.util.Date;
019:
020: import org.joda.time.Chronology;
021: import org.joda.time.DateTime;
022: import org.joda.time.DateTimeField;
023: import org.joda.time.DateTimeFieldType;
024: import org.joda.time.DateTimeUtils;
025: import org.joda.time.DateTimeZone;
026: import org.joda.time.Instant;
027: import org.joda.time.MutableDateTime;
028: import org.joda.time.ReadableInstant;
029: import org.joda.time.chrono.ISOChronology;
030: import org.joda.time.field.FieldUtils;
031: import org.joda.time.format.DateTimeFormatter;
032: import org.joda.time.format.ISODateTimeFormat;
033:
034: /**
035: * AbstractInstant provides the common behaviour for instant classes.
036: * <p>
037: * This class has no concept of a chronology, all methods work on the
038: * millisecond instant.
039: * <p>
040: * This class should generally not be used directly by API users. The
041: * {@link ReadableInstant} interface should be used when different
042: * kinds of date/time objects are to be referenced.
043: * <p>
044: * Whenever you want to implement <code>ReadableInstant</code> you should
045: * extend this class.
046: * <p>
047: * AbstractInstant itself is thread-safe and immutable, but subclasses may be
048: * mutable and not thread-safe.
049: *
050: * @author Stephen Colebourne
051: * @author Brian S O'Neill
052: * @since 1.0
053: */
054: public abstract class AbstractInstant implements ReadableInstant {
055:
056: /**
057: * Constructor.
058: */
059: protected AbstractInstant() {
060: super ();
061: }
062:
063: //-----------------------------------------------------------------------
064: /**
065: * Gets the time zone of the instant from the chronology.
066: *
067: * @return the DateTimeZone that the instant is using, never null
068: */
069: public DateTimeZone getZone() {
070: return getChronology().getZone();
071: }
072:
073: /**
074: * Get the value of one of the fields of a datetime using the chronology of the instant.
075: * <p>
076: * This method uses the chronology of the instant to obtain the value.
077: * For example:
078: * <pre>
079: * DateTime dt = new DateTime();
080: * int year = dt.get(DateTimeFieldType.year());
081: * </pre>
082: *
083: * @param type a field type, usually obtained from DateTimeFieldType, not null
084: * @return the value of that field
085: * @throws IllegalArgumentException if the field type is null
086: */
087: public int get(DateTimeFieldType type) {
088: if (type == null) {
089: throw new IllegalArgumentException(
090: "The DateTimeFieldType must not be null");
091: }
092: return type.getField(getChronology()).get(getMillis());
093: }
094:
095: /**
096: * Checks if the field type specified is supported by this instant and chronology.
097: * This can be used to avoid exceptions in {@link #get(DateTimeFieldType)}.
098: *
099: * @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(
126: "The DateTimeField must not be null");
127: }
128: return field.get(getMillis());
129: }
130:
131: //-----------------------------------------------------------------------
132: /**
133: * Get this object as an Instant.
134: *
135: * @return an Instant using the same millis
136: */
137: public Instant toInstant() {
138: return new Instant(getMillis());
139: }
140:
141: /**
142: * Get this object as a DateTime in the same zone.
143: *
144: * @return a DateTime using the same millis
145: */
146: public DateTime toDateTime() {
147: return new DateTime(getMillis(), getZone());
148: }
149:
150: /**
151: * Get this object as a DateTime using ISOChronology in the same zone.
152: *
153: * @return a DateTime using the same millis with ISOChronology
154: */
155: public DateTime toDateTimeISO() {
156: return new DateTime(getMillis(), ISOChronology
157: .getInstance(getZone()));
158: }
159:
160: /**
161: * Get this object as a DateTime using the same chronology but a different zone.
162: *
163: * @param zone time zone to apply, or default if null
164: * @return a DateTime using the same millis
165: */
166: public DateTime toDateTime(DateTimeZone zone) {
167: Chronology chrono = DateTimeUtils
168: .getChronology(getChronology());
169: chrono = chrono.withZone(zone);
170: return new DateTime(getMillis(), chrono);
171: }
172:
173: /**
174: * Get this object as a DateTime using the given chronology and its zone.
175: *
176: * @param chronology chronology to apply, or ISOChronology if null
177: * @return a DateTime using the same millis
178: */
179: public DateTime toDateTime(Chronology chronology) {
180: return new DateTime(getMillis(), chronology);
181: }
182:
183: // NOTE: Although the toMutableDateTime methods could check to see if this
184: // is already a MutableDateTime and return this casted, it makes it too
185: // easy to mistakenly modify ReadableDateTime input parameters. Always
186: // returning a copy prevents this.
187:
188: /**
189: * Get this object as a MutableDateTime in the same zone.
190: *
191: * @return a MutableDateTime using the same millis
192: */
193: public MutableDateTime toMutableDateTime() {
194: return new MutableDateTime(getMillis(), getZone());
195: }
196:
197: /**
198: * Get this object as a MutableDateTime using ISOChronology in the same zone.
199: *
200: * @return a MutableDateTime using the same millis with ISOChronology
201: */
202: public MutableDateTime toMutableDateTimeISO() {
203: return new MutableDateTime(getMillis(), ISOChronology
204: .getInstance(getZone()));
205: }
206:
207: /**
208: * Get this object as a MutableDateTime using the same chronology but a different zone.
209: *
210: * @param zone time zone to apply, or default if null
211: * @return a MutableDateTime using the same millis
212: */
213: public MutableDateTime toMutableDateTime(DateTimeZone zone) {
214: Chronology chrono = DateTimeUtils
215: .getChronology(getChronology());
216: chrono = chrono.withZone(zone);
217: return new MutableDateTime(getMillis(), chrono);
218: }
219:
220: /**
221: * Get this object as a MutableDateTime using the given chronology and its zone.
222: *
223: * @param chronology chronology to apply, or ISOChronology if null
224: * @return a MutableDateTime using the same millis
225: */
226: public MutableDateTime toMutableDateTime(Chronology chronology) {
227: return new MutableDateTime(getMillis(), chronology);
228: }
229:
230: //-----------------------------------------------------------------------
231: /**
232: * Get the date time as a <code>java.util.Date</code>.
233: * <p>
234: * The <code>Date</code> object created has exactly the same millisecond
235: * instant as this object.
236: *
237: * @return a Date initialised with this datetime
238: */
239: public Date toDate() {
240: return new Date(getMillis());
241: }
242:
243: //-----------------------------------------------------------------------
244: /**
245: * Compares this object with the specified object for equality based
246: * on the millisecond instant, chronology and time zone.
247: * <p>
248: * Two objects which represent the same instant in time, but are in
249: * different time zones (based on time zone id), will be considered to
250: * be different. Only two objects with the same {@link DateTimeZone},
251: * {@link Chronology} and instant are equal.
252: * <p>
253: * See {@link #isEqual(ReadableInstant)} for an equals method that
254: * ignores the Chronology and time zone.
255: * <p>
256: * All ReadableInstant instances are accepted.
257: *
258: * @param readableInstant a readable instant to check against
259: * @return true if millisecond and chronology are equal, false if
260: * not or the instant is null or of an incorrect type
261: */
262: public boolean equals(Object readableInstant) {
263: // must be to fulfil ReadableInstant contract
264: if (this == readableInstant) {
265: return true;
266: }
267: if (readableInstant instanceof ReadableInstant == false) {
268: return false;
269: }
270: ReadableInstant otherInstant = (ReadableInstant) readableInstant;
271: return getMillis() == otherInstant.getMillis()
272: && FieldUtils.equals(getChronology(), otherInstant
273: .getChronology());
274: }
275:
276: /**
277: * Gets a hash code for the instant as defined in <code>ReadableInstant</code>.
278: *
279: * @return a suitable hash code
280: */
281: public int hashCode() {
282: // must be to fulfil ReadableInstant contract
283: return ((int) (getMillis() ^ (getMillis() >>> 32)))
284: + (getChronology().hashCode());
285: }
286:
287: /**
288: * Compares this object with the specified object for ascending
289: * millisecond instant order. This ordering is inconsistent with
290: * equals, as it ignores the Chronology.
291: * <p>
292: * All ReadableInstant instances are accepted.
293: *
294: * @param instant a readable instant to check against
295: * @return negative value if this is less, 0 if equal, or positive value if greater
296: * @throws NullPointerException if the object is null
297: * @throws ClassCastException if the object type is not supported
298: */
299: public int compareTo(Object instant) {
300: if (this == instant) {
301: return 0;
302: }
303:
304: ReadableInstant otherInstant = (ReadableInstant) instant;
305:
306: long otherMillis = otherInstant.getMillis();
307: long this Millis = getMillis();
308:
309: // cannot do (thisMillis - otherMillis) as can overflow
310: if (this Millis == otherMillis) {
311: return 0;
312: }
313: if (this Millis < otherMillis) {
314: return -1;
315: } else {
316: return 1;
317: }
318: }
319:
320: //-----------------------------------------------------------------------
321: /**
322: * Is this instant after the millisecond instant passed in
323: * comparing solely by millisecond.
324: *
325: * @param instant a millisecond instant to check against
326: * @return true if this instant is after the instant passed in
327: */
328: public boolean isAfter(long instant) {
329: return (getMillis() > instant);
330: }
331:
332: /**
333: * Is this instant after the current instant
334: * comparing solely by millisecond.
335: *
336: * @return true if this instant is after the current instant
337: */
338: public boolean isAfterNow() {
339: return isAfter(DateTimeUtils.currentTimeMillis());
340: }
341:
342: /**
343: * Is this instant after the instant passed in
344: * comparing solely by millisecond.
345: *
346: * @param instant an instant to check against, null means now
347: * @return true if the instant is after the instant passed in
348: */
349: public boolean isAfter(ReadableInstant instant) {
350: long instantMillis = DateTimeUtils.getInstantMillis(instant);
351: return isAfter(instantMillis);
352: }
353:
354: //-----------------------------------------------------------------------
355: /**
356: * Is this instant before the millisecond instant passed in
357: * comparing solely by millisecond.
358: *
359: * @param instant a millisecond instant to check against
360: * @return true if this instant is before the instant passed in
361: */
362: public boolean isBefore(long instant) {
363: return (getMillis() < instant);
364: }
365:
366: /**
367: * Is this instant before the current instant
368: * comparing solely by millisecond.
369: *
370: * @return true if this instant is before the current instant
371: */
372: public boolean isBeforeNow() {
373: return isBefore(DateTimeUtils.currentTimeMillis());
374: }
375:
376: /**
377: * Is this instant before the instant passed in
378: * comparing solely by millisecond.
379: *
380: * @param instant an instant to check against, null means now
381: * @return true if the instant is before the instant passed in
382: */
383: public boolean isBefore(ReadableInstant instant) {
384: long instantMillis = DateTimeUtils.getInstantMillis(instant);
385: return isBefore(instantMillis);
386: }
387:
388: //-----------------------------------------------------------------------
389: /**
390: * Is this instant equal to the millisecond instant passed in
391: * comparing solely by millisecond.
392: *
393: * @param instant a millisecond instant to check against
394: * @return true if this instant is before the instant passed in
395: */
396: public boolean isEqual(long instant) {
397: return (getMillis() == instant);
398: }
399:
400: /**
401: * Is this instant equal to the current instant
402: * comparing solely by millisecond.
403: *
404: * @return true if this instant is before the current instant
405: */
406: public boolean isEqualNow() {
407: return isEqual(DateTimeUtils.currentTimeMillis());
408: }
409:
410: /**
411: * Is this instant equal to the instant passed in
412: * comparing solely by millisecond.
413: *
414: * @param instant an instant to check against, null means now
415: * @return true if the instant is equal to the instant passed in
416: */
417: public boolean isEqual(ReadableInstant instant) {
418: long instantMillis = DateTimeUtils.getInstantMillis(instant);
419: return isEqual(instantMillis);
420: }
421:
422: //-----------------------------------------------------------------------
423: /**
424: * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZ).
425: *
426: * @return ISO8601 time formatted string.
427: */
428: public String toString() {
429: return ISODateTimeFormat.dateTime().print(this );
430: }
431:
432: //-----------------------------------------------------------------------
433: /**
434: * Uses the specified formatter to convert this partial to a String.
435: *
436: * @param formatter the formatter to use, null means use <code>toString()</code>.
437: * @return the formatted string
438: * @since 1.1
439: */
440: public String toString(DateTimeFormatter formatter) {
441: if (formatter == null) {
442: return toString();
443: }
444: return formatter.print(this);
445: }
446:
447: }
|