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