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("The DateTimeFieldType must not be null");
090 }
091 return type.getField(getChronology()).get(getMillis());
092 }
093
094 /**
095 * Checks if the field type specified is supported by this instant and chronology.
096 * This can be used to avoid exceptions in {@link #get(DateTimeFieldType)}.
097 *
098 * @param type a field type, usually obtained from DateTimeFieldType
099 * @return true if the field type is supported
100 */
101 public boolean isSupported(DateTimeFieldType type) {
102 if (type == null) {
103 return false;
104 }
105 return type.getField(getChronology()).isSupported();
106 }
107
108 /**
109 * Get the value of one of the fields of a datetime.
110 * <p>
111 * This could be used to get a field using a different Chronology.
112 * For example:
113 * <pre>
114 * Instant dt = new Instant();
115 * int gjYear = dt.get(Chronology.getCoptic().year());
116 * </pre>
117 *
118 * @param field the DateTimeField to use, not null
119 * @return the value
120 * @throws IllegalArgumentException if the field is null
121 */
122 public int get(DateTimeField field) {
123 if (field == null) {
124 throw new IllegalArgumentException("The DateTimeField must not be null");
125 }
126 return field.get(getMillis());
127 }
128
129 //-----------------------------------------------------------------------
130 /**
131 * Get this object as an Instant.
132 *
133 * @return an Instant using the same millis
134 */
135 public Instant toInstant() {
136 return new Instant(getMillis());
137 }
138
139 /**
140 * Get this object as a DateTime in the same zone.
141 *
142 * @return a DateTime using the same millis
143 */
144 public DateTime toDateTime() {
145 return new DateTime(getMillis(), getZone());
146 }
147
148 /**
149 * Get this object as a DateTime using ISOChronology in the same zone.
150 *
151 * @return a DateTime using the same millis with ISOChronology
152 */
153 public DateTime toDateTimeISO() {
154 return new DateTime(getMillis(), ISOChronology.getInstance(getZone()));
155 }
156
157 /**
158 * Get this object as a DateTime using the same chronology but a different zone.
159 *
160 * @param zone time zone to apply, or default if null
161 * @return a DateTime using the same millis
162 */
163 public DateTime toDateTime(DateTimeZone zone) {
164 Chronology chrono = DateTimeUtils.getChronology(getChronology());
165 chrono = chrono.withZone(zone);
166 return new DateTime(getMillis(), chrono);
167 }
168
169 /**
170 * Get this object as a DateTime using the given chronology and its zone.
171 *
172 * @param chronology chronology to apply, or ISOChronology if null
173 * @return a DateTime using the same millis
174 */
175 public DateTime toDateTime(Chronology chronology) {
176 return new DateTime(getMillis(), chronology);
177 }
178
179 // NOTE: Although the toMutableDateTime methods could check to see if this
180 // is already a MutableDateTime and return this casted, it makes it too
181 // easy to mistakenly modify ReadableDateTime input parameters. Always
182 // returning a copy prevents this.
183
184 /**
185 * Get this object as a MutableDateTime in the same zone.
186 *
187 * @return a MutableDateTime using the same millis
188 */
189 public MutableDateTime toMutableDateTime() {
190 return new MutableDateTime(getMillis(), getZone());
191 }
192
193 /**
194 * Get this object as a MutableDateTime using ISOChronology in the same zone.
195 *
196 * @return a MutableDateTime using the same millis with ISOChronology
197 */
198 public MutableDateTime toMutableDateTimeISO() {
199 return new MutableDateTime(getMillis(), ISOChronology.getInstance(getZone()));
200 }
201
202 /**
203 * Get this object as a MutableDateTime using the same chronology but a different zone.
204 *
205 * @param zone time zone to apply, or default if null
206 * @return a MutableDateTime using the same millis
207 */
208 public MutableDateTime toMutableDateTime(DateTimeZone zone) {
209 Chronology chrono = DateTimeUtils.getChronology(getChronology());
210 chrono = chrono.withZone(zone);
211 return new MutableDateTime(getMillis(), chrono);
212 }
213
214 /**
215 * Get this object as a MutableDateTime using the given chronology and its zone.
216 *
217 * @param chronology chronology to apply, or ISOChronology if null
218 * @return a MutableDateTime using the same millis
219 */
220 public MutableDateTime toMutableDateTime(Chronology chronology) {
221 return new MutableDateTime(getMillis(), chronology);
222 }
223
224 //-----------------------------------------------------------------------
225 /**
226 * Get the date time as a <code>java.util.Date</code>.
227 * <p>
228 * The <code>Date</code> object created has exactly the same millisecond
229 * instant as this object.
230 *
231 * @return a Date initialised with this datetime
232 */
233 public Date toDate() {
234 return new Date(getMillis());
235 }
236
237 //-----------------------------------------------------------------------
238 /**
239 * Compares this object with the specified object for equality based
240 * on the millisecond instant, chronology and time zone.
241 * <p>
242 * Two objects which represent the same instant in time, but are in
243 * different time zones (based on time zone id), will be considered to
244 * be different. Only two objects with the same {@link DateTimeZone},
245 * {@link Chronology} and instant are equal.
246 * <p>
247 * See {@link #isEqual(ReadableInstant)} for an equals method that
248 * ignores the Chronology and time zone.
249 * <p>
250 * All ReadableInstant instances are accepted.
251 *
252 * @param readableInstant a readable instant to check against
253 * @return true if millisecond and chronology are equal, false if
254 * not or the instant is null or of an incorrect type
255 */
256 public boolean equals(Object readableInstant) {
257 // must be to fulfil ReadableInstant contract
258 if (this == readableInstant) {
259 return true;
260 }
261 if (readableInstant instanceof ReadableInstant == false) {
262 return false;
263 }
264 ReadableInstant otherInstant = (ReadableInstant) readableInstant;
265 return
266 getMillis() == otherInstant.getMillis() &&
267 FieldUtils.equals(getChronology(), otherInstant.getChronology());
268 }
269
270 /**
271 * Gets a hash code for the instant as defined in <code>ReadableInstant</code>.
272 *
273 * @return a suitable hash code
274 */
275 public int hashCode() {
276 // must be to fulfil ReadableInstant contract
277 return
278 ((int) (getMillis() ^ (getMillis() >>> 32))) +
279 (getChronology().hashCode());
280 }
281
282 /**
283 * Compares this object with the specified object for ascending
284 * millisecond instant order. This ordering is inconsistent with
285 * equals, as it ignores the Chronology.
286 * <p>
287 * All ReadableInstant instances are accepted.
288 *
289 * @param instant a readable instant to check against
290 * @return negative value if this is less, 0 if equal, or positive value if greater
291 * @throws NullPointerException if the object is null
292 * @throws ClassCastException if the object type is not supported
293 */
294 public int compareTo(Object instant) {
295 if (this == instant) {
296 return 0;
297 }
298
299 ReadableInstant otherInstant = (ReadableInstant) instant;
300
301 long otherMillis = otherInstant.getMillis();
302 long thisMillis = getMillis();
303
304 // cannot do (thisMillis - otherMillis) as can overflow
305 if (thisMillis == otherMillis) {
306 return 0;
307 }
308 if (thisMillis < otherMillis) {
309 return -1;
310 } else {
311 return 1;
312 }
313 }
314
315 //-----------------------------------------------------------------------
316 /**
317 * Is this instant after the millisecond instant passed in
318 * comparing solely by millisecond.
319 *
320 * @param instant a millisecond instant to check against
321 * @return true if this instant is after the instant passed in
322 */
323 public boolean isAfter(long instant) {
324 return (getMillis() > instant);
325 }
326
327 /**
328 * Is this instant after the current instant
329 * comparing solely by millisecond.
330 *
331 * @return true if this instant is after the current instant
332 */
333 public boolean isAfterNow() {
334 return isAfter(DateTimeUtils.currentTimeMillis());
335 }
336
337 /**
338 * Is this instant after the instant passed in
339 * comparing solely by millisecond.
340 *
341 * @param instant an instant to check against, null means now
342 * @return true if the instant is after the instant passed in
343 */
344 public boolean isAfter(ReadableInstant instant) {
345 long instantMillis = DateTimeUtils.getInstantMillis(instant);
346 return isAfter(instantMillis);
347 }
348
349 //-----------------------------------------------------------------------
350 /**
351 * Is this instant before the millisecond instant passed in
352 * comparing solely by millisecond.
353 *
354 * @param instant a millisecond instant to check against
355 * @return true if this instant is before the instant passed in
356 */
357 public boolean isBefore(long instant) {
358 return (getMillis() < instant);
359 }
360
361 /**
362 * Is this instant before the current instant
363 * comparing solely by millisecond.
364 *
365 * @return true if this instant is before the current instant
366 */
367 public boolean isBeforeNow() {
368 return isBefore(DateTimeUtils.currentTimeMillis());
369 }
370
371 /**
372 * Is this instant before the instant passed in
373 * comparing solely by millisecond.
374 *
375 * @param instant an instant to check against, null means now
376 * @return true if the instant is before the instant passed in
377 */
378 public boolean isBefore(ReadableInstant instant) {
379 long instantMillis = DateTimeUtils.getInstantMillis(instant);
380 return isBefore(instantMillis);
381 }
382
383 //-----------------------------------------------------------------------
384 /**
385 * Is this instant equal to the millisecond instant passed in
386 * comparing solely by millisecond.
387 *
388 * @param instant a millisecond instant to check against
389 * @return true if this instant is before the instant passed in
390 */
391 public boolean isEqual(long instant) {
392 return (getMillis() == instant);
393 }
394
395 /**
396 * Is this instant equal to the current instant
397 * comparing solely by millisecond.
398 *
399 * @return true if this instant is before the current instant
400 */
401 public boolean isEqualNow() {
402 return isEqual(DateTimeUtils.currentTimeMillis());
403 }
404
405 /**
406 * Is this instant equal to the instant passed in
407 * comparing solely by millisecond.
408 *
409 * @param instant an instant to check against, null means now
410 * @return true if the instant is equal to the instant passed in
411 */
412 public boolean isEqual(ReadableInstant instant) {
413 long instantMillis = DateTimeUtils.getInstantMillis(instant);
414 return isEqual(instantMillis);
415 }
416
417 //-----------------------------------------------------------------------
418 /**
419 * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ).
420 *
421 * @return ISO8601 time formatted string.
422 */
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 }