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 */ 016package org.joda.time; 017 018import java.io.Serializable; 019 020import org.joda.time.base.BaseInterval; 021import org.joda.time.field.FieldUtils; 022import org.joda.time.format.ISODateTimeFormat; 023import 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 */ 052public 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 * Constructs a zero length time interval from 1970-01-01 to 1970-01-01. 062 */ 063 public MutableInterval() { 064 super(0L, 0L, null); 065 } 066 067 /** 068 * Constructs an interval from a start and end instant with the ISO default chronology. 069 * 070 * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z. 071 * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z. 072 * @throws IllegalArgumentException if the end is before the start 073 */ 074 public MutableInterval(long startInstant, long endInstant) { 075 super(startInstant, endInstant, null); 076 } 077 078 /** 079 * Constructs an interval from a start and end instant with a chronology. 080 * 081 * @param chronology the chronology to use, null is ISO default 082 * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z. 083 * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z. 084 * @throws IllegalArgumentException if the end is before the start 085 */ 086 public MutableInterval(long startInstant, long endInstant, Chronology chronology) { 087 super(startInstant, endInstant, chronology); 088 } 089 090 /** 091 * Constructs an interval from a start and end instant. 092 * <p> 093 * The chronology used is that of the start instant. 094 * 095 * @param start start of this interval, null means now 096 * @param end end of this interval, null means now 097 * @throws IllegalArgumentException if the end is before the start 098 */ 099 public MutableInterval(ReadableInstant start, ReadableInstant end) { 100 super(start, end); 101 } 102 103 /** 104 * Constructs an interval from a start instant and a duration. 105 * 106 * @param start start of this interval, null means now 107 * @param duration the duration of this interval, null means zero length 108 * @throws IllegalArgumentException if the end is before the start 109 * @throws ArithmeticException if the end instant exceeds the capacity of a long 110 */ 111 public MutableInterval(ReadableInstant start, ReadableDuration duration) { 112 super(start, duration); 113 } 114 115 /** 116 * Constructs an interval from a millisecond duration and an end instant. 117 * 118 * @param duration the duration of this interval, null means zero length 119 * @param end end of this interval, null means now 120 * @throws IllegalArgumentException if the end is before the start 121 * @throws ArithmeticException if the start instant exceeds the capacity of a long 122 */ 123 public MutableInterval(ReadableDuration duration, ReadableInstant end) { 124 super(duration, end); 125 } 126 127 /** 128 * Constructs an interval from a start instant and a time period. 129 * <p> 130 * When forming the interval, the chronology from the instant is used 131 * if present, otherwise the chronology of the period is used. 132 * 133 * @param start start of this interval, null means now 134 * @param period the period of this interval, null means zero length 135 * @throws IllegalArgumentException if the end is before the start 136 * @throws ArithmeticException if the end instant exceeds the capacity of a long 137 */ 138 public MutableInterval(ReadableInstant start, ReadablePeriod period) { 139 super(start, period); 140 } 141 142 /** 143 * Constructs an interval from a time period and an end instant. 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 period the period of this interval, null means zero length 149 * @param end end of this interval, null means now 150 * @throws IllegalArgumentException if the end is before the start 151 * @throws ArithmeticException if the start instant exceeds the capacity of a long 152 */ 153 public MutableInterval(ReadablePeriod period, ReadableInstant end) { 154 super(period, end); 155 } 156 157 /** 158 * Constructs a time interval by converting or copying from another object. 159 * <p> 160 * The recognised object types are defined in 161 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 162 * include ReadableInterval and String. 163 * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()} 164 * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime', 165 * 'datetime/period' or 'period/datetime'. 166 * 167 * @param interval the time interval to copy 168 * @throws IllegalArgumentException if the interval is invalid 169 */ 170 public MutableInterval(Object interval) { 171 super(interval, null); 172 } 173 174 /** 175 * Constructs a time interval by converting or copying from another object, 176 * overriding the chronology. 177 * <p> 178 * The recognised object types are defined in 179 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 180 * include ReadableInterval and String. 181 * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()} 182 * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime', 183 * 'datetime/period' or 'period/datetime'. 184 * 185 * @param interval the time interval to copy 186 * @param chronology the chronology to use, null means ISO default 187 * @throws IllegalArgumentException if the interval is invalid 188 */ 189 public MutableInterval(Object interval, Chronology chronology) { 190 super(interval, chronology); 191 } 192 193 //----------------------------------------------------------------------- 194 /** 195 * Sets this interval from two millisecond instants retaining the chronology. 196 * 197 * @param startInstant the start of the time interval 198 * @param endInstant the start of the time interval 199 * @throws IllegalArgumentException if the end is before the start 200 */ 201 public void setInterval(long startInstant, long endInstant) { 202 super.setInterval(startInstant, endInstant, getChronology()); 203 } 204 205 /** 206 * Sets this interval to be the same as another. 207 * 208 * @param interval the interval to copy 209 * @throws IllegalArgumentException if the interval is null 210 */ 211 public void setInterval(ReadableInterval interval) { 212 if (interval == null) { 213 throw new IllegalArgumentException("Interval must not be null"); 214 } 215 long startMillis = interval.getStartMillis(); 216 long endMillis = interval.getEndMillis(); 217 Chronology chrono = interval.getChronology(); 218 super.setInterval(startMillis, endMillis, chrono); 219 } 220 221 /** 222 * Sets this interval from two instants, replacing the chronology with 223 * that from the start instant. 224 * 225 * @param start the start of the time interval 226 * @param end the start of the time interval 227 * @throws IllegalArgumentException if the end is before the start 228 */ 229 public void setInterval(ReadableInstant start, ReadableInstant end) { 230 if (start == null && end == null) { 231 long now = DateTimeUtils.currentTimeMillis(); 232 setInterval(now, now); 233 } else { 234 long startMillis = DateTimeUtils.getInstantMillis(start); 235 long endMillis = DateTimeUtils.getInstantMillis(end); 236 Chronology chrono = DateTimeUtils.getInstantChronology(start); 237 super.setInterval(startMillis, endMillis, chrono); 238 } 239 } 240 241 //----------------------------------------------------------------------- 242 /** 243 * Sets the chronology of this time interval. 244 * 245 * @param chrono the chronology to use, null means ISO default 246 */ 247 public void setChronology(Chronology chrono) { 248 super.setInterval(getStartMillis(), getEndMillis(), chrono); 249 } 250 251 /** 252 * Sets the start of this time interval. 253 * 254 * @param startInstant the start of the time interval, 255 * millisecond instant from 1970-01-01T00:00:00Z 256 * @throws IllegalArgumentException if the end is before the start 257 */ 258 public void setStartMillis(long startInstant) { 259 super.setInterval(startInstant, getEndMillis(), getChronology()); 260 } 261 262 /** 263 * Sets the start of this time interval as an Instant. 264 * 265 * @param start the start of the time interval, null means now 266 * @throws IllegalArgumentException if the end is before the start 267 */ 268 public void setStart(ReadableInstant start) { 269 long startMillis = DateTimeUtils.getInstantMillis(start); 270 super.setInterval(startMillis, getEndMillis(), getChronology()); 271 } 272 273 /** 274 * Sets the end of this time interval. 275 * 276 * @param endInstant the end of the time interval, 277 * millisecond instant from 1970-01-01T00:00:00Z 278 * @throws IllegalArgumentException if the end is before the start 279 */ 280 public void setEndMillis(long endInstant) { 281 super.setInterval(getStartMillis(), endInstant, getChronology()); 282 } 283 284 /** 285 * Sets the end of this time interval as an Instant. 286 * 287 * @param end the end of the time interval, null means now 288 * @throws IllegalArgumentException if the end is before the start 289 */ 290 public void setEnd(ReadableInstant end) { 291 long endMillis = DateTimeUtils.getInstantMillis(end); 292 super.setInterval(getStartMillis(), endMillis, getChronology()); 293 } 294 295 //----------------------------------------------------------------------- 296 /** 297 * Sets the duration of this time interval, preserving the start instant. 298 * 299 * @param duration new duration for interval 300 * @throws IllegalArgumentException if the end is before the start 301 * @throws ArithmeticException if the end instant exceeds the capacity of a long 302 */ 303 public void setDurationAfterStart(long duration) { 304 setEndMillis(FieldUtils.safeAdd(getStartMillis(), duration)); 305 } 306 307 /** 308 * Sets the duration of this time interval, preserving the end instant. 309 * 310 * @param duration new duration for interval 311 * @throws IllegalArgumentException if the end is before the start 312 * @throws ArithmeticException if the start instant exceeds the capacity of a long 313 */ 314 public void setDurationBeforeEnd(long duration) { 315 setStartMillis(FieldUtils.safeAdd(getEndMillis(), -duration)); 316 } 317 318 //----------------------------------------------------------------------- 319 /** 320 * Sets the duration of this time interval, preserving the start instant. 321 * 322 * @param duration new duration for interval, null means zero length 323 * @throws IllegalArgumentException if the end is before the start 324 * @throws ArithmeticException if the end instant exceeds the capacity of a long 325 */ 326 public void setDurationAfterStart(ReadableDuration duration) { 327 long durationMillis = DateTimeUtils.getDurationMillis(duration); 328 setEndMillis(FieldUtils.safeAdd(getStartMillis(), durationMillis)); 329 } 330 331 /** 332 * Sets the duration of this time interval, preserving the end instant. 333 * 334 * @param duration new duration for interval, null means zero length 335 * @throws IllegalArgumentException if the end is before the start 336 * @throws ArithmeticException if the start instant exceeds the capacity of a long 337 */ 338 public void setDurationBeforeEnd(ReadableDuration duration) { 339 long durationMillis = DateTimeUtils.getDurationMillis(duration); 340 setStartMillis(FieldUtils.safeAdd(getEndMillis(), -durationMillis)); 341 } 342 343 //----------------------------------------------------------------------- 344 /** 345 * Sets the period of this time interval, preserving the start instant 346 * and using the ISOChronology in the default zone for calculations. 347 * 348 * @param period new period for interval, null means zero length 349 * @throws IllegalArgumentException if the end is before the start 350 * @throws ArithmeticException if the end instant exceeds the capacity of a long 351 */ 352 public void setPeriodAfterStart(ReadablePeriod period) { 353 if (period == null) { 354 setEndMillis(getStartMillis()); 355 } else { 356 setEndMillis(getChronology().add(period, getStartMillis(), 1)); 357 } 358 } 359 360 /** 361 * Sets the period of this time interval, preserving the end instant 362 * and using the ISOChronology in the default zone for calculations. 363 * 364 * @param period new period for interval, null means zero length 365 * @throws IllegalArgumentException if the end is before the start 366 * @throws ArithmeticException if the start instant exceeds the capacity of a long 367 */ 368 public void setPeriodBeforeEnd(ReadablePeriod period) { 369 if (period == null) { 370 setStartMillis(getEndMillis()); 371 } else { 372 setStartMillis(getChronology().add(period, getEndMillis(), -1)); 373 } 374 } 375 376 //----------------------------------------------------------------------- 377 /** 378 * Clone this object without having to cast the returned object. 379 * 380 * @return a clone of the this object. 381 */ 382 public MutableInterval copy() { 383 return (MutableInterval) clone(); 384 } 385 386 /** 387 * Clone this object. 388 * 389 * @return a clone of this object. 390 */ 391 public Object clone() { 392 try { 393 return super.clone(); 394 } catch (CloneNotSupportedException ex) { 395 throw new InternalError("Clone error"); 396 } 397 } 398 399}