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, long unitMillis) {
055 super(type);
056 iUnitMillis = unitMillis;
057 iDurationField = new LinkedDurationField(type.getDurationType());
058 }
059
060 public abstract int get(long instant);
061
062 public abstract long set(long instant, int value);
063
064 public abstract long add(long instant, int value);
065
066 public abstract long add(long instant, long value);
067
068 /**
069 * Computes the difference between two instants, as measured in the units
070 * of this field. Any fractional units are dropped from the result. Calling
071 * getDifference reverses the effect of calling add. In the following code:
072 *
073 * <pre>
074 * long instant = ...
075 * int v = ...
076 * int age = getDifference(add(instant, v), instant);
077 * </pre>
078 *
079 * The value 'age' is the same as the value 'v'.
080 * <p>
081 * The default implementation call getDifferenceAsLong and converts the
082 * return value to an int.
083 *
084 * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to
085 * subtract from
086 * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to
087 * subtract off the minuend
088 * @return the difference in the units of this field
089 */
090 public int getDifference(long minuendInstant, long subtrahendInstant) {
091 return FieldUtils.safeToInt(getDifferenceAsLong(minuendInstant, subtrahendInstant));
092 }
093
094 /**
095 * Computes the difference between two instants, as measured in the units
096 * of this field. Any fractional units are dropped from the result. Calling
097 * getDifference reverses the effect of calling add. In the following code:
098 *
099 * <pre>
100 * long instant = ...
101 * long v = ...
102 * long age = getDifferenceAsLong(add(instant, v), instant);
103 * </pre>
104 *
105 * The value 'age' is the same as the value 'v'.
106 * <p>
107 * The default implementation performs a guess-and-check algorithm using
108 * getDurationField().getUnitMillis() and the add() method. Subclasses are
109 * encouraged to provide a more efficient implementation.
110 *
111 * @param minuendInstant the milliseconds from 1970-01-01T00:00:00Z to
112 * subtract from
113 * @param subtrahendInstant the milliseconds from 1970-01-01T00:00:00Z to
114 * subtract off the minuend
115 * @return the difference in the units of this field
116 */
117 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
118 if (minuendInstant < subtrahendInstant) {
119 return -getDifferenceAsLong(subtrahendInstant, minuendInstant);
120 }
121
122 long difference = (minuendInstant - subtrahendInstant) / iUnitMillis;
123 if (add(subtrahendInstant, difference) < minuendInstant) {
124 do {
125 difference++;
126 } while (add(subtrahendInstant, difference) <= minuendInstant);
127 difference--;
128 } else if (add(subtrahendInstant, difference) > minuendInstant) {
129 do {
130 difference--;
131 } while (add(subtrahendInstant, difference) > minuendInstant);
132 }
133 return difference;
134 }
135
136 public final DurationField getDurationField() {
137 return iDurationField;
138 }
139
140 public abstract DurationField getRangeDurationField();
141
142 public abstract long roundFloor(long instant);
143
144 protected final long getDurationUnitMillis() {
145 return iUnitMillis;
146 }
147
148 private final class LinkedDurationField extends BaseDurationField {
149 private static final long serialVersionUID = -203813474600094134L;
150
151 LinkedDurationField(DurationFieldType type) {
152 super(type);
153 }
154
155 public boolean isPrecise() {
156 return false;
157 }
158
159 public long getUnitMillis() {
160 return iUnitMillis;
161 }
162
163 public int getValue(long duration, long instant) {
164 return ImpreciseDateTimeField.this
165 .getDifference(instant + duration, instant);
166 }
167
168 public long getValueAsLong(long duration, long instant) {
169 return ImpreciseDateTimeField.this
170 .getDifferenceAsLong(instant + duration, instant);
171 }
172
173 public long getMillis(int value, long instant) {
174 return ImpreciseDateTimeField.this.add(instant, value) - instant;
175 }
176
177 public long getMillis(long value, long instant) {
178 return ImpreciseDateTimeField.this.add(instant, value) - instant;
179 }
180
181 public long add(long instant, int value) {
182 return ImpreciseDateTimeField.this.add(instant, value);
183 }
184
185 public long add(long instant, long value) {
186 return ImpreciseDateTimeField.this.add(instant, value);
187 }
188
189 public int getDifference(long minuendInstant, long subtrahendInstant) {
190 return ImpreciseDateTimeField.this
191 .getDifference(minuendInstant, subtrahendInstant);
192 }
193
194 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
195 return ImpreciseDateTimeField.this
196 .getDifferenceAsLong(minuendInstant, subtrahendInstant);
197 }
198 }
199
200 }