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 org.joda.time.DateTimeFieldType;
019: import org.joda.time.DurationField;
020: import org.joda.time.DurationFieldType;
021:
022: /**
023: * Abstract datetime field class that defines its own DurationField, which
024: * delegates back into this ImpreciseDateTimeField.
025: * <p>
026: * This DateTimeField is useful for defining DateTimeFields that are composed
027: * of imprecise durations. If both duration fields are precise, then a
028: * {@link PreciseDateTimeField} should be used instead.
029: * <p>
030: * When defining imprecise DateTimeFields where a matching DurationField is
031: * already available, just extend BaseDateTimeField directly so as not to
032: * create redundant DurationField instances.
033: * <p>
034: * ImpreciseDateTimeField is thread-safe and immutable, and its subclasses must
035: * be as well.
036: *
037: * @author Brian S O'Neill
038: * @see PreciseDateTimeField
039: * @since 1.0
040: */
041: public abstract class ImpreciseDateTimeField extends BaseDateTimeField {
042:
043: private static final long serialVersionUID = 7190739608550251860L;
044:
045: final long iUnitMillis;
046: private final DurationField iDurationField;
047:
048: /**
049: * Constructor.
050: *
051: * @param type the field type
052: * @param unitMillis the average duration unit milliseconds
053: */
054: public ImpreciseDateTimeField(DateTimeFieldType type,
055: long unitMillis) {
056: super (type);
057: iUnitMillis = unitMillis;
058: iDurationField = new LinkedDurationField(type.getDurationType());
059: }
060:
061: public abstract int get(long instant);
062:
063: public abstract long set(long instant, int value);
064:
065: public abstract long add(long instant, int value);
066:
067: public abstract long add(long instant, long value);
068:
069: /**
070: * Computes the difference between two instants, as measured in the units
071: * of this field. Any fractional units are dropped from the result. Calling
072: * getDifference reverses the effect of calling add. In the following code:
073: *
074: * <pre>
075: * long instant = ...
076: * int v = ...
077: * int age = getDifference(add(instant, v), instant);
078: * </pre>
079: *
080: * The value 'age' is the same as the value 'v'.
081: * <p>
082: * The default implementation call getDifferenceAsLong and converts the
083: * return value to an int.
084: *
085: * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to
086: * subtract from
087: * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to
088: * subtract off the minuend
089: * @return the difference in the units of this field
090: */
091: public int getDifference(long minuendInstant, long subtrahendInstant) {
092: return FieldUtils.safeToInt(getDifferenceAsLong(minuendInstant,
093: subtrahendInstant));
094: }
095:
096: /**
097: * Computes the difference between two instants, as measured in the units
098: * of this field. Any fractional units are dropped from the result. Calling
099: * getDifference reverses the effect of calling add. In the following code:
100: *
101: * <pre>
102: * long instant = ...
103: * long v = ...
104: * long age = getDifferenceAsLong(add(instant, v), instant);
105: * </pre>
106: *
107: * The value 'age' is the same as the value 'v'.
108: * <p>
109: * The default implementation performs a guess-and-check algorithm using
110: * getDurationField().getUnitMillis() and the add() method. Subclasses are
111: * encouraged to provide a more efficient implementation.
112: *
113: * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to
114: * subtract from
115: * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to
116: * subtract off the minuend
117: * @return the difference in the units of this field
118: */
119: public long getDifferenceAsLong(long minuendInstant,
120: long subtrahendInstant) {
121: if (minuendInstant < subtrahendInstant) {
122: return -getDifferenceAsLong(subtrahendInstant,
123: minuendInstant);
124: }
125:
126: long difference = (minuendInstant - subtrahendInstant)
127: / iUnitMillis;
128: if (add(subtrahendInstant, difference) < minuendInstant) {
129: do {
130: difference++;
131: } while (add(subtrahendInstant, difference) <= minuendInstant);
132: difference--;
133: } else if (add(subtrahendInstant, difference) > minuendInstant) {
134: do {
135: difference--;
136: } while (add(subtrahendInstant, difference) > minuendInstant);
137: }
138: return difference;
139: }
140:
141: public final DurationField getDurationField() {
142: return iDurationField;
143: }
144:
145: public abstract DurationField getRangeDurationField();
146:
147: public abstract long roundFloor(long instant);
148:
149: protected final long getDurationUnitMillis() {
150: return iUnitMillis;
151: }
152:
153: private final class LinkedDurationField extends BaseDurationField {
154: private static final long serialVersionUID = -203813474600094134L;
155:
156: LinkedDurationField(DurationFieldType type) {
157: super (type);
158: }
159:
160: public boolean isPrecise() {
161: return false;
162: }
163:
164: public long getUnitMillis() {
165: return iUnitMillis;
166: }
167:
168: public int getValue(long duration, long instant) {
169: return ImpreciseDateTimeField.this .getDifference(instant
170: + duration, instant);
171: }
172:
173: public long getValueAsLong(long duration, long instant) {
174: return ImpreciseDateTimeField.this .getDifferenceAsLong(
175: instant + duration, instant);
176: }
177:
178: public long getMillis(int value, long instant) {
179: return ImpreciseDateTimeField.this .add(instant, value)
180: - instant;
181: }
182:
183: public long getMillis(long value, long instant) {
184: return ImpreciseDateTimeField.this .add(instant, value)
185: - instant;
186: }
187:
188: public long add(long instant, int value) {
189: return ImpreciseDateTimeField.this .add(instant, value);
190: }
191:
192: public long add(long instant, long value) {
193: return ImpreciseDateTimeField.this .add(instant, value);
194: }
195:
196: public int getDifference(long minuendInstant,
197: long subtrahendInstant) {
198: return ImpreciseDateTimeField.this .getDifference(
199: minuendInstant, subtrahendInstant);
200: }
201:
202: public long getDifferenceAsLong(long minuendInstant,
203: long subtrahendInstant) {
204: return ImpreciseDateTimeField.this.getDifferenceAsLong(
205: minuendInstant, subtrahendInstant);
206: }
207: }
208:
209: }
|