1 /*
2 * Copyright 2001-2011 Stephen Colebourne
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.joda.time.base;
17
18 import java.io.Serializable;
19
20 import org.joda.time.Chronology;
21 import org.joda.time.DateTimeUtils;
22 import org.joda.time.MutableInterval;
23 import org.joda.time.ReadWritableInterval;
24 import org.joda.time.ReadableDuration;
25 import org.joda.time.ReadableInstant;
26 import org.joda.time.ReadableInterval;
27 import org.joda.time.ReadablePeriod;
28 import org.joda.time.chrono.ISOChronology;
29 import org.joda.time.convert.ConverterManager;
30 import org.joda.time.convert.IntervalConverter;
31 import org.joda.time.field.FieldUtils;
32
33 /**
34 * BaseInterval is an abstract implementation of ReadableInterval that stores
35 * data in two <code>long</code> millisecond fields.
36 * <p>
37 * This class should generally not be used directly by API users.
38 * The {@link ReadableInterval} interface should be used when different
39 * kinds of interval objects are to be referenced.
40 * <p>
41 * BaseInterval subclasses may be mutable and not thread-safe.
42 *
43 * @author Brian S O'Neill
44 * @author Sean Geoghegan
45 * @author Stephen Colebourne
46 * @since 1.0
47 */
48 public abstract class BaseInterval
49 extends AbstractInterval
50 implements ReadableInterval, Serializable {
51
52 /** Serialization version */
53 private static final long serialVersionUID = 576586928732749278L;
54
55 /** The chronology of the interval */
56 private volatile Chronology iChronology;
57 /** The start of the interval */
58 private volatile long iStartMillis;
59 /** The end of the interval */
60 private volatile long iEndMillis;
61
62 /**
63 * Constructs an interval from a start and end instant.
64 *
65 * @param startInstant start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
66 * @param endInstant end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
67 * @param chrono the chronology to use, null is ISO default
68 * @throws IllegalArgumentException if the end is before the start
69 */
70 protected BaseInterval(long startInstant, long endInstant, Chronology chrono) {
71 super();
72 iChronology = DateTimeUtils.getChronology(chrono);
73 checkInterval(startInstant, endInstant);
74 iStartMillis = startInstant;
75 iEndMillis = endInstant;
76 }
77
78 /**
79 * Constructs an interval from a start and end instant.
80 *
81 * @param start start of this interval, null means now
82 * @param end end of this interval, null means now
83 * @throws IllegalArgumentException if the end is before the start
84 */
85 protected BaseInterval(ReadableInstant start, ReadableInstant end) {
86 super();
87 if (start == null && end == null) {
88 iStartMillis = iEndMillis = DateTimeUtils.currentTimeMillis();
89 iChronology = ISOChronology.getInstance();
90 } else {
91 iChronology = DateTimeUtils.getInstantChronology(start);
92 iStartMillis = DateTimeUtils.getInstantMillis(start);
93 iEndMillis = DateTimeUtils.getInstantMillis(end);
94 checkInterval(iStartMillis, iEndMillis);
95 }
96 }
97
98 /**
99 * 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 }