001: /*
002: * Copyright 2001-2005 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.field;
017:
018: import java.io.Serializable;
019: import java.util.Locale;
020:
021: import org.joda.time.Chronology;
022: import org.joda.time.DateTimeField;
023: import org.joda.time.DateTimeFieldType;
024: import org.joda.time.DateTimeUtils;
025: import org.joda.time.DurationField;
026: import org.joda.time.Interval;
027: import org.joda.time.ReadableInstant;
028: import org.joda.time.ReadablePartial;
029:
030: /**
031: * AbstractReadableInstantFieldProperty is a base class for binding a
032: * ReadableInstant to a DateTimeField.
033: * <p>
034: * It allows the date and time manipulation code to be field based yet
035: * still easy to use.
036: * <p>
037: * AbstractReadableInstantFieldProperty itself is thread-safe and immutable,
038: * but the ReadableInstant being operated on may be mutable and not
039: * thread-safe.
040: *
041: * @author Stephen Colebourne
042: * @author Brian S O'Neill
043: * @author Mike Schrag
044: * @since 1.0
045: */
046: public abstract class AbstractReadableInstantFieldProperty implements
047: Serializable {
048:
049: /** Serialization version. */
050: private static final long serialVersionUID = 1971226328211649661L;
051:
052: /**
053: * Constructor.
054: */
055: public AbstractReadableInstantFieldProperty() {
056: super ();
057: }
058:
059: //-----------------------------------------------------------------------
060: /**
061: * Gets the field being used.
062: *
063: * @return the field
064: */
065: public abstract DateTimeField getField();
066:
067: /**
068: * Gets the field type being used.
069: *
070: * @return the field type
071: */
072: public DateTimeFieldType getFieldType() {
073: return getField().getType();
074: }
075:
076: /**
077: * Gets the name of the field.
078: *
079: * @return the field name
080: */
081: public String getName() {
082: return getField().getName();
083: }
084:
085: /**
086: * Gets the milliseconds of the datetime that this property is linked to.
087: *
088: * @return the milliseconds
089: */
090: protected abstract long getMillis();
091:
092: /**
093: * Gets the chronology of the datetime that this property is linked to.
094: * <p>
095: * This implementation throws UnsupportedOperationException, and must be
096: * implemented by subclasses to enable the equals() and hashCode() methods.
097: *
098: * @return the chronology
099: * @since 1.4
100: */
101: protected Chronology getChronology() {
102: throw new UnsupportedOperationException(
103: "The method getChronology() was added in v1.4 and needs "
104: + "to be implemented by subclasses of AbstractReadableInstantFieldProperty");
105: }
106:
107: //-----------------------------------------------------------------------
108: /**
109: * Gets the value of this property from the instant.
110: * <p>
111: * For example, the following two lines of code are equivalent:
112: * <pre>
113: * datetime.getDayOfMonth();
114: * datetime.dayOfMonth().get();
115: * </pre>
116: *
117: * @return the current value
118: * @see DateTimeField#get
119: */
120: public int get() {
121: return getField().get(getMillis());
122: }
123:
124: /**
125: * Gets the value of this property from the instant as a string.
126: * <p>
127: * This method returns the value converted to a <code>String</code>
128: * using <code>Integer.toString</code>. This method does NOT return
129: * textual descriptions such as 'Monday' or 'January'.
130: * See {@link #getAsText()} and {@link #getAsShortText()} for those.
131: *
132: * @return the current value
133: * @see DateTimeField#get
134: * @since 1.1
135: */
136: public String getAsString() {
137: return Integer.toString(get());
138: }
139:
140: /**
141: * Gets the textual value of this property from the instant as a
142: * string in the default locale.
143: * <p>
144: * This method returns the value converted to a <code>String</code>
145: * returning the appropriate textual description wherever possible.
146: * Thus, a day of week of 1 would return 'Monday' in English.
147: *
148: * @return the current text value
149: * @see DateTimeField#getAsText
150: */
151: public String getAsText() {
152: return getAsText(null);
153: }
154:
155: /**
156: * Gets the textual value of this property from the instant as a
157: * string in the specified locale.
158: * <p>
159: * This method returns the value converted to a <code>String</code>
160: * returning the appropriate textual description wherever possible.
161: * Thus, a day of week of 1 would return 'Monday' in English.
162: *
163: * @param locale locale to use for selecting a text symbol, null means default
164: * @return the current text value
165: * @see DateTimeField#getAsText
166: */
167: public String getAsText(Locale locale) {
168: return getField().getAsText(getMillis(), locale);
169: }
170:
171: /**
172: * Gets the short textual value of this property from the instant as a
173: * string in the default locale.
174: * <p>
175: * This method returns the value converted to a <code>String</code>
176: * returning the appropriate textual description wherever possible.
177: * Thus, a day of week of 1 would return 'Mon' in English.
178: *
179: * @return the current text value
180: * @see DateTimeField#getAsShortText
181: */
182: public String getAsShortText() {
183: return getAsShortText(null);
184: }
185:
186: /**
187: * Gets the short textual value of this property from the instant as a
188: * string in the specified locale.
189: * <p>
190: * This method returns the value converted to a <code>String</code>
191: * returning the appropriate textual description wherever possible.
192: * Thus, a day of week of 1 would return 'Mon' in English.
193: *
194: * @param locale locale to use for selecting a text symbol, null means default
195: * @return the current text value
196: * @see DateTimeField#getAsShortText
197: */
198: public String getAsShortText(Locale locale) {
199: return getField().getAsShortText(getMillis(), locale);
200: }
201:
202: //-----------------------------------------------------------------------
203: /**
204: * Returns the difference between this field property instant and the one
205: * passed in, in the units of this field. The sign of the difference
206: * matches that of compareTo. In other words, this field property's instant
207: * is the minuend.
208: *
209: * @param instant the subtrahend, null means now
210: * @return the difference in the units of this field
211: * @see DateTimeField#getDifference
212: */
213: public int getDifference(ReadableInstant instant) {
214: if (instant == null) {
215: return getField().getDifference(getMillis(),
216: DateTimeUtils.currentTimeMillis());
217: }
218: return getField().getDifference(getMillis(),
219: instant.getMillis());
220: }
221:
222: /**
223: * Returns the difference between this field property instant and the one
224: * passed in, in the units of this field. The sign of the difference
225: * matches that of compareTo. In other words, this field property's instant
226: * is the minuend.
227: *
228: * @param instant the subtrahend, null means now
229: * @return the difference in the units of this field
230: * @see DateTimeField#getDifference
231: */
232: public long getDifferenceAsLong(ReadableInstant instant) {
233: if (instant == null) {
234: return getField().getDifferenceAsLong(getMillis(),
235: DateTimeUtils.currentTimeMillis());
236: }
237: return getField().getDifferenceAsLong(getMillis(),
238: instant.getMillis());
239: }
240:
241: //-----------------------------------------------------------------------
242: /**
243: * Returns the duration per unit value of this field. For example, if this
244: * field represents "hour of day", then the duration is an hour.
245: *
246: * @return the duration of this field, or UnsupportedDurationField
247: */
248: public DurationField getDurationField() {
249: return getField().getDurationField();
250: }
251:
252: /**
253: * Returns the range duration of this field. For example, if this field
254: * represents "hour of day", then the range duration is a day.
255: *
256: * @return the range duration of this field, or null if field has no range
257: */
258: public DurationField getRangeDurationField() {
259: return getField().getRangeDurationField();
260: }
261:
262: /**
263: * Gets whether this field is leap.
264: *
265: * @return true if a leap field
266: * @see DateTimeField#isLeap
267: */
268: public boolean isLeap() {
269: return getField().isLeap(getMillis());
270: }
271:
272: /**
273: * Gets the amount by which this field is leap.
274: *
275: * @return the amount by which the field is leap
276: * @see DateTimeField#getLeapAmount
277: */
278: public int getLeapAmount() {
279: return getField().getLeapAmount(getMillis());
280: }
281:
282: /**
283: * If this field were to leap, then it would be in units described by the
284: * returned duration. If this field doesn't ever leap, null is returned.
285: */
286: public DurationField getLeapDurationField() {
287: return getField().getLeapDurationField();
288: }
289:
290: //-----------------------------------------------------------------------
291: /**
292: * Gets the minimum value for the field ignoring the current time.
293: *
294: * @return the minimum value
295: * @see DateTimeField#getMinimumValue
296: */
297: public int getMinimumValueOverall() {
298: return getField().getMinimumValue();
299: }
300:
301: /**
302: * Gets the minimum value for the field.
303: *
304: * @return the minimum value
305: * @see DateTimeField#getMinimumValue
306: */
307: public int getMinimumValue() {
308: return getField().getMinimumValue(getMillis());
309: }
310:
311: /**
312: * Gets the maximum value for the field ignoring the current time.
313: *
314: * @return the maximum value
315: * @see DateTimeField#getMaximumValue
316: */
317: public int getMaximumValueOverall() {
318: return getField().getMaximumValue();
319: }
320:
321: /**
322: * Gets the maximum value for the field.
323: *
324: * @return the maximum value
325: * @see DateTimeField#getMaximumValue
326: */
327: public int getMaximumValue() {
328: return getField().getMaximumValue(getMillis());
329: }
330:
331: /**
332: * Gets the maximum text length for the field.
333: *
334: * @param locale optional locale to use for selecting a text symbol
335: * @return the maximum length
336: * @see DateTimeField#getMaximumTextLength
337: */
338: public int getMaximumTextLength(Locale locale) {
339: return getField().getMaximumTextLength(locale);
340: }
341:
342: /**
343: * Gets the maximum short text length for the field.
344: *
345: * @param locale optional locale to use for selecting a text symbol
346: * @return the maximum length
347: * @see DateTimeField#getMaximumShortTextLength
348: */
349: public int getMaximumShortTextLength(Locale locale) {
350: return getField().getMaximumShortTextLength(locale);
351: }
352:
353: /**
354: * Returns the fractional duration milliseconds of this field.
355: *
356: * @see DateTimeField#remainder
357: * @return remainder duration, in milliseconds
358: */
359: public long remainder() {
360: return getField().remainder(getMillis());
361: }
362:
363: /**
364: * Returns the interval that represents the range of the minimum
365: * and maximum values of this field.
366: * <p>
367: * For example, <code>datetime.monthOfYear().toInterval()</code>
368: * will return an interval over the whole month.
369: *
370: * @return the interval of this field
371: * @since 1.2
372: */
373: public Interval toInterval() {
374: DateTimeField field = getField();
375: long start = field.roundFloor(getMillis());
376: long end = field.add(start, 1);
377: Interval interval = new Interval(start, end);
378: return interval;
379: }
380:
381: //-----------------------------------------------------------------------
382: /**
383: * Compare this field to the same field on another instant.
384: * <p>
385: * The comparison is based on the value of the same field type, irrespective
386: * of any difference in chronology. Thus, if this property represents the
387: * hourOfDay field, then the hourOfDay field of the other instant will be queried
388: * whether in the same chronology or not.
389: *
390: * @param instant the instant to compare to
391: * @return negative value if this is less, 0 if equal, or positive value if greater
392: * @throws IllegalArgumentException if the instant is null
393: */
394: public int compareTo(ReadableInstant instant) {
395: if (instant == null) {
396: throw new IllegalArgumentException(
397: "The instant must not be null");
398: }
399: int this Value = get();
400: int otherValue = instant.get(getFieldType());
401: if (this Value < otherValue) {
402: return -1;
403: } else if (this Value > otherValue) {
404: return 1;
405: } else {
406: return 0;
407: }
408: }
409:
410: //-----------------------------------------------------------------------
411: /**
412: * Compare this field to the same field on another partial instant.
413: * <p>
414: * The comparison is based on the value of the same field type, irrespective
415: * of any difference in chronology. Thus, if this property represents the
416: * hourOfDay field, then the hourOfDay field of the other partial will be queried
417: * whether in the same chronology or not.
418: *
419: * @param partial the partial to compare to
420: * @return negative value if this is less, 0 if equal, or positive value if greater
421: * @throws IllegalArgumentException if the partial is null
422: * @throws IllegalArgumentException if the partial doesn't support this field
423: */
424: public int compareTo(ReadablePartial partial) {
425: if (partial == null) {
426: throw new IllegalArgumentException(
427: "The partial must not be null");
428: }
429: int this Value = get();
430: int otherValue = partial.get(getFieldType());
431: if (this Value < otherValue) {
432: return -1;
433: } else if (this Value > otherValue) {
434: return 1;
435: } else {
436: return 0;
437: }
438: }
439:
440: //-----------------------------------------------------------------------
441: /**
442: * Compares this property to another.
443: *
444: * @param object the object to compare to
445: * @return true if equal
446: */
447: public boolean equals(Object object) {
448: if (this == object) {
449: return true;
450: }
451: if (object instanceof AbstractReadableInstantFieldProperty == false) {
452: return false;
453: }
454: AbstractReadableInstantFieldProperty other = (AbstractReadableInstantFieldProperty) object;
455: return get() == other.get()
456: && getFieldType().equals(other.getFieldType())
457: && FieldUtils.equals(getChronology(), other
458: .getChronology());
459: }
460:
461: /**
462: * Returns a hashcode compatible with the equals method.
463: *
464: * @return the hashcode
465: */
466: public int hashCode() {
467: return get() * 17 + getFieldType().hashCode()
468: + getChronology().hashCode();
469: }
470:
471: //-----------------------------------------------------------------------
472: /**
473: * Output a debugging string.
474: *
475: * @return debugging string
476: */
477: public String toString() {
478: return "Property[" + getName() + "]";
479: }
480:
481: }
|