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 }