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:
021: /**
022: * Precise datetime field, which has a precise unit duration field.
023: * <p>
024: * PreciseDurationDateTimeField is thread-safe and immutable, and its
025: * subclasses must be as well.
026: *
027: * @author Brian S O'Neill
028: * @since 1.0
029: */
030: public abstract class PreciseDurationDateTimeField extends
031: BaseDateTimeField {
032:
033: private static final long serialVersionUID = 5004523158306266035L;
034:
035: /** The fractional unit in millis */
036: final long iUnitMillis;
037:
038: private final DurationField iUnitField;
039:
040: /**
041: * Constructor.
042: *
043: * @param type the field type
044: * @param unit precise unit duration, like "days()".
045: * @throws IllegalArgumentException if duration field is imprecise
046: * @throws IllegalArgumentException if unit milliseconds is less than one
047: */
048: public PreciseDurationDateTimeField(DateTimeFieldType type,
049: DurationField unit) {
050: super (type);
051:
052: if (!unit.isPrecise()) {
053: throw new IllegalArgumentException(
054: "Unit duration field must be precise");
055: }
056:
057: iUnitMillis = unit.getUnitMillis();
058: if (iUnitMillis < 1) {
059: throw new IllegalArgumentException(
060: "The unit milliseconds must be at least 1");
061: }
062:
063: iUnitField = unit;
064: }
065:
066: /**
067: * Returns false by default.
068: */
069: public boolean isLenient() {
070: return false;
071: }
072:
073: /**
074: * Set the specified amount of units to the specified time instant.
075: *
076: * @param instant the milliseconds from 1970-01-01T00:00:00Z to set in
077: * @param value value of units to set.
078: * @return the updated time instant.
079: * @throws IllegalArgumentException if value is too large or too small.
080: */
081: public long set(long instant, int value) {
082: FieldUtils.verifyValueBounds(this , value, getMinimumValue(),
083: getMaximumValueForSet(instant, value));
084: return instant + (value - get(instant)) * iUnitMillis;
085: }
086:
087: /**
088: * This method assumes that this field is properly rounded on
089: * 1970-01-01T00:00:00. If the rounding alignment differs, override this
090: * method as follows:
091: * <pre>
092: * return super.roundFloor(instant + ALIGNMENT_MILLIS) - ALIGNMENT_MILLIS;
093: * </pre>
094: */
095: public long roundFloor(long instant) {
096: if (instant >= 0) {
097: return instant - instant % iUnitMillis;
098: } else {
099: instant += 1;
100: return instant - instant % iUnitMillis - iUnitMillis;
101: }
102: }
103:
104: /**
105: * This method assumes that this field is properly rounded on
106: * 1970-01-01T00:00:00. If the rounding alignment differs, override this
107: * method as follows:
108: * <pre>
109: * return super.roundCeiling(instant + ALIGNMENT_MILLIS) - ALIGNMENT_MILLIS;
110: * </pre>
111: */
112: public long roundCeiling(long instant) {
113: if (instant > 0) {
114: instant -= 1;
115: return instant - instant % iUnitMillis + iUnitMillis;
116: } else {
117: return instant - instant % iUnitMillis;
118: }
119: }
120:
121: /**
122: * This method assumes that this field is properly rounded on
123: * 1970-01-01T00:00:00. If the rounding alignment differs, override this
124: * method as follows:
125: * <pre>
126: * return super.remainder(instant + ALIGNMENT_MILLIS);
127: * </pre>
128: */
129: public long remainder(long instant) {
130: if (instant >= 0) {
131: return instant % iUnitMillis;
132: } else {
133: return (instant + 1) % iUnitMillis + iUnitMillis - 1;
134: }
135: }
136:
137: /**
138: * Returns the duration per unit value of this field. For example, if this
139: * field represents "minute of hour", then the duration field is minutes.
140: *
141: * @return the duration of this field, or UnsupportedDurationField if field
142: * has no duration
143: */
144: public DurationField getDurationField() {
145: return iUnitField;
146: }
147:
148: /**
149: * Get the minimum value for the field.
150: *
151: * @return the minimum value
152: */
153: public int getMinimumValue() {
154: return 0;
155: }
156:
157: public final long getUnitMillis() {
158: return iUnitMillis;
159: }
160:
161: /**
162: * Called by the set method to get the maximum allowed value. By default,
163: * returns getMaximumValue(instant). Override to provide a faster
164: * implementation.
165: */
166: protected int getMaximumValueForSet(long instant, int value) {
167: return getMaximumValue(instant);
168: }
169:
170: }
|