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;
17
18 import java.io.Serializable;
19
20 import org.joda.time.base.BaseInterval;
21 import org.joda.time.field.FieldUtils;
22 import org.joda.time.format.ISODateTimeFormat;
23 import org.joda.time.format.ISOPeriodFormat;
24
25 /**
26 * MutableInterval is the standard implementation of a mutable time interval.
27 * <p>
28 * A time interval represents a period of time between two instants.
29 * Intervals are inclusive of the start instant and exclusive of the end.
30 * The end instant is always greater than or equal to the start instant.
31 * <p>
32 * Intervals have a fixed millisecond duration.
33 * This is the difference between the start and end instants.
34 * The duration is represented separately by {@link ReadableDuration}.
35 * As a result, intervals are not comparable.
36 * To compare the length of two intervals, you should compare their durations.
37 * <p>
38 * An interval can also be converted to a {@link ReadablePeriod}.
39 * This represents the difference between the start and end points in terms of fields
40 * such as years and days.
41 * <p>
42 * If performing significant calculations on an interval, it may be faster to
43 * convert an Interval object to a MutableInterval one.
44 * <p>
45 * MutableInterval is mutable and not thread-safe, unless concurrent threads
46 * are not invoking mutator methods.
47 *
48 * @author Stephen Colebourne
49 * @author Brian S O'Neill
50 * @since 1.0
51 */
52 public class MutableInterval
53 extends BaseInterval
54 implements ReadWritableInterval, Cloneable, Serializable {
55
56 /** Serialization version */
57 private static final long serialVersionUID = -5982824024992428470L;
58
59 //-----------------------------------------------------------------------
60 /**
61 * Parses a {@code MutableInterval} from the specified string.
62 * <p>
63 * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
64 * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
65 * 'datetime/period' or 'period/datetime'.
66 *
67 * @param str the string to parse, not null
68 * @since 2.0
69 */
70 public static MutableInterval parse(String str) {
71 return new MutableInterval(str);
72 }
73
74 //-----------------------------------------------------------------------
75 /**
76 * Constructs a zero length time interval from 1970-01-01 to 1970-01-01.
77 */
78 public MutableInterval() {
79 super(0L, 0L, null);
80 }
81
82 /**
83 * Constructs an interval from a start and end instant with the ISO default chronology.
84 *
85 * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
86 * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
87 * @throws IllegalArgumentException if the end is before the start
88 */
89 public MutableInterval(long startInstant, long endInstant) {
90 super(startInstant, endInstant, null);
91 }
92
93 /**
94 * Constructs an interval from a start and end instant with a chronology.
95 *
96 * @param chronology the chronology to use, null is ISO default
97 * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
98 * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
99 * @throws IllegalArgumentException if the end is before the start
100 */
101 public MutableInterval(long startInstant, long endInstant, Chronology chronology) {
102 super(startInstant, endInstant, chronology);
103 }
104
105 /**
106 * Constructs an interval from a start and end instant.
107 * <p>
108 * The chronology used is that of the start instant.
109 *
110 * @param start start of this interval, null means now
111 * @param end end of this interval, null means now
112 * @throws IllegalArgumentException if the end is before the start
113 */
114 public MutableInterval(ReadableInstant start, ReadableInstant end) {
115 super(start, end);
116 }
117
118 /**
119 * Constructs an interval from a start instant and a duration.
120 *
121 * @param start start of this interval, null means now
122 * @param duration the duration of this interval, null means zero length
123 * @throws IllegalArgumentException if the end is before the start
124 * @throws ArithmeticException if the end instant exceeds the capacity of a long
125 */
126 public MutableInterval(ReadableInstant start, ReadableDuration duration) {
127 super(start, duration);
128 }
129
130 /**
131 * Constructs an interval from a millisecond duration and an end instant.
132 *
133 * @param duration the duration of this interval, null means zero length
134 * @param end end of this interval, null means now
135 * @throws IllegalArgumentException if the end is before the start
136 * @throws ArithmeticException if the start instant exceeds the capacity of a long
137 */
138 public MutableInterval(ReadableDuration duration, ReadableInstant end) {
139 super(duration, end);
140 }
141
142 /**
143 * Constructs an interval from a start instant and a time period.
144 * <p>
145 * When forming the interval, the chronology from the instant is used
146 * if present, otherwise the chronology of the period is used.
147 *
148 * @param start start of this interval, null means now
149 * @param period the period of this interval, null means zero length
150 * @throws IllegalArgumentException if the end is before the start
151 * @throws ArithmeticException if the end instant exceeds the capacity of a long
152 */
153 public MutableInterval(ReadableInstant start, ReadablePeriod period) {
154 super(start, period);
155 }
156
157 /**
158 * Constructs an interval from a time period and an end instant.
159 * <p>
160 * When forming the interval, the chronology from the instant is used
161 * if present, otherwise the chronology of the period is used.
162 *
163 * @param period the period of this interval, null means zero length
164 * @param end end of this interval, null means now
165 * @throws IllegalArgumentException if the end is before the start
166 * @throws ArithmeticException if the start instant exceeds the capacity of a long
167 */
168 public MutableInterval(ReadablePeriod period, ReadableInstant end) {
169 super(period, end);
170 }
171
172 /**
173 * Constructs a time interval by converting or copying from another object.
174 * <p>
175 * The recognised object types are defined in
176 * {@link org.joda.time.convert.ConverterManager ConverterManager} and
177 * include ReadableInterval and String.
178 * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
179 * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
180 * 'datetime/period' or 'period/datetime'.
181 *
182 * @param interval the time interval to copy
183 * @throws IllegalArgumentException if the interval is invalid
184 */
185 public MutableInterval(Object interval) {
186 super(interval, null);
187 }
188
189 /**
190 * Constructs a time interval by converting or copying from another object,
191 * overriding the chronology.
192 * <p>
193 * The recognised object types are defined in
194 * {@link org.joda.time.convert.ConverterManager ConverterManager} and
195 * include ReadableInterval and String.
196 * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
197 * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
198 * 'datetime/period' or 'period/datetime'.
199 *
200 * @param interval the time interval to copy
201 * @param chronology the chronology to use, null means ISO default
202 * @throws IllegalArgumentException if the interval is invalid
203 */
204 public MutableInterval(Object interval, Chronology chronology) {
205 super(interval, chronology);
206 }
207
208 //-----------------------------------------------------------------------
209 /**
210 * Sets this interval from two millisecond instants retaining the chronology.
211 *
212 * @param startInstant the start of the time interval
213 * @param endInstant the start of the time interval
214 * @throws IllegalArgumentException if the end is before the start
215 */
216 public void setInterval(long startInstant, long endInstant) {
217 super.setInterval(startInstant, endInstant, getChronology());
218 }
219
220 /**
221 * Sets this interval to be the same as another.
222 *
223 * @param interval the interval to copy
224 * @throws IllegalArgumentException if the interval is null
225 */
226 public void setInterval(ReadableInterval interval) {
227 if (interval == null) {
228 throw new IllegalArgumentException("Interval must not be null");
229 }
230 long startMillis = interval.getStartMillis();
231 long endMillis = interval.getEndMillis();
232 Chronology chrono = interval.getChronology();
233 super.setInterval(startMillis, endMillis, chrono);
234 }
235
236 /**
237 * Sets this interval from two instants, replacing the chronology with
238 * that from the start instant.
239 *
240 * @param start the start of the time interval
241 * @param end the start of the time interval
242 * @throws IllegalArgumentException if the end is before the start
243 */
244 public void setInterval(ReadableInstant start, ReadableInstant end) {
245 if (start == null && end == null) {
246 long now = DateTimeUtils.currentTimeMillis();
247 setInterval(now, now);
248 } else {
249 long startMillis = DateTimeUtils.getInstantMillis(start);
250 long endMillis = DateTimeUtils.getInstantMillis(end);
251 Chronology chrono = DateTimeUtils.getInstantChronology(start);
252 super.setInterval(startMillis, endMillis, chrono);
253 }
254 }
255
256 //-----------------------------------------------------------------------
257 /**
258 * Sets the chronology of this time interval.
259 *
260 * @param chrono the chronology to use, null means ISO default
261 */
262 public void setChronology(Chronology chrono) {
263 super.setInterval(getStartMillis(), getEndMillis(), chrono);
264 }
265
266 /**
267 * Sets the start of this time interval.
268 *
269 * @param startInstant the start of the time interval,
270 * millisecond instant from 1970-01-01T00:00:00Z
271 * @throws IllegalArgumentException if the end is before the start
272 */
273 public void setStartMillis(long startInstant) {
274 super.setInterval(startInstant, getEndMillis(), getChronology());
275 }
276
277 /**
278 * Sets the start of this time interval as an Instant.
279 *
280 * @param start the start of the time interval, null means now
281 * @throws IllegalArgumentException if the end is before the start
282 */
283 public void setStart(ReadableInstant start) {
284 long startMillis = DateTimeUtils.getInstantMillis(start);
285 super.setInterval(startMillis, getEndMillis(), getChronology());
286 }
287
288 /**
289 * Sets the end of this time interval.
290 *
291 * @param endInstant the end of the time interval,
292 * millisecond instant from 1970-01-01T00:00:00Z
293 * @throws IllegalArgumentException if the end is before the start
294 */
295 public void setEndMillis(long endInstant) {
296 super.setInterval(getStartMillis(), endInstant, getChronology());
297 }
298
299 /**
300 * Sets the end of this time interval as an Instant.
301 *
302 * @param end the end of the time interval, null means now
303 * @throws IllegalArgumentException if the end is before the start
304 */
305 public void setEnd(ReadableInstant end) {
306 long endMillis = DateTimeUtils.getInstantMillis(end);
307 super.setInterval(getStartMillis(), endMillis, getChronology());
308 }
309
310 //-----------------------------------------------------------------------
311 /**
312 * Sets the duration of this time interval, preserving the start instant.
313 *
314 * @param duration new duration for interval
315 * @throws IllegalArgumentException if the end is before the start
316 * @throws ArithmeticException if the end instant exceeds the capacity of a long
317 */
318 public void setDurationAfterStart(long duration) {
319 setEndMillis(FieldUtils.safeAdd(getStartMillis(), duration));
320 }
321
322 /**
323 * Sets the duration of this time interval, preserving the end instant.
324 *
325 * @param duration new duration for interval
326 * @throws IllegalArgumentException if the end is before the start
327 * @throws ArithmeticException if the start instant exceeds the capacity of a long
328 */
329 public void setDurationBeforeEnd(long duration) {
330 setStartMillis(FieldUtils.safeAdd(getEndMillis(), -duration));
331 }
332
333 //-----------------------------------------------------------------------
334 /**
335 * Sets the duration of this time interval, preserving the start instant.
336 *
337 * @param duration new duration for interval, null means zero length
338 * @throws IllegalArgumentException if the end is before the start
339 * @throws ArithmeticException if the end instant exceeds the capacity of a long
340 */
341 public void setDurationAfterStart(ReadableDuration duration) {
342 long durationMillis = DateTimeUtils.getDurationMillis(duration);
343 setEndMillis(FieldUtils.safeAdd(getStartMillis(), durationMillis));
344 }
345
346 /**
347 * Sets the duration of this time interval, preserving the end instant.
348 *
349 * @param duration new duration for interval, null means zero length
350 * @throws IllegalArgumentException if the end is before the start
351 * @throws ArithmeticException if the start instant exceeds the capacity of a long
352 */
353 public void setDurationBeforeEnd(ReadableDuration duration) {
354 long durationMillis = DateTimeUtils.getDurationMillis(duration);
355 setStartMillis(FieldUtils.safeAdd(getEndMillis(), -durationMillis));
356 }
357
358 //-----------------------------------------------------------------------
359 /**
360 * Sets the period of this time interval, preserving the start instant
361 * and using the ISOChronology in the default zone for calculations.
362 *
363 * @param period new period for interval, null means zero length
364 * @throws IllegalArgumentException if the end is before the start
365 * @throws ArithmeticException if the end instant exceeds the capacity of a long
366 */
367 public void setPeriodAfterStart(ReadablePeriod period) {
368 if (period == null) {
369 setEndMillis(getStartMillis());
370 } else {
371 setEndMillis(getChronology().add(period, getStartMillis(), 1));
372 }
373 }
374
375 /**
376 * Sets the period of this time interval, preserving the end instant
377 * and using the ISOChronology in the default zone for calculations.
378 *
379 * @param period new period for interval, null means zero length
380 * @throws IllegalArgumentException if the end is before the start
381 * @throws ArithmeticException if the start instant exceeds the capacity of a long
382 */
383 public void setPeriodBeforeEnd(ReadablePeriod period) {
384 if (period == null) {
385 setStartMillis(getEndMillis());
386 } else {
387 setStartMillis(getChronology().add(period, getEndMillis(), -1));
388 }
389 }
390
391 //-----------------------------------------------------------------------
392 /**
393 * Clone this object without having to cast the returned object.
394 *
395 * @return a clone of the this object.
396 */
397 public MutableInterval copy() {
398 return (MutableInterval) clone();
399 }
400
401 /**
402 * Clone this object.
403 *
404 * @return a clone of this object.
405 */
406 public Object clone() {
407 try {
408 return super.clone();
409 } catch (CloneNotSupportedException ex) {
410 throw new InternalError("Clone error");
411 }
412 }
413
414 }