1 /*
2 * Copyright 2001-2005 Stephen Colebourne
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.joda.time.field;
17
18 import org.joda.time.DateTimeField;
19 import org.joda.time.DateTimeFieldType;
20 import org.joda.time.DurationField;
21
22 /**
23 * Generic offset adjusting datetime field.
24 * <p>
25 * OffsetDateTimeField is thread-safe and immutable.
26 *
27 * @author Brian S O'Neill
28 * @since 1.0
29 */
30 public class OffsetDateTimeField extends DecoratedDateTimeField {
31 private static final long serialVersionUID = 3145790132623583142L;
32
33 private final int iOffset;
34
35 private final int iMin;
36 private final int iMax;
37
38 /**
39 * Constructor.
40 *
41 * @param field the field to wrap, like "year()".
42 * @param offset offset to add to field values
43 * @throws IllegalArgumentException if offset is zero
44 */
45 public OffsetDateTimeField(DateTimeField field, int offset) {
46 this(field, (field == null ? null : field.getType()), offset, Integer.MIN_VALUE, Integer.MAX_VALUE);
47 }
48
49 /**
50 * Constructor.
51 *
52 * @param field the field to wrap, like "year()".
53 * @param type the field type this field actually uses
54 * @param offset offset to add to field values
55 * @throws IllegalArgumentException if offset is zero
56 */
57 public OffsetDateTimeField(DateTimeField field, DateTimeFieldType type, int offset) {
58 this(field, type, offset, Integer.MIN_VALUE, Integer.MAX_VALUE);
59 }
60
61 /**
62 * Constructor.
63 *
64 * @param field the field to wrap, like "year()".
65 * @param type the field type this field actually uses
66 * @param offset offset to add to field values
67 * @param minValue minimum allowed value
68 * @param maxValue maximum allowed value
69 * @throws IllegalArgumentException if offset is zero
70 */
71 public OffsetDateTimeField(DateTimeField field, DateTimeFieldType type, int offset,
72 int minValue, int maxValue) {
73 super(field, type);
74
75 if (offset == 0) {
76 throw new IllegalArgumentException("The offset cannot be zero");
77 }
78
79 iOffset = offset;
80
81 if (minValue < (field.getMinimumValue() + offset)) {
82 iMin = field.getMinimumValue() + offset;
83 } else {
84 iMin = minValue;
85 }
86 if (maxValue > (field.getMaximumValue() + offset)) {
87 iMax = field.getMaximumValue() + offset;
88 } else {
89 iMax = maxValue;
90 }
91 }
92
93 /**
94 * Get the amount of offset units from the specified time instant.
95 *
96 * @param instant the time instant in millis to query.
97 * @return the amount of units extracted from the input.
98 */
99 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 }