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.DateTimeField;
019: import org.joda.time.DateTimeFieldType;
020: import org.joda.time.DurationField;
021:
022: /**
023: * Counterpart remainder datetime field to {@link DividedDateTimeField}. The
024: * field's unit duration is unchanged, but the range duration is scaled
025: * accordingly.
026: * <p>
027: * RemainderDateTimeField is thread-safe and immutable.
028: *
029: * @see DividedDateTimeField
030: *
031: * @author Brian S O'Neill
032: * @since 1.0
033: */
034: public class RemainderDateTimeField extends DecoratedDateTimeField {
035:
036: private static final long serialVersionUID = 5708241235177666790L;
037:
038: // Shared with DividedDateTimeField.
039: final int iDivisor;
040: final DurationField iRangeField;
041:
042: /**
043: * Constructor.
044: *
045: * @param field the field to wrap, like "year()".
046: * @param type the field type this field actually uses
047: * @param divisor divisor, such as 100 years in a century
048: * @throws IllegalArgumentException if divisor is less than two
049: */
050: public RemainderDateTimeField(DateTimeField field,
051: DateTimeFieldType type, int divisor) {
052: super (field, type);
053:
054: if (divisor < 2) {
055: throw new IllegalArgumentException(
056: "The divisor must be at least 2");
057: }
058:
059: DurationField rangeField = field.getDurationField();
060: if (rangeField == null) {
061: iRangeField = null;
062: } else {
063: iRangeField = new ScaledDurationField(rangeField, type
064: .getRangeDurationType(), divisor);
065: }
066:
067: iDivisor = divisor;
068: }
069:
070: /**
071: * Construct a RemainderDateTimeField that compliments the given
072: * DividedDateTimeField.
073: *
074: * @param dividedField complimentary divided field, like "century()".
075: */
076: public RemainderDateTimeField(DividedDateTimeField dividedField) {
077: this (dividedField, dividedField.getType());
078: }
079:
080: /**
081: * Construct a RemainderDateTimeField that compliments the given
082: * DividedDateTimeField.
083: *
084: * @param dividedField complimentary divided field, like "century()".
085: * @param type the field type this field actually uses
086: */
087: public RemainderDateTimeField(DividedDateTimeField dividedField,
088: DateTimeFieldType type) {
089: super (dividedField.getWrappedField(), type);
090: iDivisor = dividedField.iDivisor;
091: iRangeField = dividedField.iDurationField;
092: }
093:
094: //-----------------------------------------------------------------------
095: /**
096: * Get the remainder from the specified time instant.
097: *
098: * @param instant the time instant in millis to query.
099: * @return the remainder extracted from the input.
100: */
101: public int get(long instant) {
102: int value = getWrappedField().get(instant);
103: if (value >= 0) {
104: return value % iDivisor;
105: } else {
106: return (iDivisor - 1) + ((value + 1) % iDivisor);
107: }
108: }
109:
110: /**
111: * Add the specified amount to the specified time instant, wrapping around
112: * within the remainder range if necessary. The amount added may be
113: * negative.
114: *
115: * @param instant the time instant in millis to update.
116: * @param amount the amount to add (can be negative).
117: * @return the updated time instant.
118: */
119: public long addWrapField(long instant, int amount) {
120: return set(instant, FieldUtils.getWrappedValue(get(instant),
121: amount, 0, iDivisor - 1));
122: }
123:
124: /**
125: * Set the specified amount of remainder units to the specified time instant.
126: *
127: * @param instant the time instant in millis to update.
128: * @param value value of remainder units to set.
129: * @return the updated time instant.
130: * @throws IllegalArgumentException if value is too large or too small.
131: */
132: public long set(long instant, int value) {
133: FieldUtils.verifyValueBounds(this , value, 0, iDivisor - 1);
134: int divided = getDivided(getWrappedField().get(instant));
135: return getWrappedField().set(instant,
136: divided * iDivisor + value);
137: }
138:
139: /**
140: * Returns a scaled version of the wrapped field's unit duration field.
141: */
142: public DurationField getRangeDurationField() {
143: return iRangeField;
144: }
145:
146: /**
147: * Get the minimum value for the field, which is always zero.
148: *
149: * @return the minimum value of zero.
150: */
151: public int getMinimumValue() {
152: return 0;
153: }
154:
155: /**
156: * Get the maximum value for the field, which is always one less than the
157: * divisor.
158: *
159: * @return the maximum value
160: */
161: public int getMaximumValue() {
162: return iDivisor - 1;
163: }
164:
165: public long roundFloor(long instant) {
166: return getWrappedField().roundFloor(instant);
167: }
168:
169: public long roundCeiling(long instant) {
170: return getWrappedField().roundCeiling(instant);
171: }
172:
173: public long roundHalfFloor(long instant) {
174: return getWrappedField().roundHalfFloor(instant);
175: }
176:
177: public long roundHalfCeiling(long instant) {
178: return getWrappedField().roundHalfCeiling(instant);
179: }
180:
181: public long roundHalfEven(long instant) {
182: return getWrappedField().roundHalfEven(instant);
183: }
184:
185: public long remainder(long instant) {
186: return getWrappedField().remainder(instant);
187: }
188:
189: /**
190: * Returns the divisor applied, in the field's units.
191: *
192: * @return the divisor
193: */
194: public int getDivisor() {
195: return iDivisor;
196: }
197:
198: private int getDivided(int value) {
199: if (value >= 0) {
200: return value / iDivisor;
201: } else {
202: return ((value + 1) / iDivisor) - 1;
203: }
204: }
205:
206: }
|