001 /*
002 * Copyright 2001-2011 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.base;
017
018 import java.io.Serializable;
019
020 import org.joda.time.Chronology;
021 import org.joda.time.DateTimeUtils;
022 import org.joda.time.MutableInterval;
023 import org.joda.time.ReadWritableInterval;
024 import org.joda.time.ReadableDuration;
025 import org.joda.time.ReadableInstant;
026 import org.joda.time.ReadableInterval;
027 import org.joda.time.ReadablePeriod;
028 import org.joda.time.chrono.ISOChronology;
029 import org.joda.time.convert.ConverterManager;
030 import org.joda.time.convert.IntervalConverter;
031 import org.joda.time.field.FieldUtils;
032
033 /**
034 * BaseInterval is an abstract implementation of ReadableInterval that stores
035 * data in two <code>long</code> millisecond fields.
036 * <p>
037 * This class should generally not be used directly by API users.
038 * The {@link ReadableInterval} interface should be used when different
039 * kinds of interval objects are to be referenced.
040 * <p>
041 * BaseInterval subclasses may be mutable and not thread-safe.
042 *
043 * @author Brian S O'Neill
044 * @author Sean Geoghegan
045 * @author Stephen Colebourne
046 * @since 1.0
047 */
048 public abstract class BaseInterval
049 extends AbstractInterval
050 implements ReadableInterval, Serializable {
051
052 /** Serialization version */
053 private static final long serialVersionUID = 576586928732749278L;
054
055 /** The chronology of the interval */
056 private volatile Chronology iChronology;
057 /** The start of the interval */
058 private volatile long iStartMillis;
059 /** The end of the interval */
060 private volatile long iEndMillis;
061
062 /**
063 * Constructs an interval from a start and end instant.
064 *
065 * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
066 * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
067 * @param chrono the chronology to use, null is ISO default
068 * @throws IllegalArgumentException if the end is before the start
069 */
070 protected BaseInterval(long startInstant, long endInstant, Chronology chrono) {
071 super();
072 iChronology = DateTimeUtils.getChronology(chrono);
073 checkInterval(startInstant, endInstant);
074 iStartMillis = startInstant;
075 iEndMillis = endInstant;
076 }
077
078 /**
079 * Constructs an interval from a start and end instant.
080 *
081 * @param start start of this interval, null means now
082 * @param end end of this interval, null means now
083 * @throws IllegalArgumentException if the end is before the start
084 */
085 protected BaseInterval(ReadableInstant start, ReadableInstant end) {
086 super();
087 if (start == null && end == null) {
088 iStartMillis = iEndMillis = DateTimeUtils.currentTimeMillis();
089 iChronology = ISOChronology.getInstance();
090 } else {
091 iChronology = DateTimeUtils.getInstantChronology(start);
092 iStartMillis = DateTimeUtils.getInstantMillis(start);
093 iEndMillis = DateTimeUtils.getInstantMillis(end);
094 checkInterval(iStartMillis, iEndMillis);
095 }
096 }
097
098 /**
099 * Constructs an interval from a start instant and a duration.
100 *
101 * @param start start of this interval, null means now
102 * @param duration the duration of this interval, null means zero length
103 * @throws IllegalArgumentException if the end is before the start
104 * @throws ArithmeticException if the end instant exceeds the capacity of a long
105 */
106 protected BaseInterval(ReadableInstant start, ReadableDuration duration) {
107 super();
108 iChronology = DateTimeUtils.getInstantChronology(start);
109 iStartMillis = DateTimeUtils.getInstantMillis(start);
110 long durationMillis = DateTimeUtils.getDurationMillis(duration);
111 iEndMillis = FieldUtils.safeAdd(iStartMillis, durationMillis);
112 checkInterval(iStartMillis, iEndMillis);
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 protected BaseInterval(ReadableDuration duration, ReadableInstant end) {
124 super();
125 iChronology = DateTimeUtils.getInstantChronology(end);
126 iEndMillis = DateTimeUtils.getInstantMillis(end);
127 long durationMillis = DateTimeUtils.getDurationMillis(duration);
128 iStartMillis = FieldUtils.safeAdd(iEndMillis, -durationMillis);
129 checkInterval(iStartMillis, iEndMillis);
130 }
131
132 /**
133 * Constructs an interval from a start instant and a time period.
134 * <p>
135 * When forming the interval, the chronology from the instant is used
136 * if present, otherwise the chronology of the period is used.
137 *
138 * @param start start of this interval, null means now
139 * @param period the period of this interval, null means zero length
140 * @throws IllegalArgumentException if the end is before the start
141 * @throws ArithmeticException if the end instant exceeds the capacity of a long
142 */
143 protected BaseInterval(ReadableInstant start, ReadablePeriod period) {
144 super();
145 Chronology chrono = DateTimeUtils.getInstantChronology(start);
146 iChronology = chrono;
147 iStartMillis = DateTimeUtils.getInstantMillis(start);
148 if (period == null) {
149 iEndMillis = iStartMillis;
150 } else {
151 iEndMillis = chrono.add(period, iStartMillis, 1);
152 }
153 checkInterval(iStartMillis, iEndMillis);
154 }
155
156 /**
157 * Constructs an interval from a time period and an end instant.
158 * <p>
159 * When forming the interval, the chronology from the instant is used
160 * if present, otherwise the chronology of the period is used.
161 *
162 * @param period the period of this interval, null means zero length
163 * @param end end of this interval, null means now
164 * @throws IllegalArgumentException if the end is before the start
165 * @throws ArithmeticException if the start instant exceeds the capacity of a long
166 */
167 protected BaseInterval(ReadablePeriod period, ReadableInstant end) {
168 super();
169 Chronology chrono = DateTimeUtils.getInstantChronology(end);
170 iChronology = chrono;
171 iEndMillis = DateTimeUtils.getInstantMillis(end);
172 if (period == null) {
173 iStartMillis = iEndMillis;
174 } else {
175 iStartMillis = chrono.add(period, iEndMillis, -1);
176 }
177 checkInterval(iStartMillis, iEndMillis);
178 }
179
180 /**
181 * Constructs a time interval converting or copying from another object
182 * that describes an interval.
183 *
184 * @param interval the time interval to copy
185 * @param chrono the chronology to use, null means let converter decide
186 * @throws IllegalArgumentException if the interval is invalid
187 */
188 protected BaseInterval(Object interval, Chronology chrono) {
189 super();
190 IntervalConverter converter = ConverterManager.getInstance().getIntervalConverter(interval);
191 if (converter.isReadableInterval(interval, chrono)) {
192 ReadableInterval input = (ReadableInterval) interval;
193 iChronology = (chrono != null ? chrono : input.getChronology());
194 iStartMillis = input.getStartMillis();
195 iEndMillis = input.getEndMillis();
196 } else if (this instanceof ReadWritableInterval) {
197 converter.setInto((ReadWritableInterval) this, interval, chrono);
198 } else {
199 MutableInterval mi = new MutableInterval();
200 converter.setInto(mi, interval, chrono);
201 iChronology = mi.getChronology();
202 iStartMillis = mi.getStartMillis();
203 iEndMillis = mi.getEndMillis();
204 }
205 checkInterval(iStartMillis, iEndMillis);
206 }
207
208 //-----------------------------------------------------------------------
209 /**
210 * Gets the chronology of this interval.
211 *
212 * @return the chronology
213 */
214 public Chronology getChronology() {
215 return iChronology;
216 }
217
218 /**
219 * Gets the start of this time interval which is inclusive.
220 *
221 * @return the start of the time interval,
222 * millisecond instant from 1970-01-01T00:00:00Z
223 */
224 public long getStartMillis() {
225 return iStartMillis;
226 }
227
228 /**
229 * Gets the end of this time interval which is exclusive.
230 *
231 * @return the end of the time interval,
232 * millisecond instant from 1970-01-01T00:00:00Z
233 */
234 public long getEndMillis() {
235 return iEndMillis;
236 }
237
238 //-----------------------------------------------------------------------
239 /**
240 * Sets this interval from two millisecond instants and a chronology.
241 *
242 * @param startInstant the start of the time interval
243 * @param endInstant the start of the time interval
244 * @param chrono the chronology, not null
245 * @throws IllegalArgumentException if the end is before the start
246 */
247 protected void setInterval(long startInstant, long endInstant, Chronology chrono) {
248 checkInterval(startInstant, endInstant);
249 iStartMillis = startInstant;
250 iEndMillis = endInstant;
251 iChronology = DateTimeUtils.getChronology(chrono);
252 }
253
254 }