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.DateTimeZone;
023    import org.joda.time.ReadableDateTime;
024    import org.joda.time.chrono.ISOChronology;
025    import org.joda.time.convert.ConverterManager;
026    import org.joda.time.convert.InstantConverter;
027    
028    /**
029     * BaseDateTime is an abstract implementation of ReadableDateTime that stores
030     * data in <code>long</code> and <code>Chronology</code> fields.
031     * <p>
032     * This class should generally not be used directly by API users.
033     * The {@link ReadableDateTime} interface should be used when different 
034     * kinds of date/time objects are to be referenced.
035     * <p>
036     * BaseDateTime subclasses may be mutable and not thread-safe.
037     *
038     * @author Stephen Colebourne
039     * @author Kandarp Shah
040     * @author Brian S O'Neill
041     * @since 1.0
042     */
043    public abstract class BaseDateTime
044            extends AbstractDateTime
045            implements ReadableDateTime, Serializable {
046    
047        /** Serialization lock */
048        private static final long serialVersionUID = -6728882245981L;
049    
050        /** The millis from 1970-01-01T00:00:00Z */
051        private volatile long iMillis;
052        /** The chronology to use */
053        private volatile Chronology iChronology;
054    
055        //-----------------------------------------------------------------------
056        /**
057         * Constructs an instance set to the current system millisecond time
058         * using <code>ISOChronology</code> in the default time zone.
059         */
060        public BaseDateTime() {
061            this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance());
062        }
063    
064        /**
065         * Constructs an instance set to the current system millisecond time
066         * using <code>ISOChronology</code> in the specified time zone.
067         * <p>
068         * If the specified time zone is null, the default zone is used.
069         *
070         * @param zone  the time zone, null means default zone
071         */
072        public BaseDateTime(DateTimeZone zone) {
073            this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance(zone));
074        }
075    
076        /**
077         * Constructs an instance set to the current system millisecond time
078         * using the specified chronology.
079         * <p>
080         * If the chronology is null, <code>ISOChronology</code>
081         * in the default time zone is used.
082         *
083         * @param chronology  the chronology, null means ISOChronology in default zone
084         */
085        public BaseDateTime(Chronology chronology) {
086            this(DateTimeUtils.currentTimeMillis(), chronology);
087        }
088    
089        //-----------------------------------------------------------------------
090        /**
091         * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
092         * using <code>ISOChronology</code> in the default time zone.
093         *
094         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
095         */
096        public BaseDateTime(long instant) {
097            this(instant, ISOChronology.getInstance());
098        }
099    
100        /**
101         * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
102         * using <code>ISOChronology</code> in the specified time zone.
103         * <p>
104         * If the specified time zone is null, the default zone is used.
105         *
106         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
107         * @param zone  the time zone, null means default zone
108         */
109        public BaseDateTime(long instant, DateTimeZone zone) {
110            this(instant, ISOChronology.getInstance(zone));
111        }
112    
113        /**
114         * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
115         * using the specified chronology.
116         * <p>
117         * If the chronology is null, <code>ISOChronology</code>
118         * in the default time zone is used.
119         *
120         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
121         * @param chronology  the chronology, null means ISOChronology in default zone
122         */
123        public BaseDateTime(long instant, Chronology chronology) {
124            super();
125            iChronology = checkChronology(chronology);
126            iMillis = checkInstant(instant, iChronology);
127        }
128    
129        //-----------------------------------------------------------------------
130        /**
131         * Constructs an instance from an Object that represents a datetime,
132         * forcing the time zone to that specified.
133         * <p>
134         * If the object contains no chronology, <code>ISOChronology</code> is used.
135         * If the specified time zone is null, the default zone is used.
136         * <p>
137         * The recognised object types are defined in
138         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
139         * include ReadableInstant, String, Calendar and Date.
140         *
141         * @param instant  the datetime object
142         * @param zone  the time zone
143         * @throws IllegalArgumentException if the instant is invalid
144         */
145        public BaseDateTime(Object instant, DateTimeZone zone) {
146            super();
147            InstantConverter converter = ConverterManager.getInstance().getInstantConverter(instant);
148            Chronology chrono = checkChronology(converter.getChronology(instant, zone));
149            iChronology = chrono;
150            iMillis = checkInstant(converter.getInstantMillis(instant, chrono), chrono);
151        }
152    
153        /**
154         * Constructs an instance from an Object that represents a datetime,
155         * using the specified chronology.
156         * <p>
157         * If the chronology is null, ISO in the default time zone is used.
158         * <p>
159         * The recognised object types are defined in
160         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
161         * include ReadableInstant, String, Calendar and Date.
162         *
163         * @param instant  the datetime object
164         * @param chronology  the chronology
165         * @throws IllegalArgumentException if the instant is invalid
166         */
167        public BaseDateTime(Object instant, Chronology chronology) {
168            super();
169            InstantConverter converter = ConverterManager.getInstance().getInstantConverter(instant);
170            iChronology = checkChronology(converter.getChronology(instant, chronology));
171            iMillis = checkInstant(converter.getInstantMillis(instant, chronology), iChronology);
172        }
173    
174        //-----------------------------------------------------------------------
175        /**
176         * Constructs an instance from datetime field values
177         * using <code>ISOChronology</code> in the default time zone.
178         *
179         * @param year  the year
180         * @param monthOfYear  the month of the year
181         * @param dayOfMonth  the day of the month
182         * @param hourOfDay  the hour of the day
183         * @param minuteOfHour  the minute of the hour
184         * @param secondOfMinute  the second of the minute
185         * @param millisOfSecond  the millisecond of the second
186         */
187        public BaseDateTime(
188                int year,
189                int monthOfYear,
190                int dayOfMonth,
191                int hourOfDay,
192                int minuteOfHour,
193                int secondOfMinute,
194                int millisOfSecond) {
195            this(year, monthOfYear, dayOfMonth, hourOfDay,
196                minuteOfHour, secondOfMinute, millisOfSecond, ISOChronology.getInstance());
197        }
198    
199        /**
200         * Constructs an instance from datetime field values
201         * using <code>ISOChronology</code> in the specified time zone.
202         * <p>
203         * If the specified time zone is null, the default zone is used.
204         *
205         * @param year  the year
206         * @param monthOfYear  the month of the year
207         * @param dayOfMonth  the day of the month
208         * @param hourOfDay  the hour of the day
209         * @param minuteOfHour  the minute of the hour
210         * @param secondOfMinute  the second of the minute
211         * @param millisOfSecond  the millisecond of the second
212         * @param zone  the time zone, null means default time zone
213         */
214        public BaseDateTime(
215                int year,
216                int monthOfYear,
217                int dayOfMonth,
218                int hourOfDay,
219                int minuteOfHour,
220                int secondOfMinute,
221                int millisOfSecond,
222                DateTimeZone zone) {
223            this(year, monthOfYear, dayOfMonth, hourOfDay,
224                minuteOfHour, secondOfMinute, millisOfSecond, ISOChronology.getInstance(zone));
225        }
226    
227        /**
228         * Constructs an instance from datetime field values
229         * using the specified chronology.
230         * <p>
231         * If the chronology is null, <code>ISOChronology</code>
232         * in the default time zone is used.
233         *
234         * @param year  the year
235         * @param monthOfYear  the month of the year
236         * @param dayOfMonth  the day of the month
237         * @param hourOfDay  the hour of the day
238         * @param minuteOfHour  the minute of the hour
239         * @param secondOfMinute  the second of the minute
240         * @param millisOfSecond  the millisecond of the second
241         * @param chronology  the chronology, null means ISOChronology in default zone
242         */
243        public BaseDateTime(
244                int year,
245                int monthOfYear,
246                int dayOfMonth,
247                int hourOfDay,
248                int minuteOfHour,
249                int secondOfMinute,
250                int millisOfSecond,
251                Chronology chronology) {
252            super();
253            iChronology = checkChronology(chronology);
254            long instant = iChronology.getDateTimeMillis(year, monthOfYear, dayOfMonth,
255                hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
256            iMillis = checkInstant(instant, iChronology);
257        }
258    
259        //-----------------------------------------------------------------------
260        /**
261         * Checks the specified chronology before storing it, potentially altering it.
262         * This method must not access any instance variables.
263         * <p>
264         * This implementation converts nulls to ISOChronology in the default zone.
265         *
266         * @param chronology  the chronology to use, may be null
267         * @return the chronology to store in this datetime, not null
268         */
269        protected Chronology checkChronology(Chronology chronology) {
270            return DateTimeUtils.getChronology(chronology);
271        }
272    
273        /**
274         * Checks the specified instant before storing it, potentially altering it.
275         * This method must not access any instance variables.
276         * <p>
277         * This implementation simply returns the instant.
278         *
279         * @param instant  the milliseconds from 1970-01-01T00:00:00Z to round
280         * @param chronology  the chronology to use, not null
281         * @return the instant to store in this datetime
282         */
283        protected long checkInstant(long instant, Chronology chronology) {
284            return instant;
285        }
286    
287        //-----------------------------------------------------------------------
288        /**
289         * Gets the milliseconds of the datetime instant from the Java epoch
290         * of 1970-01-01T00:00:00Z.
291         * 
292         * @return the number of milliseconds since 1970-01-01T00:00:00Z
293         */
294        public long getMillis() {
295            return iMillis;
296        }
297    
298        /**
299         * Gets the chronology of the datetime.
300         * 
301         * @return the Chronology that the datetime is using
302         */
303        public Chronology getChronology() {
304            return iChronology;
305        }
306    
307        //-----------------------------------------------------------------------
308        /**
309         * Sets the milliseconds of the datetime.
310         * <p>
311         * All changes to the millisecond field occurs via this method.
312         * Override and block this method to make a subclass immutable.
313         *
314         * @param instant  the milliseconds since 1970-01-01T00:00:00Z to set the datetime to
315         */
316        protected void setMillis(long instant) {
317            iMillis = checkInstant(instant, iChronology);
318        }
319    
320        /**
321         * Sets the chronology of the datetime.
322         * <p>
323         * All changes to the chronology field occurs via this method.
324         * Override and block this method to make a subclass immutable.
325         *
326         * @param chronology  the chronology to set
327         */
328        protected void setChronology(Chronology chronology) {
329            iChronology = checkChronology(chronology);
330        }
331    
332    }