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 * Parses a {@code MutableInterval} from the specified string.
062 * <p>
063 * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
064 * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
065 * 'datetime/period' or 'period/datetime'.
066 *
067 * @param str the string to parse, not null
068 * @since 2.0
069 */
070 public static MutableInterval parse(String str) {
071 return new MutableInterval(str);
072 }
073
074 //-----------------------------------------------------------------------
075 /**
076 * Constructs a zero length time interval from 1970-01-01 to 1970-01-01.
077 */
078 public MutableInterval() {
079 super(0L, 0L, null);
080 }
081
082 /**
083 * Constructs an interval from a start and end instant with the ISO default chronology.
084 *
085 * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
086 * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
087 * @throws IllegalArgumentException if the end is before the start
088 */
089 public MutableInterval(long startInstant, long endInstant) {
090 super(startInstant, endInstant, null);
091 }
092
093 /**
094 * Constructs an interval from a start and end instant with a chronology.
095 *
096 * @param chronology the chronology to use, null is ISO default
097 * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
098 * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
099 * @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 }