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 * Generic offset adjusting datetime field.
024 * <p>
025 * OffsetDateTimeField is thread-safe and immutable.
026 *
027 * @author Brian S O'Neill
028 * @since 1.0
029 */
030 public class OffsetDateTimeField extends DecoratedDateTimeField {
031 private static final long serialVersionUID = 3145790132623583142L;
032
033 private final int iOffset;
034
035 private final int iMin;
036 private final int iMax;
037
038 /**
039 * Constructor.
040 *
041 * @param field the field to wrap, like "year()".
042 * @param offset offset to add to field values
043 * @throws IllegalArgumentException if offset is zero
044 */
045 public OffsetDateTimeField(DateTimeField field, int offset) {
046 this(field, (field == null ? null : field.getType()), offset, Integer.MIN_VALUE, Integer.MAX_VALUE);
047 }
048
049 /**
050 * Constructor.
051 *
052 * @param field the field to wrap, like "year()".
053 * @param type the field type this field actually uses
054 * @param offset offset to add to field values
055 * @throws IllegalArgumentException if offset is zero
056 */
057 public OffsetDateTimeField(DateTimeField field, DateTimeFieldType type, int offset) {
058 this(field, type, offset, Integer.MIN_VALUE, Integer.MAX_VALUE);
059 }
060
061 /**
062 * Constructor.
063 *
064 * @param field the field to wrap, like "year()".
065 * @param type the field type this field actually uses
066 * @param offset offset to add to field values
067 * @param minValue minimum allowed value
068 * @param maxValue maximum allowed value
069 * @throws IllegalArgumentException if offset is zero
070 */
071 public OffsetDateTimeField(DateTimeField field, DateTimeFieldType type, int offset,
072 int minValue, int maxValue) {
073 super(field, type);
074
075 if (offset == 0) {
076 throw new IllegalArgumentException("The offset cannot be zero");
077 }
078
079 iOffset = offset;
080
081 if (minValue < (field.getMinimumValue() + offset)) {
082 iMin = field.getMinimumValue() + offset;
083 } else {
084 iMin = minValue;
085 }
086 if (maxValue > (field.getMaximumValue() + offset)) {
087 iMax = field.getMaximumValue() + offset;
088 } else {
089 iMax = maxValue;
090 }
091 }
092
093 /**
094 * Get the amount of offset units from the specified time instant.
095 *
096 * @param instant the time instant in millis to query.
097 * @return the amount of units extracted from the input.
098 */
099 public int get(long instant) {
100 return super.get(instant) + iOffset;
101 }
102
103 /**
104 * Add the specified amount of offset units to the specified time
105 * instant. The amount added may be negative.
106 *
107 * @param instant the time instant in millis to update.
108 * @param amount the amount of units to add (can be negative).
109 * @return the updated time instant.
110 */
111 public long add(long instant, int amount) {
112 instant = super.add(instant, amount);
113 FieldUtils.verifyValueBounds(this, get(instant), iMin, iMax);
114 return instant;
115 }
116
117 /**
118 * Add the specified amount of offset units to the specified time
119 * instant. The amount added may be negative.
120 *
121 * @param instant the time instant in millis to update.
122 * @param amount the amount of units to add (can be negative).
123 * @return the updated time instant.
124 */
125 public long add(long instant, long amount) {
126 instant = super.add(instant, amount);
127 FieldUtils.verifyValueBounds(this, get(instant), iMin, iMax);
128 return instant;
129 }
130
131 /**
132 * Add to the offset component of the specified time instant,
133 * wrapping around within that component if necessary.
134 *
135 * @param instant the time instant in millis to update.
136 * @param amount the amount of units to add (can be negative).
137 * @return the updated time instant.
138 */
139 public long addWrapField(long instant, int amount) {
140 return set(instant, FieldUtils.getWrappedValue(get(instant), amount, iMin, iMax));
141 }
142
143 /**
144 * Set the specified amount of offset units to the specified time instant.
145 *
146 * @param instant the time instant in millis to update.
147 * @param value value of units to set.
148 * @return the updated time instant.
149 * @throws IllegalArgumentException if value is too large or too small.
150 */
151 public long set(long instant, int value) {
152 FieldUtils.verifyValueBounds(this, value, iMin, iMax);
153 return super.set(instant, value - iOffset);
154 }
155
156 public boolean isLeap(long instant) {
157 return getWrappedField().isLeap(instant);
158 }
159
160 public int getLeapAmount(long instant) {
161 return getWrappedField().getLeapAmount(instant);
162 }
163
164 public DurationField getLeapDurationField() {
165 return getWrappedField().getLeapDurationField();
166 }
167
168 /**
169 * Get the minimum value for the field.
170 *
171 * @return the minimum value
172 */
173 public int getMinimumValue() {
174 return iMin;
175 }
176
177 /**
178 * Get the maximum value for the field.
179 *
180 * @return the maximum value
181 */
182 public int getMaximumValue() {
183 return iMax;
184 }
185
186 public long roundFloor(long instant) {
187 return getWrappedField().roundFloor(instant);
188 }
189
190 public long roundCeiling(long instant) {
191 return getWrappedField().roundCeiling(instant);
192 }
193
194 public long roundHalfFloor(long instant) {
195 return getWrappedField().roundHalfFloor(instant);
196 }
197
198 public long roundHalfCeiling(long instant) {
199 return getWrappedField().roundHalfCeiling(instant);
200 }
201
202 public long roundHalfEven(long instant) {
203 return getWrappedField().roundHalfEven(instant);
204 }
205
206 public long remainder(long instant) {
207 return getWrappedField().remainder(instant);
208 }
209
210 /**
211 * Returns the offset added to the field values.
212 *
213 * @return the offset
214 */
215 public int getOffset() {
216 return iOffset;
217 }
218 }