/*
* Copyright 2001-2015 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.base;
import java.io.Serializable;
import org.joda.time.Chronology;
import org.joda.time.DateTimeUtils;
import org.joda.time.DateTimeZone;
import org.joda.time.ReadableDateTime;
import org.joda.time.chrono.ISOChronology;
import org.joda.time.convert.ConverterManager;
import org.joda.time.convert.InstantConverter;
/**
* BaseDateTime is an abstract implementation of ReadableDateTime that stores
* data in <code>long</code> and <code>Chronology</code> fields.
* <p>
* This class should generally not be used directly by API users.
* The {@link ReadableDateTime} interface should be used when different
* kinds of date/time objects are to be referenced.
* <p>
* BaseDateTime subclasses may be mutable and not thread-safe.
*
* @author Stephen Colebourne
* @author Kandarp Shah
* @author Brian S O'Neill
* @since 1.0
*/
public abstract class BaseDateTime
extends AbstractDateTime
implements ReadableDateTime, Serializable {
/** Serialization lock */
private static final long serialVersionUID = -6728882245981L;
/** The millis from 1970-01-01T00:00:00Z */
private volatile long iMillis;
/** The chronology to use */
private volatile Chronology iChronology;
//-----------------------------------------------------------------------
/**
* Constructs an instance set to the current system millisecond time
* using <code>ISOChronology</code> in the default time zone.
*/
public BaseDateTime() {
this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance());
}
/**
* Constructs an instance set to the current system millisecond time
* using <code>ISOChronology</code> in the specified time zone.
* <p>
* If the specified time zone is null, the default zone is used.
*
* @param zone the time zone, null means default zone
*/
public BaseDateTime(DateTimeZone zone) {
this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance(zone));
}
/**
* Constructs an instance set to the current system millisecond time
* using the specified chronology.
* <p>
* If the chronology is null, <code>ISOChronology</code>
* in the default time zone is used.
*
* @param chronology the chronology, null means ISOChronology in default zone
*/
public BaseDateTime(Chronology chronology) {
this(DateTimeUtils.currentTimeMillis(), chronology);
}
//-----------------------------------------------------------------------
/**
* Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
* using <code>ISOChronology</code> in the default time zone.
*
* @param instant the milliseconds from 1970-01-01T00:00:00Z
*/
public BaseDateTime(long instant) {
this(instant, ISOChronology.getInstance());
}
/**
* Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
* using <code>ISOChronology</code> in the specified time zone.
* <p>
* If the specified time zone is null, the default zone is used.
*
* @param instant the milliseconds from 1970-01-01T00:00:00Z
* @param zone the time zone, null means default zone
*/
public BaseDateTime(long instant, DateTimeZone zone) {
this(instant, ISOChronology.getInstance(zone));
}
/**
* Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
* using the specified chronology.
* <p>
* If the chronology is null, <code>ISOChronology</code>
* in the default time zone is used.
*
* @param instant the milliseconds from 1970-01-01T00:00:00Z
* @param chronology the chronology, null means ISOChronology in default zone
*/
public BaseDateTime(long instant, Chronology chronology) {
super();
iChronology = checkChronology(chronology);
iMillis = checkInstant(instant, iChronology);
adjustForMinMax();
}
//-----------------------------------------------------------------------
/**
* Constructs an instance from an Object that represents a datetime,
* forcing the time zone to that specified.
* <p>
* If the object contains no chronology, <code>ISOChronology</code> is used.
* If the specified time zone is null, the default zone is used.
* <p>
* The recognised object types are defined in
* {@link org.joda.time.convert.ConverterManager ConverterManager} and
* include ReadableInstant, String, Calendar and Date.
*
* @param instant the datetime object
* @param zone the time zone
* @throws IllegalArgumentException if the instant is invalid
*/
public BaseDateTime(Object instant, DateTimeZone zone) {
super();
InstantConverter converter = ConverterManager.getInstance().getInstantConverter(instant);
Chronology chrono = checkChronology(converter.getChronology(instant, zone));
iChronology = chrono;
iMillis = checkInstant(converter.getInstantMillis(instant, chrono), chrono);
adjustForMinMax();
}
/**
* Constructs an instance from an Object that represents a datetime,
* using the specified chronology.
* <p>
* If the chronology is null, ISO in the default time zone is used.
* <p>
* The recognised object types are defined in
* {@link org.joda.time.convert.ConverterManager ConverterManager} and
* include ReadableInstant, String, Calendar and Date.
*
* @param instant the datetime object
* @param chronology the chronology
* @throws IllegalArgumentException if the instant is invalid
*/
public BaseDateTime(Object instant, Chronology chronology) {
super();
InstantConverter converter = ConverterManager.getInstance().getInstantConverter(instant);
iChronology = checkChronology(converter.getChronology(instant, chronology));
iMillis = checkInstant(converter.getInstantMillis(instant, chronology), iChronology);
adjustForMinMax();
}
//-----------------------------------------------------------------------
/**
* Constructs an instance from datetime field values
* using <code>ISOChronology</code> in the default time zone.
*
* @param year the year
* @param monthOfYear the month of the year
* @param dayOfMonth the day of the month
* @param hourOfDay the hour of the day
* @param minuteOfHour the minute of the hour
* @param secondOfMinute the second of the minute
* @param millisOfSecond the millisecond of the second
*/
public BaseDateTime(
int year,
int monthOfYear,
int dayOfMonth,
int hourOfDay,
int minuteOfHour,
int secondOfMinute,
int millisOfSecond) {
this(year, monthOfYear, dayOfMonth, hourOfDay,
minuteOfHour, secondOfMinute, millisOfSecond, ISOChronology.getInstance());
}
/**
* Constructs an instance from datetime field values
* using <code>ISOChronology</code> in the specified time zone.
* <p>
* If the specified time zone is null, the default zone is used.
*
* @param year the year
* @param monthOfYear the month of the year
* @param dayOfMonth the day of the month
* @param hourOfDay the hour of the day
* @param minuteOfHour the minute of the hour
* @param secondOfMinute the second of the minute
* @param millisOfSecond the millisecond of the second
* @param zone the time zone, null means default time zone
*/
public BaseDateTime(
int year,
int monthOfYear,
int dayOfMonth,
int hourOfDay,
int minuteOfHour,
int secondOfMinute,
int millisOfSecond,
DateTimeZone zone) {
this(year, monthOfYear, dayOfMonth, hourOfDay,
minuteOfHour, secondOfMinute, millisOfSecond, ISOChronology.getInstance(zone));
}
/**
* Constructs an instance from datetime field values
* using the specified chronology.
* <p>
* If the chronology is null, <code>ISOChronology</code>
* in the default time zone is used.
*
* @param year the year
* @param monthOfYear the month of the year
* @param dayOfMonth the day of the month
* @param hourOfDay the hour of the day
* @param minuteOfHour the minute of the hour
* @param secondOfMinute the second of the minute
* @param millisOfSecond the millisecond of the second
* @param chronology the chronology, null means ISOChronology in default zone
*/
public BaseDateTime(
int year,
int monthOfYear,
int dayOfMonth,
int hourOfDay,
int minuteOfHour,
int secondOfMinute,
int millisOfSecond,
Chronology chronology) {
super();
iChronology = checkChronology(chronology);
long instant = iChronology.getDateTimeMillis(year, monthOfYear, dayOfMonth,
hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
iMillis = checkInstant(instant, iChronology);
adjustForMinMax();
}
private void adjustForMinMax() {
if (iMillis == Long.MIN_VALUE || iMillis == Long.MAX_VALUE) {
iChronology = iChronology.withUTC();
}
}
//-----------------------------------------------------------------------
/**
* Checks the specified chronology before storing it, potentially altering it.
* This method must not access any instance variables.
* <p>
* This implementation converts nulls to ISOChronology in the default zone.
*
* @param chronology the chronology to use, may be null
* @return the chronology to store in this datetime, not null
*/
protected Chronology checkChronology(Chronology chronology) {
return DateTimeUtils.getChronology(chronology);
}
/**
* Checks the specified instant before storing it, potentially altering it.
* This method must not access any instance variables.
* <p>
* This implementation simply returns the instant.
*
* @param instant the milliseconds from 1970-01-01T00:00:00Z to round
* @param chronology the chronology to use, not null
* @return the instant to store in this datetime
*/
protected long checkInstant(long instant, Chronology chronology) {
return instant;
}
//-----------------------------------------------------------------------
/**
* Gets the milliseconds of the datetime instant from the Java epoch
* of 1970-01-01T00:00:00Z.
*
* @return the number of milliseconds since 1970-01-01T00:00:00Z
*/
public long getMillis() {
return iMillis;
}
/**
* Gets the chronology of the datetime.
*
* @return the Chronology that the datetime is using
*/
public Chronology getChronology() {
return iChronology;
}
//-----------------------------------------------------------------------
/**
* Sets the milliseconds of the datetime.
* <p>
* All changes to the millisecond field occurs via this method.
* Override and block this method to make a subclass immutable.
*
* @param instant the milliseconds since 1970-01-01T00:00:00Z to set the datetime to
*/
protected void setMillis(long instant) {
iMillis = checkInstant(instant, iChronology);
}
/**
* Sets the chronology of the datetime.
* <p>
* All changes to the chronology field occurs via this method.
* Override and block this method to make a subclass immutable.
*
* @param chronology the chronology to set
*/
protected void setChronology(Chronology chronology) {
iChronology = checkChronology(chronology);
}
}