/*
* Copyright 2001-2005 Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.joda.time;
import java.io.Serializable;
import org.joda.time.base.BaseInterval;
import org.joda.time.field.FieldUtils;
import org.joda.time.format.ISODateTimeFormat;
import org.joda.time.format.ISOPeriodFormat;
/**
* MutableInterval is the standard implementation of a mutable time interval.
* <p>
* A time interval represents a period of time between two instants.
* Intervals are inclusive of the start instant and exclusive of the end.
* The end instant is always greater than or equal to the start instant.
* <p>
* Intervals have a fixed millisecond duration.
* This is the difference between the start and end instants.
* The duration is represented separately by {@link ReadableDuration}.
* As a result, intervals are not comparable.
* To compare the length of two intervals, you should compare their durations.
* <p>
* An interval can also be converted to a {@link ReadablePeriod}.
* This represents the difference between the start and end points in terms of fields
* such as years and days.
* <p>
* If performing significant calculations on an interval, it may be faster to
* convert an Interval object to a MutableInterval one.
* <p>
* MutableInterval is mutable and not thread-safe, unless concurrent threads
* are not invoking mutator methods.
*
* @author Stephen Colebourne
* @author Brian S O'Neill
* @since 1.0
*/
public class MutableInterval
extends BaseInterval
implements ReadWritableInterval, Cloneable, Serializable {
/** Serialization version */
private static final long serialVersionUID = -5982824024992428470L;
//-----------------------------------------------------------------------
/**
* Parses a {@code MutableInterval} from the specified string.
* <p>
* The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
* and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
* 'datetime/period' or 'period/datetime'.
*
* @param str the string to parse, not null
* @since 2.0
*/
public static MutableInterval parse(String str) {
return new MutableInterval(str);
}
//-----------------------------------------------------------------------
/**
* Constructs a zero length time interval from 1970-01-01 to 1970-01-01.
*/
public MutableInterval() {
super(0L, 0L, null);
}
/**
* Constructs an interval from a start and end instant with the ISO default chronology.
*
* @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
* @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
* @throws IllegalArgumentException if the end is before the start
*/
public MutableInterval(long startInstant, long endInstant) {
super(startInstant, endInstant, null);
}
/**
* Constructs an interval from a start and end instant with a chronology.
*
* @param chronology the chronology to use, null is ISO default
* @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
* @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
* @throws IllegalArgumentException if the end is before the start
*/
public MutableInterval(long startInstant, long endInstant, Chronology chronology) {
super(startInstant, endInstant, chronology);
}
/**
* Constructs an interval from a start and end instant.
* <p>
* The chronology used is that of the start instant.
*
* @param start start of this interval, null means now
* @param end end of this interval, null means now
* @throws IllegalArgumentException if the end is before the start
*/
public MutableInterval(ReadableInstant start, ReadableInstant end) {
super(start, end);
}
/**
* Constructs an interval from a start instant and a duration.
*
* @param start start of this interval, null means now
* @param duration the duration of this interval, null means zero length
* @throws IllegalArgumentException if the end is before the start
* @throws ArithmeticException if the end instant exceeds the capacity of a long
*/
public MutableInterval(ReadableInstant start, ReadableDuration duration) {
super(start, duration);
}
/**
* Constructs an interval from a millisecond duration and an end instant.
*
* @param duration the duration of this interval, null means zero length
* @param end end of this interval, null means now
* @throws IllegalArgumentException if the end is before the start
* @throws ArithmeticException if the start instant exceeds the capacity of a long
*/
public MutableInterval(ReadableDuration duration, ReadableInstant end) {
super(duration, end);
}
/**
* Constructs an interval from a start instant and a time period.
* <p>
* When forming the interval, the chronology from the instant is used
* if present, otherwise the chronology of the period is used.
*
* @param start start of this interval, null means now
* @param period the period of this interval, null means zero length
* @throws IllegalArgumentException if the end is before the start
* @throws ArithmeticException if the end instant exceeds the capacity of a long
*/
public MutableInterval(ReadableInstant start, ReadablePeriod period) {
super(start, period);
}
/**
* Constructs an interval from a time period and an end instant.
* <p>
* When forming the interval, the chronology from the instant is used
* if present, otherwise the chronology of the period is used.
*
* @param period the period of this interval, null means zero length
* @param end end of this interval, null means now
* @throws IllegalArgumentException if the end is before the start
* @throws ArithmeticException if the start instant exceeds the capacity of a long
*/
public MutableInterval(ReadablePeriod period, ReadableInstant end) {
super(period, end);
}
/**
* Constructs a time interval by converting or copying from another object.
* <p>
* The recognised object types are defined in
* {@link org.joda.time.convert.ConverterManager ConverterManager} and
* include ReadableInterval and String.
* The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
* and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
* 'datetime/period' or 'period/datetime'.
*
* @param interval the time interval to copy
* @throws IllegalArgumentException if the interval is invalid
*/
public MutableInterval(Object interval) {
super(interval, null);
}
/**
* Constructs a time interval by converting or copying from another object,
* overriding the chronology.
* <p>
* The recognised object types are defined in
* {@link org.joda.time.convert.ConverterManager ConverterManager} and
* include ReadableInterval and String.
* The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
* and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
* 'datetime/period' or 'period/datetime'.
*
* @param interval the time interval to copy
* @param chronology the chronology to use, null means ISO default
* @throws IllegalArgumentException if the interval is invalid
*/
public MutableInterval(Object interval, Chronology chronology) {
super(interval, chronology);
}
//-----------------------------------------------------------------------
/**
* Sets this interval from two millisecond instants retaining the chronology.
*
* @param startInstant the start of the time interval
* @param endInstant the start of the time interval
* @throws IllegalArgumentException if the end is before the start
*/
public void setInterval(long startInstant, long endInstant) {
super.setInterval(startInstant, endInstant, getChronology());
}
/**
* Sets this interval to be the same as another.
*
* @param interval the interval to copy
* @throws IllegalArgumentException if the interval is null
*/
public void setInterval(ReadableInterval interval) {
if (interval == null) {
throw new IllegalArgumentException("Interval must not be null");
}
long startMillis = interval.getStartMillis();
long endMillis = interval.getEndMillis();
Chronology chrono = interval.getChronology();
super.setInterval(startMillis, endMillis, chrono);
}
/**
* Sets this interval from two instants, replacing the chronology with
* that from the start instant.
*
* @param start the start of the time interval
* @param end the start of the time interval
* @throws IllegalArgumentException if the end is before the start
*/
public void setInterval(ReadableInstant start, ReadableInstant end) {
if (start == null && end == null) {
long now = DateTimeUtils.currentTimeMillis();
setInterval(now, now);
} else {
long startMillis = DateTimeUtils.getInstantMillis(start);
long endMillis = DateTimeUtils.getInstantMillis(end);
Chronology chrono = DateTimeUtils.getInstantChronology(start);
super.setInterval(startMillis, endMillis, chrono);
}
}
//-----------------------------------------------------------------------
/**
* Sets the chronology of this time interval.
*
* @param chrono the chronology to use, null means ISO default
*/
public void setChronology(Chronology chrono) {
super.setInterval(getStartMillis(), getEndMillis(), chrono);
}
/**
* Sets the start of this time interval.
*
* @param startInstant the start of the time interval,
* millisecond instant from 1970-01-01T00:00:00Z
* @throws IllegalArgumentException if the end is before the start
*/
public void setStartMillis(long startInstant) {
super.setInterval(startInstant, getEndMillis(), getChronology());
}
/**
* Sets the start of this time interval as an Instant.
*
* @param start the start of the time interval, null means now
* @throws IllegalArgumentException if the end is before the start
*/
public void setStart(ReadableInstant start) {
long startMillis = DateTimeUtils.getInstantMillis(start);
super.setInterval(startMillis, getEndMillis(), getChronology());
}
/**
* Sets the end of this time interval.
*
* @param endInstant the end of the time interval,
* millisecond instant from 1970-01-01T00:00:00Z
* @throws IllegalArgumentException if the end is before the start
*/
public void setEndMillis(long endInstant) {
super.setInterval(getStartMillis(), endInstant, getChronology());
}
/**
* Sets the end of this time interval as an Instant.
*
* @param end the end of the time interval, null means now
* @throws IllegalArgumentException if the end is before the start
*/
public void setEnd(ReadableInstant end) {
long endMillis = DateTimeUtils.getInstantMillis(end);
super.setInterval(getStartMillis(), endMillis, getChronology());
}
//-----------------------------------------------------------------------
/**
* Sets the duration of this time interval, preserving the start instant.
*
* @param duration new duration for interval
* @throws IllegalArgumentException if the end is before the start
* @throws ArithmeticException if the end instant exceeds the capacity of a long
*/
public void setDurationAfterStart(long duration) {
setEndMillis(FieldUtils.safeAdd(getStartMillis(), duration));
}
/**
* Sets the duration of this time interval, preserving the end instant.
*
* @param duration new duration for interval
* @throws IllegalArgumentException if the end is before the start
* @throws ArithmeticException if the start instant exceeds the capacity of a long
*/
public void setDurationBeforeEnd(long duration) {
setStartMillis(FieldUtils.safeAdd(getEndMillis(), -duration));
}
//-----------------------------------------------------------------------
/**
* Sets the duration of this time interval, preserving the start instant.
*
* @param duration new duration for interval, null means zero length
* @throws IllegalArgumentException if the end is before the start
* @throws ArithmeticException if the end instant exceeds the capacity of a long
*/
public void setDurationAfterStart(ReadableDuration duration) {
long durationMillis = DateTimeUtils.getDurationMillis(duration);
setEndMillis(FieldUtils.safeAdd(getStartMillis(), durationMillis));
}
/**
* Sets the duration of this time interval, preserving the end instant.
*
* @param duration new duration for interval, null means zero length
* @throws IllegalArgumentException if the end is before the start
* @throws ArithmeticException if the start instant exceeds the capacity of a long
*/
public void setDurationBeforeEnd(ReadableDuration duration) {
long durationMillis = DateTimeUtils.getDurationMillis(duration);
setStartMillis(FieldUtils.safeAdd(getEndMillis(), -durationMillis));
}
//-----------------------------------------------------------------------
/**
* Sets the period of this time interval, preserving the start instant
* and using the ISOChronology in the default zone for calculations.
*
* @param period new period for interval, null means zero length
* @throws IllegalArgumentException if the end is before the start
* @throws ArithmeticException if the end instant exceeds the capacity of a long
*/
public void setPeriodAfterStart(ReadablePeriod period) {
if (period == null) {
setEndMillis(getStartMillis());
} else {
setEndMillis(getChronology().add(period, getStartMillis(), 1));
}
}
/**
* Sets the period of this time interval, preserving the end instant
* and using the ISOChronology in the default zone for calculations.
*
* @param period new period for interval, null means zero length
* @throws IllegalArgumentException if the end is before the start
* @throws ArithmeticException if the start instant exceeds the capacity of a long
*/
public void setPeriodBeforeEnd(ReadablePeriod period) {
if (period == null) {
setStartMillis(getEndMillis());
} else {
setStartMillis(getChronology().add(period, getEndMillis(), -1));
}
}
//-----------------------------------------------------------------------
/**
* Clone this object without having to cast the returned object.
*
* @return a clone of the this object.
*/
public MutableInterval copy() {
return (MutableInterval) clone();
}
/**
* Clone this object.
*
* @return a clone of this object.
*/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
throw new InternalError("Clone error");
}
}
}