View Javadoc

1   /*
2    *  Copyright 2001-2006 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.chrono.ISOChronology;
22  import org.joda.time.format.ISODateTimeFormat;
23  import org.joda.time.format.ISOPeriodFormat;
24  
25  /**
26   * Interval is the standard implementation of an immutable 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   * Interval is thread-safe and immutable.
43   *
44   * @author Brian S O'Neill
45   * @author Sean Geoghegan
46   * @author Stephen Colebourne
47   * @author Julen Parra
48   * @since 1.0
49   */
50  public final class Interval
51          extends BaseInterval
52          implements ReadableInterval, Serializable {
53  
54      /** Serialization version */
55      private static final long serialVersionUID = 4922451897541386752L;
56  
57      //-----------------------------------------------------------------------
58      /**
59       * Parses a {@code Interval} from the specified string.
60       * <p>
61       * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
62       * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
63       * 'datetime/period' or 'period/datetime'.
64       * 
65       * @param str  the string to parse, not null
66       * @since 2.0
67       */
68      public static Interval parse(String str) {
69          return new Interval(str);
70      }
71  
72      //-----------------------------------------------------------------------
73      /**
74       * Constructs an interval from a start and end instant with the ISO
75       * default chronology in the default time zone.
76       * 
77       * @param startInstant  start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
78       * @param endInstant  end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
79       * @throws IllegalArgumentException if the end is before the start
80       */
81      public Interval(long startInstant, long endInstant) {
82          super(startInstant, endInstant, null);
83      }
84  
85      /**
86       * Constructs an interval from a start and end instant with the ISO
87       * default chronology in the specified time zone.
88       * 
89       * @param startInstant  start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
90       * @param endInstant  end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
91       * @param zone  the time zone to use, null means default zone
92       * @throws IllegalArgumentException if the end is before the start
93       * @since 1.5
94       */
95      public Interval(long startInstant, long endInstant, DateTimeZone zone) {
96          super(startInstant, endInstant, ISOChronology.getInstance(zone));
97      }
98  
99      /**
100      * Constructs an interval from a start and end instant with the
101      * specified chronology.
102      * 
103      * @param chronology  the chronology to use, null is ISO default
104      * @param startInstant  start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
105      * @param endInstant  end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
106      * @throws IllegalArgumentException if the end is before the start
107      */
108     public Interval(long startInstant, long endInstant, Chronology chronology) {
109         super(startInstant, endInstant, chronology);
110     }
111 
112     /**
113      * Constructs an interval from a start and end instant.
114      * <p>
115      * The chronology used is that of the start instant.
116      * 
117      * @param start  start of this interval, null means now
118      * @param end  end of this interval, null means now
119      * @throws IllegalArgumentException if the end is before the start
120      */
121     public Interval(ReadableInstant start, ReadableInstant end) {
122         super(start, end);
123     }
124 
125     /**
126      * Constructs an interval from a start instant and a duration.
127      * 
128      * @param start  start of this interval, null means now
129      * @param duration  the duration of this interval, null means zero length
130      * @throws IllegalArgumentException if the end is before the start
131      * @throws ArithmeticException if the end instant exceeds the capacity of a long
132      */
133     public Interval(ReadableInstant start, ReadableDuration duration) {
134         super(start, duration);
135     }
136 
137     /**
138      * Constructs an interval from a millisecond duration and an end instant.
139      * 
140      * @param duration  the duration of this interval, null means zero length
141      * @param end  end of this interval, null means now
142      * @throws IllegalArgumentException if the end is before the start
143      * @throws ArithmeticException if the start instant exceeds the capacity of a long
144      */
145     public Interval(ReadableDuration duration, ReadableInstant end) {
146         super(duration, end);
147     }
148 
149     /**
150      * Constructs an interval from a start instant and a time period.
151      * <p>
152      * When forming the interval, the chronology from the instant is used
153      * if present, otherwise the chronology of the period is used.
154      * 
155      * @param start  start of this interval, null means now
156      * @param period  the period of this interval, null means zero length
157      * @throws IllegalArgumentException if the end is before the start
158      * @throws ArithmeticException if the end instant exceeds the capacity of a long
159      */
160     public Interval(ReadableInstant start, ReadablePeriod period) {
161         super(start, period);
162     }
163 
164     /**
165      * Constructs an interval from a time period and an end instant.
166      * <p>
167      * When forming the interval, the chronology from the instant is used
168      * if present, otherwise the chronology of the period is used.
169      * 
170      * @param period  the period of this interval, null means zero length
171      * @param end  end of this interval, null means now
172      * @throws IllegalArgumentException if the end is before the start
173      * @throws ArithmeticException if the start instant exceeds the capacity of a long
174      */
175     public Interval(ReadablePeriod period, ReadableInstant end) {
176         super(period, end);
177     }
178 
179     /**
180      * Constructs a time interval by converting or copying from another object.
181      * <p>
182      * The recognised object types are defined in
183      * {@link org.joda.time.convert.ConverterManager ConverterManager} and
184      * include ReadableInterval and String.
185      * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
186      * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
187      * 'datetime/period' or 'period/datetime'.
188      * 
189      * @param interval  the time interval to copy
190      * @throws IllegalArgumentException if the interval is invalid
191      */
192     public Interval(Object interval) {
193         super(interval, null);
194     }
195 
196     /**
197      * Constructs a time interval by converting or copying from another object,
198      * overriding the chronology.
199      * <p>
200      * The recognised object types are defined in
201      * {@link org.joda.time.convert.ConverterManager ConverterManager} and
202      * include ReadableInterval and String.
203      * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
204      * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
205      * 'datetime/period' or 'period/datetime'.
206      * 
207      * @param interval  the time interval to copy
208      * @param chronology  the chronology to use, null means ISO default
209      * @throws IllegalArgumentException if the interval is invalid
210      */
211     public Interval(Object interval, Chronology chronology) {
212         super(interval, chronology);
213     }
214 
215     //-----------------------------------------------------------------------
216     /**
217      * Get this interval as an immutable <code>Interval</code> object
218      * by returning <code>this</code>.
219      *
220      * @return <code>this</code>
221      */
222     public Interval toInterval() {
223         return this;
224     }
225 
226     //-----------------------------------------------------------------------
227     /**
228      * Gets the overlap between this interval and another interval.
229      * <p>
230      * Intervals are inclusive of the start instant and exclusive of the end.
231      * An interval overlaps another if it shares some common part of the
232      * datetime continuum. This method returns the amount of the overlap,
233      * only if the intervals actually do overlap.
234      * If the intervals do not overlap, then null is returned.
235      * <p>
236      * When two intervals are compared the result is one of three states:
237      * (a) they abut, (b) there is a gap between them, (c) they overlap.
238      * The abuts state takes precedence over the other two, thus a zero duration
239      * interval at the start of a larger interval abuts and does not overlap.
240      * <p>
241      * The chronology of the returned interval is the same as that of
242      * this interval (the chronology of the interval parameter is not used).
243      * Note that the use of the chronology was only correctly implemented
244      * in version 1.3.
245      *
246      * @param interval  the interval to examine, null means now
247      * @return the overlap interval, null if no overlap
248      * @since 1.1
249      */
250     public Interval overlap(ReadableInterval interval) {
251         interval = DateTimeUtils.getReadableInterval(interval);
252         if (overlaps(interval) == false) {
253             return null;
254         }
255         long start = Math.max(getStartMillis(), interval.getStartMillis());
256         long end = Math.min(getEndMillis(), interval.getEndMillis());
257         return new Interval(start, end, getChronology());
258     }
259 
260     //-----------------------------------------------------------------------
261     /**
262      * Gets the gap between this interval and another interval.
263      * The other interval can be either before or after this interval.
264      * <p>
265      * Intervals are inclusive of the start instant and exclusive of the end.
266      * An interval has a gap to another interval if there is a non-zero
267      * duration between them. This method returns the amount of the gap only
268      * if the intervals do actually have a gap between them.
269      * If the intervals overlap or abut, then null is returned.
270      * <p>
271      * When two intervals are compared the result is one of three states:
272      * (a) they abut, (b) there is a gap between them, (c) they overlap.
273      * The abuts state takes precedence over the other two, thus a zero duration
274      * interval at the start of a larger interval abuts and does not overlap.
275      * <p>
276      * The chronology of the returned interval is the same as that of
277      * this interval (the chronology of the interval parameter is not used).
278      * Note that the use of the chronology was only correctly implemented
279      * in version 1.3.
280      *
281      * @param interval  the interval to examine, null means now
282      * @return the gap interval, null if no gap
283      * @since 1.1
284      */
285     public Interval gap(ReadableInterval interval) {
286         interval = DateTimeUtils.getReadableInterval(interval);
287         long otherStart = interval.getStartMillis();
288         long otherEnd = interval.getEndMillis();
289         long thisStart = getStartMillis();
290         long thisEnd = getEndMillis();
291         if (thisStart > otherEnd) {
292             return new Interval(otherEnd, thisStart, getChronology());
293         } else if (otherStart > thisEnd) {
294             return new Interval(thisEnd, otherStart, getChronology());
295         } else {
296             return null;
297         }
298     }
299 
300     //-----------------------------------------------------------------------
301     /**
302      * Does this interval abut with the interval specified.
303      * <p>
304      * Intervals are inclusive of the start instant and exclusive of the end.
305      * An interval abuts if it starts immediately after, or ends immediately
306      * before this interval without overlap.
307      * A zero duration interval abuts with itself.
308      * <p>
309      * When two intervals are compared the result is one of three states:
310      * (a) they abut, (b) there is a gap between them, (c) they overlap.
311      * The abuts state takes precedence over the other two, thus a zero duration
312      * interval at the start of a larger interval abuts and does not overlap.
313      * <p>
314      * For example:
315      * <pre>
316      * [09:00 to 10:00) abuts [08:00 to 08:30)  = false (completely before)
317      * [09:00 to 10:00) abuts [08:00 to 09:00)  = true
318      * [09:00 to 10:00) abuts [08:00 to 09:01)  = false (overlaps)
319      * 
320      * [09:00 to 10:00) abuts [09:00 to 09:00)  = true
321      * [09:00 to 10:00) abuts [09:00 to 09:01)  = false (overlaps)
322      * 
323      * [09:00 to 10:00) abuts [10:00 to 10:00)  = true
324      * [09:00 to 10:00) abuts [10:00 to 10:30)  = true
325      * 
326      * [09:00 to 10:00) abuts [10:30 to 11:00)  = false (completely after)
327      * 
328      * [14:00 to 14:00) abuts [14:00 to 14:00)  = true
329      * [14:00 to 14:00) abuts [14:00 to 15:00)  = true
330      * [14:00 to 14:00) abuts [13:00 to 14:00)  = true
331      * </pre>
332      *
333      * @param interval  the interval to examine, null means now
334      * @return true if the interval abuts
335      * @since 1.1
336      */
337     public boolean abuts(ReadableInterval interval) {
338         if (interval == null) {
339             long now = DateTimeUtils.currentTimeMillis();
340             return (getStartMillis() == now || getEndMillis() == now);
341         } else {
342             return (interval.getEndMillis() == getStartMillis() ||
343                     getEndMillis() == interval.getStartMillis());
344         }
345     }
346 
347     //-----------------------------------------------------------------------
348     /**
349      * Creates a new interval with the same start and end, but a different chronology.
350      *
351      * @param chronology  the chronology to use, null means ISO default
352      * @return an interval with a different chronology
353      */
354     public Interval withChronology(Chronology chronology) {
355         if (getChronology() == chronology) {
356             return this;
357         }
358         return new Interval(getStartMillis(), getEndMillis(), chronology);
359     }
360 
361     /**
362      * Creates a new interval with the specified start millisecond instant.
363      *
364      * @param startInstant  the start instant for the new interval
365      * @return an interval with the end from this interval and the specified start
366      * @throws IllegalArgumentException if the resulting interval has end before start
367      */
368     public Interval withStartMillis(long startInstant) {
369         if (startInstant == getStartMillis()) {
370             return this;
371         }
372         return new Interval(startInstant, getEndMillis(), getChronology());
373     }
374 
375     /**
376      * Creates a new interval with the specified start instant.
377      *
378      * @param start  the start instant for the new interval, null means now
379      * @return an interval with the end from this interval and the specified start
380      * @throws IllegalArgumentException if the resulting interval has end before start
381      */
382     public Interval withStart(ReadableInstant start) {
383         long startMillis = DateTimeUtils.getInstantMillis(start);
384         return withStartMillis(startMillis);
385     }
386 
387     /**
388      * Creates a new interval with the specified start millisecond instant.
389      *
390      * @param endInstant  the end instant for the new interval
391      * @return an interval with the start from this interval and the specified end
392      * @throws IllegalArgumentException if the resulting interval has end before start
393      */
394     public Interval withEndMillis(long endInstant) {
395         if (endInstant == getEndMillis()) {
396             return this;
397         }
398         return new Interval(getStartMillis(), endInstant, getChronology());
399     }
400 
401     /**
402      * Creates a new interval with the specified end instant.
403      *
404      * @param end  the end instant for the new interval, null means now
405      * @return an interval with the start from this interval and the specified end
406      * @throws IllegalArgumentException if the resulting interval has end before start
407      */
408     public Interval withEnd(ReadableInstant end) {
409         long endMillis = DateTimeUtils.getInstantMillis(end);
410         return withEndMillis(endMillis);
411     }
412 
413     //-----------------------------------------------------------------------
414     /**
415      * Creates a new interval with the specified duration after the start instant.
416      *
417      * @param duration  the duration to add to the start to get the new end instant, null means zero
418      * @return an interval with the start from this interval and a calculated end
419      * @throws IllegalArgumentException if the duration is negative
420      */
421     public Interval withDurationAfterStart(ReadableDuration duration) {
422         long durationMillis = DateTimeUtils.getDurationMillis(duration);
423         if (durationMillis == toDurationMillis()) {
424             return this;
425         }
426         Chronology chrono = getChronology();
427         long startMillis = getStartMillis();
428         long endMillis = chrono.add(startMillis, durationMillis, 1);
429         return new Interval(startMillis, endMillis, chrono);
430     }
431 
432     /**
433      * Creates a new interval with the specified duration before the end instant.
434      *
435      * @param duration  the duration to add to the start to get the new end instant, null means zero
436      * @return an interval with the start from this interval and a calculated end
437      * @throws IllegalArgumentException if the duration is negative
438      */
439     public Interval withDurationBeforeEnd(ReadableDuration duration) {
440         long durationMillis = DateTimeUtils.getDurationMillis(duration);
441         if (durationMillis == toDurationMillis()) {
442             return this;
443         }
444         Chronology chrono = getChronology();
445         long endMillis = getEndMillis();
446         long startMillis = chrono.add(endMillis, durationMillis, -1);
447         return new Interval(startMillis, endMillis, chrono);
448     }
449 
450     //-----------------------------------------------------------------------
451     /**
452      * Creates a new interval with the specified period after the start instant.
453      *
454      * @param period  the period to add to the start to get the new end instant, null means zero
455      * @return an interval with the start from this interval and a calculated end
456      * @throws IllegalArgumentException if the period is negative
457      */
458     public Interval withPeriodAfterStart(ReadablePeriod period) {
459         if (period == null) {
460             return withDurationAfterStart(null);
461         }
462         Chronology chrono = getChronology();
463         long startMillis = getStartMillis();
464         long endMillis = chrono.add(period, startMillis, 1);
465         return new Interval(startMillis, endMillis, chrono);
466     }
467 
468     /**
469      * Creates a new interval with the specified period before the end instant.
470      *
471      * @param period  the period to add to the start to get the new end instant, null means zero
472      * @return an interval with the start from this interval and a calculated end
473      * @throws IllegalArgumentException if the period is negative
474      */
475     public Interval withPeriodBeforeEnd(ReadablePeriod period) {
476         if (period == null) {
477             return withDurationBeforeEnd(null);
478         }
479         Chronology chrono = getChronology();
480         long endMillis = getEndMillis();
481         long startMillis = chrono.add(period, endMillis, -1);
482         return new Interval(startMillis, endMillis, chrono);
483     }
484 
485 }