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 */ 016package org.joda.time; 017 018import java.io.Serializable; 019 020import org.joda.time.base.BaseInterval; 021import org.joda.time.chrono.ISOChronology; 022import org.joda.time.format.ISODateTimeFormat; 023import 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 */ 050public 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}