/*
* Copyright 2001-2013 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;
import java.lang.reflect.
Method;
import java.text.
DateFormatSymbols;
import java.util.
Collections;
import java.util.
HashMap;
import java.util.
LinkedHashMap;
import java.util.
Locale;
import java.util.
Map;
import java.util.concurrent.atomic.
AtomicReference;
import org.joda.time.chrono.
ISOChronology;
/**
* DateTimeUtils provide public utility methods for the date-time library.
* <p>
* DateTimeUtils uses shared static variables which are declared as volatile
* for thread-safety. These can be changed during the lifetime of the application
* however doing so is generally a bad idea.
*
* @author Stephen Colebourne
* @since 1.0
*/
public class
DateTimeUtils {
/**
* The singleton instance of the system millisecond provider.
*/
public static final
MillisProvider SYSTEM_MILLIS_PROVIDER = new
SystemMillisProvider();
/** The millisecond provider currently in use. */
private static volatile
MillisProvider cMillisProvider =
SYSTEM_MILLIS_PROVIDER;
/**
* The default names.
* This is lazily initialized to reduce risks of race conditions at startup.
*/
private static final
AtomicReference<
Map<
String,
DateTimeZone>>
cZoneNames =
new
AtomicReference<
Map<
String,
DateTimeZone>>();
/**
* Restrictive constructor
*/
protected
DateTimeUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* Gets the current time in milliseconds.
* <p>
* By default this returns <code>System.currentTimeMillis()</code>.
* This may be changed using other methods in this class.
*
* @return the current time in milliseconds from 1970-01-01T00:00:00Z
*/
public static final long
currentTimeMillis() {
return
cMillisProvider.
getMillis();
}
/**
* Resets the current time to return the system time.
* <p>
* This method changes the behaviour of {@link #currentTimeMillis()}.
* Whenever the current time is queried, {@link System#currentTimeMillis()} is used.
*
* @throws SecurityException if the application does not have sufficient security rights
*/
public static final void
setCurrentMillisSystem() throws
SecurityException {
checkPermission();
cMillisProvider =
SYSTEM_MILLIS_PROVIDER;
}
/**
* Sets the current time to return a fixed millisecond time.
* <p>
* This method changes the behaviour of {@link #currentTimeMillis()}.
* Whenever the current time is queried, the same millisecond time will be returned.
*
* @param fixedMillis the fixed millisecond time to use
* @throws SecurityException if the application does not have sufficient security rights
*/
public static final void
setCurrentMillisFixed(long
fixedMillis) throws
SecurityException {
checkPermission();
cMillisProvider = new
FixedMillisProvider(
fixedMillis);
}
/**
* Sets the current time to return the system time plus an offset.
* <p>
* This method changes the behaviour of {@link #currentTimeMillis()}.
* Whenever the current time is queried, {@link System#currentTimeMillis()} is used
* and then offset by adding the millisecond value specified here.
*
* @param offsetMillis the fixed millisecond time to use
* @throws SecurityException if the application does not have sufficient security rights
*/
public static final void
setCurrentMillisOffset(long
offsetMillis) throws
SecurityException {
checkPermission();
if (
offsetMillis == 0) {
cMillisProvider =
SYSTEM_MILLIS_PROVIDER;
} else {
cMillisProvider = new
OffsetMillisProvider(
offsetMillis);
}
}
/**
* Sets the provider of the current time to class specified.
* <p>
* This method changes the behaviour of {@link #currentTimeMillis()}.
* Whenever the current time is queried, the specified class will be called.
*
* @param millisProvider the provider of the current time to use, not null
* @throws SecurityException if the application does not have sufficient security rights
* @since 2.0
*/
public static final void
setCurrentMillisProvider(
MillisProvider millisProvider) throws
SecurityException {
if (
millisProvider == null) {
throw new
IllegalArgumentException("The MillisProvider must not be null");
}
checkPermission();
cMillisProvider =
millisProvider;
}
/**
* Checks whether the provider may be changed using permission 'CurrentTime.setProvider'.
*
* @throws SecurityException if the provider may not be changed
*/
private static void
checkPermission() throws
SecurityException {
SecurityManager sm =
System.
getSecurityManager();
if (
sm != null) {
sm.
checkPermission(new
JodaTimePermission("CurrentTime.setProvider"));
}
}
//-----------------------------------------------------------------------
/**
* Gets the millisecond instant from the specified instant object handling null.
* <p>
* If the instant object is <code>null</code>, the {@link #currentTimeMillis()}
* will be returned. Otherwise, the millis from the object are returned.
*
* @param instant the instant to examine, null means now
* @return the time in milliseconds from 1970-01-01T00:00:00Z
*/
public static final long
getInstantMillis(
ReadableInstant instant) {
if (
instant == null) {
return
DateTimeUtils.
currentTimeMillis();
}
return
instant.
getMillis();
}
//-----------------------------------------------------------------------
/**
* Gets the chronology from the specified instant object handling null.
* <p>
* If the instant object is <code>null</code>, or the instant's chronology is
* <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
* Otherwise, the chronology from the object is returned.
*
* @param instant the instant to examine, null means ISO in the default zone
* @return the chronology, never null
*/
public static final
Chronology getInstantChronology(
ReadableInstant instant) {
if (
instant == null) {
return
ISOChronology.
getInstance();
}
Chronology chrono =
instant.
getChronology();
if (
chrono == null) {
return
ISOChronology.
getInstance();
}
return
chrono;
}
//-----------------------------------------------------------------------
/**
* Gets the chronology from the specified instant based interval handling null.
* <p>
* The chronology is obtained from the start if that is not null, or from the
* end if the start is null. The result is additionally checked, and if still
* null then {@link ISOChronology#getInstance()} will be returned.
*
* @param start the instant to examine and use as the primary source of the chronology
* @param end the instant to examine and use as the secondary source of the chronology
* @return the chronology, never null
*/
public static final
Chronology getIntervalChronology(
ReadableInstant start,
ReadableInstant end) {
Chronology chrono = null;
if (
start != null) {
chrono =
start.
getChronology();
} else if (
end != null) {
chrono =
end.
getChronology();
}
if (
chrono == null) {
chrono =
ISOChronology.
getInstance();
}
return
chrono;
}
//-----------------------------------------------------------------------
/**
* Gets the chronology from the specified interval object handling null.
* <p>
* If the interval object is <code>null</code>, or the interval's chronology is
* <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
* Otherwise, the chronology from the object is returned.
*
* @param interval the interval to examine, null means ISO in the default zone
* @return the chronology, never null
*/
public static final
Chronology getIntervalChronology(
ReadableInterval interval) {
if (
interval == null) {
return
ISOChronology.
getInstance();
}
Chronology chrono =
interval.
getChronology();
if (
chrono == null) {
return
ISOChronology.
getInstance();
}
return
chrono;
}
//-----------------------------------------------------------------------
/**
* Gets the interval handling null.
* <p>
* If the interval is <code>null</code>, an interval representing now
* to now in the {@link ISOChronology#getInstance() ISOChronology}
* will be returned. Otherwise, the interval specified is returned.
*
* @param interval the interval to use, null means now to now
* @return the interval, never null
* @since 1.1
*/
public static final
ReadableInterval getReadableInterval(
ReadableInterval interval) {
if (
interval == null) {
long
now =
DateTimeUtils.
currentTimeMillis();
interval = new
Interval(
now,
now);
}
return
interval;
}
//-----------------------------------------------------------------------
/**
* Gets the chronology handling null.
* <p>
* If the chronology is <code>null</code>, {@link ISOChronology#getInstance()}
* will be returned. Otherwise, the chronology is returned.
*
* @param chrono the chronology to use, null means ISO in the default zone
* @return the chronology, never null
*/
public static final
Chronology getChronology(
Chronology chrono) {
if (
chrono == null) {
return
ISOChronology.
getInstance();
}
return
chrono;
}
//-----------------------------------------------------------------------
/**
* Gets the zone handling null.
* <p>
* If the zone is <code>null</code>, {@link DateTimeZone#getDefault()}
* will be returned. Otherwise, the zone specified is returned.
*
* @param zone the time zone to use, null means the default zone
* @return the time zone, never null
*/
public static final
DateTimeZone getZone(
DateTimeZone zone) {
if (
zone == null) {
return
DateTimeZone.
getDefault();
}
return
zone;
}
//-----------------------------------------------------------------------
/**
* Gets the period type handling null.
* <p>
* If the zone is <code>null</code>, {@link PeriodType#standard()}
* will be returned. Otherwise, the type specified is returned.
*
* @param type the time zone to use, null means the standard type
* @return the type to use, never null
*/
public static final
PeriodType getPeriodType(
PeriodType type) {
if (
type == null) {
return
PeriodType.
standard();
}
return
type;
}
//-----------------------------------------------------------------------
/**
* Gets the millisecond duration from the specified duration object handling null.
* <p>
* If the duration object is <code>null</code>, zero will be returned.
* Otherwise, the millis from the object are returned.
*
* @param duration the duration to examine, null means zero
* @return the duration in milliseconds
*/
public static final long
getDurationMillis(
ReadableDuration duration) {
if (
duration == null) {
return 0L;
}
return
duration.
getMillis();
}
//-----------------------------------------------------------------------
/**
* Checks whether the partial is contiguous.
* <p>
* A partial is contiguous if one field starts where another ends.
* <p>
* For example <code>LocalDate</code> is contiguous because DayOfMonth has
* the same range (Month) as the unit of the next field (MonthOfYear), and
* MonthOfYear has the same range (Year) as the unit of the next field (Year).
* <p>
* Similarly, <code>LocalTime</code> is contiguous, as it consists of
* MillisOfSecond, SecondOfMinute, MinuteOfHour and HourOfDay (note how
* the names of each field 'join up').
* <p>
* However, a Year/HourOfDay partial is not contiguous because the range
* field Day is not equal to the next field Year.
* Similarly, a DayOfWeek/DayOfMonth partial is not contiguous because
* the range Month is not equal to the next field Day.
*
* @param partial the partial to check
* @return true if the partial is contiguous
* @throws IllegalArgumentException if the partial is null
* @since 1.1
*/
public static final boolean
isContiguous(
ReadablePartial partial) {
if (
partial == null) {
throw new
IllegalArgumentException("Partial must not be null");
}
DurationFieldType lastType = null;
for (int
i = 0;
i <
partial.
size();
i++) {
DateTimeField loopField =
partial.
getField(
i);
if (
i > 0) {
if (
loopField.
getRangeDurationField() == null ||
loopField.
getRangeDurationField().
getType() !=
lastType) {
return false;
}
}
lastType =
loopField.
getDurationField().
getType();
}
return true;
}
//-----------------------------------------------------------------------
/**
* Gets the {@link DateFormatSymbols} based on the given locale.
* <p>
* If JDK 6 or newer is being used, DateFormatSymbols.getInstance(locale) will
* be used in order to allow the use of locales defined as extensions.
* Otherwise, new DateFormatSymbols(locale) will be used.
* See JDK 6 {@link DateFormatSymbols} for further information.
*
* @param locale the {@link Locale} used to get the correct {@link DateFormatSymbols}
* @return the symbols
* @since 2.0
*/
public static final
DateFormatSymbols getDateFormatSymbols(
Locale locale) {
try {
Method method =
DateFormatSymbols.class.
getMethod("getInstance", new
Class[] {
Locale.class});
return (
DateFormatSymbols)
method.
invoke(null, new
Object[] {
locale});
} catch (
Exception ex) {
return new
DateFormatSymbols(
locale);
}
}
//-----------------------------------------------------------------------
/**
* Gets the default map of time zone names.
* <p>
* This can be changed by {@link #setDefaultTimeZoneNames}.
* <p>
* The default set of short time zone names is as follows:
* <ul>
* <li>UT - UTC
* <li>UTC - UTC
* <li>GMT - UTC
* <li>EST - America/New_York
* <li>EDT - America/New_York
* <li>CST - America/Chicago
* <li>CDT - America/Chicago
* <li>MST - America/Denver
* <li>MDT - America/Denver
* <li>PST - America/Los_Angeles
* <li>PDT - America/Los_Angeles
* </ul>
*
* @return the unmodifiable map of abbreviations to zones, not null
* @since 2.2
*/
public static final
Map<
String,
DateTimeZone>
getDefaultTimeZoneNames() {
Map<
String,
DateTimeZone>
names =
cZoneNames.
get();
if (
names == null) {
names =
buildDefaultTimeZoneNames();
if (!
cZoneNames.
compareAndSet(null,
names)) {
names =
cZoneNames.
get();
}
}
return
names;
}
/**
* Sets the default map of time zone names.
* <p>
* The map is copied before storage.
*
* @param names the map of abbreviations to zones, not null
* @since 2.2
*/
public static final void
setDefaultTimeZoneNames(
Map<
String,
DateTimeZone>
names) {
cZoneNames.
set(
Collections.
unmodifiableMap(new
HashMap<
String,
DateTimeZone>(
names)));
}
private static
Map<
String,
DateTimeZone>
buildDefaultTimeZoneNames() {
// names from RFC-822 / JDK
// this is all very US-centric and dubious, but perhaps it will help some
Map<
String,
DateTimeZone>
map = new
LinkedHashMap<
String,
DateTimeZone>();
map.
put("UT",
DateTimeZone.
UTC);
map.
put("UTC",
DateTimeZone.
UTC);
map.
put("GMT",
DateTimeZone.
UTC);
put(
map, "EST", "America/New_York");
put(
map, "EDT", "America/New_York");
put(
map, "CST", "America/Chicago");
put(
map, "CDT", "America/Chicago");
put(
map, "MST", "America/Denver");
put(
map, "MDT", "America/Denver");
put(
map, "PST", "America/Los_Angeles");
put(
map, "PDT", "America/Los_Angeles");
return
Collections.
unmodifiableMap(
map);
}
private static void
put(
Map<
String,
DateTimeZone>
map,
String name,
String id) {
try {
map.
put(
name,
DateTimeZone.
forID(
id));
} catch (
RuntimeException ex) {
// ignore
}
}
//-------------------------------------------------------------------------
/**
* Calculates the astronomical Julian Day for an instant.
* <p>
* The <a href="http://en.wikipedia.org/wiki/Julian_day">Julian day</a> is a well-known
* system of time measurement for scientific use by the astronomy community.
* It expresses the interval of time in days and fractions of a day since
* January 1, 4713 BC (Julian) Greenwich noon.
* <p>
* Each day starts at midday (not midnight) and time is expressed as a fraction.
* Thus the fraction 0.25 is 18:00. equal to one quarter of the day from midday to midday.
* <p>
* Note that this method has nothing to do with the day-of-year.
*
* @param epochMillis the epoch millis from 1970-01-01Z
* @return the astronomical Julian Day represented by the specified instant
* @since 2.2
*/
public static final double
toJulianDay(long
epochMillis) {
// useful links
// http://en.wikipedia.org/wiki/Julian_day#cite_note-13 - Wikipedia
// http://aa.usno.navy.mil/data/docs/JulianDate.php" - USNO
// http://users.zoominternet.net/~matto/Java/Julian%20Date%20Converter.htm - Julian Date Converter by Matt Oltersdorf
// http://ssd.jpl.nasa.gov/tc.cgi#top - CalTech
double
epochDay =
epochMillis / 86400000d;
return
epochDay + 2440587.5d;
}
/**
* Calculates the astronomical Julian Day Number for an instant.
* <p>
* The {@link #toJulianDay(long)} method calculates the astronomical Julian Day
* with a fraction based on days starting at midday.
* This method calculates the variant where days start at midnight.
* JDN 0 is used for the date equivalent to Monday January 1, 4713 BC (Julian).
* Thus these days start 12 hours before those of the fractional Julian Day.
* <p>
* Note that this method has nothing to do with the day-of-year.
*
* @param epochMillis the epoch millis from 1970-01-01Z
* @return the astronomical Julian Day represented by the specified instant
* @since 2.2
*/
public static final long
toJulianDayNumber(long
epochMillis) {
return (long)
Math.
floor(
toJulianDay(
epochMillis) + 0.5d);
}
/**
* Creates a date-time from a Julian Day.
* <p>
* Returns the {@code DateTime} object equal to the specified Julian Day.
*
* @param julianDay the Julian Day
* @return the epoch millis from 1970-01-01Z
* @since 2.2
*/
public static final long
fromJulianDay(double
julianDay) {
double
epochDay =
julianDay - 2440587.5d;
return (long) (
epochDay * 86400000d);
}
//-----------------------------------------------------------------------
/**
* A millisecond provider, allowing control of the system clock.
*
* @author Stephen Colebourne
* @since 2.0 (previously private)
*/
public static interface
MillisProvider {
/**
* Gets the current time.
* <p>
* Implementations of this method must be thread-safe.
*
* @return the current time in milliseconds
*/
long
getMillis();
}
/**
* System millis provider.
*/
static class
SystemMillisProvider implements
MillisProvider {
/**
* Gets the current time.
* @return the current time in millis
*/
public long
getMillis() {
return
System.
currentTimeMillis();
}
}
/**
* Fixed millisecond provider.
*/
static class
FixedMillisProvider implements
MillisProvider {
/** The fixed millis value. */
private final long
iMillis;
/**
* Constructor.
* @param fixedMillis the millis value
*/
FixedMillisProvider(long
fixedMillis) {
iMillis =
fixedMillis;
}
/**
* Gets the current time.
* @return the current time in millis
*/
public long
getMillis() {
return
iMillis;
}
}
/**
* Offset from system millis provider.
*/
static class
OffsetMillisProvider implements
MillisProvider {
/** The millis offset. */
private final long
iMillis;
/**
* Constructor.
* @param offsetMillis the millis offset
*/
OffsetMillisProvider(long
offsetMillis) {
iMillis =
offsetMillis;
}
/**
* Gets the current time.
* @return the current time in millis
*/
public long
getMillis() {
return
System.
currentTimeMillis() +
iMillis;
}
}
}