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;
017
018 import java.io.Serializable;
019
020 import org.joda.time.base.BaseInterval;
021 import org.joda.time.field.FieldUtils;
022 import org.joda.time.format.ISODateTimeFormat;
023 import org.joda.time.format.ISOPeriodFormat;
024
025 /**
026 * MutableInterval is the standard implementation of a mutable time interval.
027 * <p>
028 * A time interval represents a period of time between two instants.
029 * Intervals are inclusive of the start instant and exclusive of the end.
030 * The end instant is always greater than or equal to the start instant.
031 * <p>
032 * Intervals have a fixed millisecond duration.
033 * This is the difference between the start and end instants.
034 * The duration is represented separately by {@link ReadableDuration}.
035 * As a result, intervals are not comparable.
036 * To compare the length of two intervals, you should compare their durations.
037 * <p>
038 * An interval can also be converted to a {@link ReadablePeriod}.
039 * This represents the difference between the start and end points in terms of fields
040 * such as years and days.
041 * <p>
042 * If performing significant calculations on an interval, it may be faster to
043 * convert an Interval object to a MutableInterval one.
044 * <p>
045 * MutableInterval is mutable and not thread-safe, unless concurrent threads
046 * are not invoking mutator methods.
047 *
048 * @author Stephen Colebourne
049 * @author Brian S O'Neill
050 * @since 1.0
051 */
052 public class MutableInterval
053 extends BaseInterval
054 implements ReadWritableInterval, Cloneable, Serializable {
055
056 /** Serialization version */
057 private static final long serialVersionUID = -5982824024992428470L;
058
059 //-----------------------------------------------------------------------
060 /**
061 * Constructs a zero length time interval from 1970-01-01 to 1970-01-01.
062 */
063 public MutableInterval() {
064 super(0L, 0L, null);
065 }
066
067 /**
068 * Constructs an interval from a start and end instant with the ISO default chronology.
069 *
070 * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
071 * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
072 * @throws IllegalArgumentException if the end is before the start
073 */
074 public MutableInterval(long startInstant, long endInstant) {
075 super(startInstant, endInstant, null);
076 }
077
078 /**
079 * Constructs an interval from a start and end instant with a chronology.
080 *
081 * @param chronology the chronology to use, null is ISO default
082 * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
083 * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
084 * @throws IllegalArgumentException if the end is before the start
085 */
086 public MutableInterval(long startInstant, long endInstant, Chronology chronology) {
087 super(startInstant, endInstant, chronology);
088 }
089
090 /**
091 * Constructs an interval from a start and end instant.
092 * <p>
093 * The chronology used is that of the start instant.
094 *
095 * @param start start of this interval, null means now
096 * @param end end of this interval, null means now
097 * @throws IllegalArgumentException if the end is before the start
098 */
099 public MutableInterval(ReadableInstant start, ReadableInstant end) {
100 super(start, end);
101 }
102
103 /**
104 * Constructs an interval from a start instant and a duration.
105 *
106 * @param start start of this interval, null means now
107 * @param duration the duration of this interval, null means zero length
108 * @throws IllegalArgumentException if the end is before the start
109 * @throws ArithmeticException if the end instant exceeds the capacity of a long
110 */
111 public MutableInterval(ReadableInstant start, ReadableDuration duration) {
112 super(start, duration);
113 }
114
115 /**
116 * Constructs an interval from a millisecond duration and an end instant.
117 *
118 * @param duration the duration of this interval, null means zero length
119 * @param end end of this interval, null means now
120 * @throws IllegalArgumentException if the end is before the start
121 * @throws ArithmeticException if the start instant exceeds the capacity of a long
122 */
123 public MutableInterval(ReadableDuration duration, ReadableInstant end) {
124 super(duration, end);
125 }
126
127 /**
128 * Constructs an interval from a start instant and a time period.
129 * <p>
130 * When forming the interval, the chronology from the instant is used
131 * if present, otherwise the chronology of the period is used.
132 *
133 * @param start start of this interval, null means now
134 * @param period the period of this interval, null means zero length
135 * @throws IllegalArgumentException if the end is before the start
136 * @throws ArithmeticException if the end instant exceeds the capacity of a long
137 */
138 public MutableInterval(ReadableInstant start, ReadablePeriod period) {
139 super(start, period);
140 }
141
142 /**
143 * Constructs an interval from a time period and an end instant.
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 period the period of this interval, null means zero length
149 * @param end end of this interval, null means now
150 * @throws IllegalArgumentException if the end is before the start
151 * @throws ArithmeticException if the start instant exceeds the capacity of a long
152 */
153 public MutableInterval(ReadablePeriod period, ReadableInstant end) {
154 super(period, end);
155 }
156
157 /**
158 * Constructs a time interval by converting or copying from another object.
159 * <p>
160 * The recognised object types are defined in
161 * {@link org.joda.time.convert.ConverterManager ConverterManager} and
162 * include ReadableInterval and String.
163 * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
164 * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
165 * 'datetime/period' or 'period/datetime'.
166 *
167 * @param interval the time interval to copy
168 * @throws IllegalArgumentException if the interval is invalid
169 */
170 public MutableInterval(Object interval) {
171 super(interval, null);
172 }
173
174 /**
175 * Constructs a time interval by converting or copying from another object,
176 * overriding the chronology.
177 * <p>
178 * The recognised object types are defined in
179 * {@link org.joda.time.convert.ConverterManager ConverterManager} and
180 * include ReadableInterval and String.
181 * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
182 * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
183 * 'datetime/period' or 'period/datetime'.
184 *
185 * @param interval the time interval to copy
186 * @param chronology the chronology to use, null means ISO default
187 * @throws IllegalArgumentException if the interval is invalid
188 */
189 public MutableInterval(Object interval, Chronology chronology) {
190 super(interval, chronology);
191 }
192
193 //-----------------------------------------------------------------------
194 /**
195 * Sets this interval from two millisecond instants retaining the chronology.
196 *
197 * @param startInstant the start of the time interval
198 * @param endInstant the start of the time interval
199 * @throws IllegalArgumentException if the end is before the start
200 */
201 public void setInterval(long startInstant, long endInstant) {
202 super.setInterval(startInstant, endInstant, getChronology());
203 }
204
205 /**
206 * Sets this interval to be the same as another.
207 *
208 * @param interval the interval to copy
209 * @throws IllegalArgumentException if the interval is null
210 */
211 public void setInterval(ReadableInterval interval) {
212 if (interval == null) {
213 throw new IllegalArgumentException("Interval must not be null");
214 }
215 long startMillis = interval.getStartMillis();
216 long endMillis = interval.getEndMillis();
217 Chronology chrono = interval.getChronology();
218 super.setInterval(startMillis, endMillis, chrono);
219 }
220
221 /**
222 * Sets this interval from two instants, replacing the chronology with
223 * that from the start instant.
224 *
225 * @param start the start of the time interval
226 * @param end the start of the time interval
227 * @throws IllegalArgumentException if the end is before the start
228 */
229 public void setInterval(ReadableInstant start, ReadableInstant end) {
230 if (start == null && end == null) {
231 long now = DateTimeUtils.currentTimeMillis();
232 setInterval(now, now);
233 } else {
234 long startMillis = DateTimeUtils.getInstantMillis(start);
235 long endMillis = DateTimeUtils.getInstantMillis(end);
236 Chronology chrono = DateTimeUtils.getInstantChronology(start);
237 super.setInterval(startMillis, endMillis, chrono);
238 }
239 }
240
241 //-----------------------------------------------------------------------
242 /**
243 * Sets the chronology of this time interval.
244 *
245 * @param chrono the chronology to use, null means ISO default
246 */
247 public void setChronology(Chronology chrono) {
248 super.setInterval(getStartMillis(), getEndMillis(), chrono);
249 }
250
251 /**
252 * Sets the start of this time interval.
253 *
254 * @param startInstant the start of the time interval,
255 * millisecond instant from 1970-01-01T00:00:00Z
256 * @throws IllegalArgumentException if the end is before the start
257 */
258 public void setStartMillis(long startInstant) {
259 super.setInterval(startInstant, getEndMillis(), getChronology());
260 }
261
262 /**
263 * Sets the start of this time interval as an Instant.
264 *
265 * @param start the start of the time interval, null means now
266 * @throws IllegalArgumentException if the end is before the start
267 */
268 public void setStart(ReadableInstant start) {
269 long startMillis = DateTimeUtils.getInstantMillis(start);
270 super.setInterval(startMillis, getEndMillis(), getChronology());
271 }
272
273 /**
274 * Sets the end of this time interval.
275 *
276 * @param endInstant the end of the time interval,
277 * millisecond instant from 1970-01-01T00:00:00Z
278 * @throws IllegalArgumentException if the end is before the start
279 */
280 public void setEndMillis(long endInstant) {
281 super.setInterval(getStartMillis(), endInstant, getChronology());
282 }
283
284 /**
285 * Sets the end of this time interval as an Instant.
286 *
287 * @param end the end of the time interval, null means now
288 * @throws IllegalArgumentException if the end is before the start
289 */
290 public void setEnd(ReadableInstant end) {
291 long endMillis = DateTimeUtils.getInstantMillis(end);
292 super.setInterval(getStartMillis(), endMillis, getChronology());
293 }
294
295 //-----------------------------------------------------------------------
296 /**
297 * Sets the duration of this time interval, preserving the start instant.
298 *
299 * @param duration new duration for interval
300 * @throws IllegalArgumentException if the end is before the start
301 * @throws ArithmeticException if the end instant exceeds the capacity of a long
302 */
303 public void setDurationAfterStart(long duration) {
304 setEndMillis(FieldUtils.safeAdd(getStartMillis(), duration));
305 }
306
307 /**
308 * Sets the duration of this time interval, preserving the end instant.
309 *
310 * @param duration new duration for interval
311 * @throws IllegalArgumentException if the end is before the start
312 * @throws ArithmeticException if the start instant exceeds the capacity of a long
313 */
314 public void setDurationBeforeEnd(long duration) {
315 setStartMillis(FieldUtils.safeAdd(getEndMillis(), -duration));
316 }
317
318 //-----------------------------------------------------------------------
319 /**
320 * Sets the duration of this time interval, preserving the start instant.
321 *
322 * @param duration new duration for interval, null means zero length
323 * @throws IllegalArgumentException if the end is before the start
324 * @throws ArithmeticException if the end instant exceeds the capacity of a long
325 */
326 public void setDurationAfterStart(ReadableDuration duration) {
327 long durationMillis = DateTimeUtils.getDurationMillis(duration);
328 setEndMillis(FieldUtils.safeAdd(getStartMillis(), durationMillis));
329 }
330
331 /**
332 * Sets the duration of this time interval, preserving the end instant.
333 *
334 * @param duration new duration for interval, null means zero length
335 * @throws IllegalArgumentException if the end is before the start
336 * @throws ArithmeticException if the start instant exceeds the capacity of a long
337 */
338 public void setDurationBeforeEnd(ReadableDuration duration) {
339 long durationMillis = DateTimeUtils.getDurationMillis(duration);
340 setStartMillis(FieldUtils.safeAdd(getEndMillis(), -durationMillis));
341 }
342
343 //-----------------------------------------------------------------------
344 /**
345 * Sets the period of this time interval, preserving the start instant
346 * and using the ISOChronology in the default zone for calculations.
347 *
348 * @param period new period for interval, null means zero length
349 * @throws IllegalArgumentException if the end is before the start
350 * @throws ArithmeticException if the end instant exceeds the capacity of a long
351 */
352 public void setPeriodAfterStart(ReadablePeriod period) {
353 if (period == null) {
354 setEndMillis(getStartMillis());
355 } else {
356 setEndMillis(getChronology().add(period, getStartMillis(), 1));
357 }
358 }
359
360 /**
361 * Sets the period of this time interval, preserving the end instant
362 * and using the ISOChronology in the default zone for calculations.
363 *
364 * @param period new period for interval, null means zero length
365 * @throws IllegalArgumentException if the end is before the start
366 * @throws ArithmeticException if the start instant exceeds the capacity of a long
367 */
368 public void setPeriodBeforeEnd(ReadablePeriod period) {
369 if (period == null) {
370 setStartMillis(getEndMillis());
371 } else {
372 setStartMillis(getChronology().add(period, getEndMillis(), -1));
373 }
374 }
375
376 //-----------------------------------------------------------------------
377 /**
378 * Clone this object without having to cast the returned object.
379 *
380 * @return a clone of the this object.
381 */
382 public MutableInterval copy() {
383 return (MutableInterval) clone();
384 }
385
386 /**
387 * Clone this object.
388 *
389 * @return a clone of this object.
390 */
391 public Object clone() {
392 try {
393 return super.clone();
394 } catch (CloneNotSupportedException ex) {
395 throw new InternalError("Clone error");
396 }
397 }
398
399 }