View Javadoc

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 }