feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
785
jdkSrc/jdk8/java/time/chrono/AbstractChronology.java
Normal file
785
jdkSrc/jdk8/java/time/chrono/AbstractChronology.java
Normal file
@@ -0,0 +1,785 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
|
||||
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
|
||||
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.DAY_OF_WEEK;
|
||||
import static java.time.temporal.ChronoField.DAY_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.EPOCH_DAY;
|
||||
import static java.time.temporal.ChronoField.ERA;
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
|
||||
import static java.time.temporal.ChronoUnit.DAYS;
|
||||
import static java.time.temporal.ChronoUnit.MONTHS;
|
||||
import static java.time.temporal.ChronoUnit.WEEKS;
|
||||
import static java.time.temporal.TemporalAdjusters.nextOrSame;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.format.ResolverStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
/**
|
||||
* An abstract implementation of a calendar system, used to organize and identify dates.
|
||||
* <p>
|
||||
* The main date and time API is built on the ISO calendar system.
|
||||
* The chronology operates behind the scenes to represent the general concept of a calendar system.
|
||||
* <p>
|
||||
* See {@link Chronology} for more details.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is separated from the {@code Chronology} interface so that the static methods
|
||||
* are not inherited. While {@code Chronology} can be implemented directly, it is strongly
|
||||
* recommended to extend this abstract class instead.
|
||||
* <p>
|
||||
* This class must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public abstract class AbstractChronology implements Chronology {
|
||||
|
||||
/**
|
||||
* ChronoLocalDate order constant.
|
||||
*/
|
||||
static final Comparator<ChronoLocalDate> DATE_ORDER =
|
||||
(Comparator<ChronoLocalDate> & Serializable) (date1, date2) -> {
|
||||
return Long.compare(date1.toEpochDay(), date2.toEpochDay());
|
||||
};
|
||||
/**
|
||||
* ChronoLocalDateTime order constant.
|
||||
*/
|
||||
static final Comparator<ChronoLocalDateTime<? extends ChronoLocalDate>> DATE_TIME_ORDER =
|
||||
(Comparator<ChronoLocalDateTime<? extends ChronoLocalDate>> & Serializable) (dateTime1, dateTime2) -> {
|
||||
int cmp = Long.compare(dateTime1.toLocalDate().toEpochDay(), dateTime2.toLocalDate().toEpochDay());
|
||||
if (cmp == 0) {
|
||||
cmp = Long.compare(dateTime1.toLocalTime().toNanoOfDay(), dateTime2.toLocalTime().toNanoOfDay());
|
||||
}
|
||||
return cmp;
|
||||
};
|
||||
/**
|
||||
* ChronoZonedDateTime order constant.
|
||||
*/
|
||||
static final Comparator<ChronoZonedDateTime<?>> INSTANT_ORDER =
|
||||
(Comparator<ChronoZonedDateTime<?>> & Serializable) (dateTime1, dateTime2) -> {
|
||||
int cmp = Long.compare(dateTime1.toEpochSecond(), dateTime2.toEpochSecond());
|
||||
if (cmp == 0) {
|
||||
cmp = Long.compare(dateTime1.toLocalTime().getNano(), dateTime2.toLocalTime().getNano());
|
||||
}
|
||||
return cmp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Map of available calendars by ID.
|
||||
*/
|
||||
private static final ConcurrentHashMap<String, Chronology> CHRONOS_BY_ID = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* Map of available calendars by calendar type.
|
||||
*/
|
||||
private static final ConcurrentHashMap<String, Chronology> CHRONOS_BY_TYPE = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Register a Chronology by its ID and type for lookup by {@link #of(String)}.
|
||||
* Chronologies must not be registered until they are completely constructed.
|
||||
* Specifically, not in the constructor of Chronology.
|
||||
*
|
||||
* @param chrono the chronology to register; not null
|
||||
* @return the already registered Chronology if any, may be null
|
||||
*/
|
||||
static Chronology registerChrono(Chronology chrono) {
|
||||
return registerChrono(chrono, chrono.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a Chronology by ID and type for lookup by {@link #of(String)}.
|
||||
* Chronos must not be registered until they are completely constructed.
|
||||
* Specifically, not in the constructor of Chronology.
|
||||
*
|
||||
* @param chrono the chronology to register; not null
|
||||
* @param id the ID to register the chronology; not null
|
||||
* @return the already registered Chronology if any, may be null
|
||||
*/
|
||||
static Chronology registerChrono(Chronology chrono, String id) {
|
||||
Chronology prev = CHRONOS_BY_ID.putIfAbsent(id, chrono);
|
||||
if (prev == null) {
|
||||
String type = chrono.getCalendarType();
|
||||
if (type != null) {
|
||||
CHRONOS_BY_TYPE.putIfAbsent(type, chrono);
|
||||
}
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization of the maps from id and type to Chronology.
|
||||
* The ServiceLoader is used to find and register any implementations
|
||||
* of {@link java.time.chrono.AbstractChronology} found in the bootclass loader.
|
||||
* The built-in chronologies are registered explicitly.
|
||||
* Calendars configured via the Thread's context classloader are local
|
||||
* to that thread and are ignored.
|
||||
* <p>
|
||||
* The initialization is done only once using the registration
|
||||
* of the IsoChronology as the test and the final step.
|
||||
* Multiple threads may perform the initialization concurrently.
|
||||
* Only the first registration of each Chronology is retained by the
|
||||
* ConcurrentHashMap.
|
||||
* @return true if the cache was initialized
|
||||
*/
|
||||
private static boolean initCache() {
|
||||
if (CHRONOS_BY_ID.get("ISO") == null) {
|
||||
// Initialization is incomplete
|
||||
|
||||
// Register built-in Chronologies
|
||||
registerChrono(HijrahChronology.INSTANCE);
|
||||
registerChrono(JapaneseChronology.INSTANCE);
|
||||
registerChrono(MinguoChronology.INSTANCE);
|
||||
registerChrono(ThaiBuddhistChronology.INSTANCE);
|
||||
|
||||
// Register Chronologies from the ServiceLoader
|
||||
@SuppressWarnings("rawtypes")
|
||||
ServiceLoader<AbstractChronology> loader = ServiceLoader.load(AbstractChronology.class, null);
|
||||
for (AbstractChronology chrono : loader) {
|
||||
String id = chrono.getId();
|
||||
if (id.equals("ISO") || registerChrono(chrono) != null) {
|
||||
// Log the attempt to replace an existing Chronology
|
||||
PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
|
||||
logger.warning("Ignoring duplicate Chronology, from ServiceLoader configuration " + id);
|
||||
}
|
||||
}
|
||||
|
||||
// finally, register IsoChronology to mark initialization is complete
|
||||
registerChrono(IsoChronology.INSTANCE);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code Chronology} from a locale.
|
||||
* <p>
|
||||
* See {@link Chronology#ofLocale(Locale)}.
|
||||
*
|
||||
* @param locale the locale to use to obtain the calendar system, not null
|
||||
* @return the calendar system associated with the locale, not null
|
||||
* @throws java.time.DateTimeException if the locale-specified calendar cannot be found
|
||||
*/
|
||||
static Chronology ofLocale(Locale locale) {
|
||||
Objects.requireNonNull(locale, "locale");
|
||||
String type = locale.getUnicodeLocaleType("ca");
|
||||
if (type == null || "iso".equals(type) || "iso8601".equals(type)) {
|
||||
return IsoChronology.INSTANCE;
|
||||
}
|
||||
// Not pre-defined; lookup by the type
|
||||
do {
|
||||
Chronology chrono = CHRONOS_BY_TYPE.get(type);
|
||||
if (chrono != null) {
|
||||
return chrono;
|
||||
}
|
||||
// If not found, do the initialization (once) and repeat the lookup
|
||||
} while (initCache());
|
||||
|
||||
// Look for a Chronology using ServiceLoader of the Thread's ContextClassLoader
|
||||
// Application provided Chronologies must not be cached
|
||||
@SuppressWarnings("rawtypes")
|
||||
ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class);
|
||||
for (Chronology chrono : loader) {
|
||||
if (type.equals(chrono.getCalendarType())) {
|
||||
return chrono;
|
||||
}
|
||||
}
|
||||
throw new DateTimeException("Unknown calendar system: " + type);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code Chronology} from a chronology ID or
|
||||
* calendar system type.
|
||||
* <p>
|
||||
* See {@link Chronology#of(String)}.
|
||||
*
|
||||
* @param id the chronology ID or calendar system type, not null
|
||||
* @return the chronology with the identifier requested, not null
|
||||
* @throws java.time.DateTimeException if the chronology cannot be found
|
||||
*/
|
||||
static Chronology of(String id) {
|
||||
Objects.requireNonNull(id, "id");
|
||||
do {
|
||||
Chronology chrono = of0(id);
|
||||
if (chrono != null) {
|
||||
return chrono;
|
||||
}
|
||||
// If not found, do the initialization (once) and repeat the lookup
|
||||
} while (initCache());
|
||||
|
||||
// Look for a Chronology using ServiceLoader of the Thread's ContextClassLoader
|
||||
// Application provided Chronologies must not be cached
|
||||
@SuppressWarnings("rawtypes")
|
||||
ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class);
|
||||
for (Chronology chrono : loader) {
|
||||
if (id.equals(chrono.getId()) || id.equals(chrono.getCalendarType())) {
|
||||
return chrono;
|
||||
}
|
||||
}
|
||||
throw new DateTimeException("Unknown chronology: " + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code Chronology} from a chronology ID or
|
||||
* calendar system type.
|
||||
*
|
||||
* @param id the chronology ID or calendar system type, not null
|
||||
* @return the chronology with the identifier requested, or {@code null} if not found
|
||||
*/
|
||||
private static Chronology of0(String id) {
|
||||
Chronology chrono = CHRONOS_BY_ID.get(id);
|
||||
if (chrono == null) {
|
||||
chrono = CHRONOS_BY_TYPE.get(id);
|
||||
}
|
||||
return chrono;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the available chronologies.
|
||||
* <p>
|
||||
* Each returned {@code Chronology} is available for use in the system.
|
||||
* The set of chronologies includes the system chronologies and
|
||||
* any chronologies provided by the application via ServiceLoader
|
||||
* configuration.
|
||||
*
|
||||
* @return the independent, modifiable set of the available chronology IDs, not null
|
||||
*/
|
||||
static Set<Chronology> getAvailableChronologies() {
|
||||
initCache(); // force initialization
|
||||
HashSet<Chronology> chronos = new HashSet<>(CHRONOS_BY_ID.values());
|
||||
|
||||
/// Add in Chronologies from the ServiceLoader configuration
|
||||
@SuppressWarnings("rawtypes")
|
||||
ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class);
|
||||
for (Chronology chrono : loader) {
|
||||
chronos.add(chrono);
|
||||
}
|
||||
return chronos;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Creates an instance.
|
||||
*/
|
||||
protected AbstractChronology() {
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Resolves parsed {@code ChronoField} values into a date during parsing.
|
||||
* <p>
|
||||
* Most {@code TemporalField} implementations are resolved using the
|
||||
* resolve method on the field. By contrast, the {@code ChronoField} class
|
||||
* defines fields that only have meaning relative to the chronology.
|
||||
* As such, {@code ChronoField} date fields are resolved here in the
|
||||
* context of a specific chronology.
|
||||
* <p>
|
||||
* {@code ChronoField} instances are resolved by this method, which may
|
||||
* be overridden in subclasses.
|
||||
* <ul>
|
||||
* <li>{@code EPOCH_DAY} - If present, this is converted to a date and
|
||||
* all other date fields are then cross-checked against the date.
|
||||
* <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the
|
||||
* {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart
|
||||
* then the field is validated.
|
||||
* <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they
|
||||
* are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA}
|
||||
* range is not validated, in smart and strict mode it is. The {@code ERA} is
|
||||
* validated for range in all three modes. If only the {@code YEAR_OF_ERA} is
|
||||
* present, and the mode is smart or lenient, then the last available era
|
||||
* is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is
|
||||
* left untouched. If only the {@code ERA} is present, then it is left untouched.
|
||||
* <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} -
|
||||
* If all three are present, then they are combined to form a date.
|
||||
* In all three modes, the {@code YEAR} is validated.
|
||||
* If the mode is smart or strict, then the month and day are validated.
|
||||
* If the mode is lenient, then the date is combined in a manner equivalent to
|
||||
* creating a date on the first day of the first month in the requested year,
|
||||
* then adding the difference in months, then the difference in days.
|
||||
* If the mode is smart, and the day-of-month is greater than the maximum for
|
||||
* the year-month, then the day-of-month is adjusted to the last day-of-month.
|
||||
* If the mode is strict, then the three fields must form a valid date.
|
||||
* <li>{@code YEAR} and {@code DAY_OF_YEAR} -
|
||||
* If both are present, then they are combined to form a date.
|
||||
* In all three modes, the {@code YEAR} is validated.
|
||||
* If the mode is lenient, then the date is combined in a manner equivalent to
|
||||
* creating a date on the first day of the requested year, then adding
|
||||
* the difference in days.
|
||||
* If the mode is smart or strict, then the two fields must form a valid date.
|
||||
* <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
|
||||
* {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
|
||||
* If all four are present, then they are combined to form a date.
|
||||
* In all three modes, the {@code YEAR} is validated.
|
||||
* If the mode is lenient, then the date is combined in a manner equivalent to
|
||||
* creating a date on the first day of the first month in the requested year, then adding
|
||||
* the difference in months, then the difference in weeks, then in days.
|
||||
* If the mode is smart or strict, then the all four fields are validated to
|
||||
* their outer ranges. The date is then combined in a manner equivalent to
|
||||
* creating a date on the first day of the requested year and month, then adding
|
||||
* the amount in weeks and days to reach their values. If the mode is strict,
|
||||
* the date is additionally validated to check that the day and week adjustment
|
||||
* did not change the month.
|
||||
* <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
|
||||
* {@code DAY_OF_WEEK} - If all four are present, then they are combined to
|
||||
* form a date. The approach is the same as described above for
|
||||
* years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}.
|
||||
* The day-of-week is adjusted as the next or same matching day-of-week once
|
||||
* the years, months and weeks have been handled.
|
||||
* <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
|
||||
* If all three are present, then they are combined to form a date.
|
||||
* In all three modes, the {@code YEAR} is validated.
|
||||
* If the mode is lenient, then the date is combined in a manner equivalent to
|
||||
* creating a date on the first day of the requested year, then adding
|
||||
* the difference in weeks, then in days.
|
||||
* If the mode is smart or strict, then the all three fields are validated to
|
||||
* their outer ranges. The date is then combined in a manner equivalent to
|
||||
* creating a date on the first day of the requested year, then adding
|
||||
* the amount in weeks and days to reach their values. If the mode is strict,
|
||||
* the date is additionally validated to check that the day and week adjustment
|
||||
* did not change the year.
|
||||
* <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} -
|
||||
* If all three are present, then they are combined to form a date.
|
||||
* The approach is the same as described above for years and weeks in
|
||||
* {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the
|
||||
* next or same matching day-of-week once the years and weeks have been handled.
|
||||
* </ul>
|
||||
* <p>
|
||||
* The default implementation is suitable for most calendar systems.
|
||||
* If {@link java.time.temporal.ChronoField#YEAR_OF_ERA} is found without an {@link java.time.temporal.ChronoField#ERA}
|
||||
* then the last era in {@link #eras()} is used.
|
||||
* The implementation assumes a 7 day week, that the first day-of-month
|
||||
* has the value 1, that first day-of-year has the value 1, and that the
|
||||
* first of the month and year always exists.
|
||||
*
|
||||
* @param fieldValues the map of fields to values, which can be updated, not null
|
||||
* @param resolverStyle the requested type of resolve, not null
|
||||
* @return the resolved date, null if insufficient information to create a date
|
||||
* @throws java.time.DateTimeException if the date cannot be resolved, typically
|
||||
* because of a conflict in the input data
|
||||
*/
|
||||
@Override
|
||||
public ChronoLocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
// check epoch-day before inventing era
|
||||
if (fieldValues.containsKey(EPOCH_DAY)) {
|
||||
return dateEpochDay(fieldValues.remove(EPOCH_DAY));
|
||||
}
|
||||
|
||||
// fix proleptic month before inventing era
|
||||
resolveProlepticMonth(fieldValues, resolverStyle);
|
||||
|
||||
// invent era if necessary to resolve year-of-era
|
||||
ChronoLocalDate resolved = resolveYearOfEra(fieldValues, resolverStyle);
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
// build date
|
||||
if (fieldValues.containsKey(YEAR)) {
|
||||
if (fieldValues.containsKey(MONTH_OF_YEAR)) {
|
||||
if (fieldValues.containsKey(DAY_OF_MONTH)) {
|
||||
return resolveYMD(fieldValues, resolverStyle);
|
||||
}
|
||||
if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) {
|
||||
if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) {
|
||||
return resolveYMAA(fieldValues, resolverStyle);
|
||||
}
|
||||
if (fieldValues.containsKey(DAY_OF_WEEK)) {
|
||||
return resolveYMAD(fieldValues, resolverStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fieldValues.containsKey(DAY_OF_YEAR)) {
|
||||
return resolveYD(fieldValues, resolverStyle);
|
||||
}
|
||||
if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) {
|
||||
if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) {
|
||||
return resolveYAA(fieldValues, resolverStyle);
|
||||
}
|
||||
if (fieldValues.containsKey(DAY_OF_WEEK)) {
|
||||
return resolveYAD(fieldValues, resolverStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
Long pMonth = fieldValues.remove(PROLEPTIC_MONTH);
|
||||
if (pMonth != null) {
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
PROLEPTIC_MONTH.checkValidValue(pMonth);
|
||||
}
|
||||
// first day-of-month is likely to be safest for setting proleptic-month
|
||||
// cannot add to year zero, as not all chronologies have a year zero
|
||||
ChronoLocalDate chronoDate = dateNow()
|
||||
.with(DAY_OF_MONTH, 1).with(PROLEPTIC_MONTH, pMonth);
|
||||
addFieldValue(fieldValues, MONTH_OF_YEAR, chronoDate.get(MONTH_OF_YEAR));
|
||||
addFieldValue(fieldValues, YEAR, chronoDate.get(YEAR));
|
||||
}
|
||||
}
|
||||
|
||||
ChronoLocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
Long yoeLong = fieldValues.remove(YEAR_OF_ERA);
|
||||
if (yoeLong != null) {
|
||||
Long eraLong = fieldValues.remove(ERA);
|
||||
int yoe;
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA);
|
||||
} else {
|
||||
yoe = Math.toIntExact(yoeLong);
|
||||
}
|
||||
if (eraLong != null) {
|
||||
Era eraObj = eraOf(range(ERA).checkValidIntValue(eraLong, ERA));
|
||||
addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe));
|
||||
} else {
|
||||
if (fieldValues.containsKey(YEAR)) {
|
||||
int year = range(YEAR).checkValidIntValue(fieldValues.get(YEAR), YEAR);
|
||||
ChronoLocalDate chronoDate = dateYearDay(year, 1);
|
||||
addFieldValue(fieldValues, YEAR, prolepticYear(chronoDate.getEra(), yoe));
|
||||
} else if (resolverStyle == ResolverStyle.STRICT) {
|
||||
// do not invent era if strict
|
||||
// reinstate the field removed earlier, no cross-check issues
|
||||
fieldValues.put(YEAR_OF_ERA, yoeLong);
|
||||
} else {
|
||||
List<Era> eras = eras();
|
||||
if (eras.isEmpty()) {
|
||||
addFieldValue(fieldValues, YEAR, yoe);
|
||||
} else {
|
||||
Era eraObj = eras.get(eras.size() - 1);
|
||||
addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (fieldValues.containsKey(ERA)) {
|
||||
range(ERA).checkValidValue(fieldValues.get(ERA), ERA); // always validated
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ChronoLocalDate resolveYMD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
|
||||
long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
|
||||
return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS);
|
||||
}
|
||||
int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
|
||||
ValueRange domRange = range(DAY_OF_MONTH);
|
||||
int dom = domRange.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH);
|
||||
if (resolverStyle == ResolverStyle.SMART) { // previous valid
|
||||
try {
|
||||
return date(y, moy, dom);
|
||||
} catch (DateTimeException ex) {
|
||||
return date(y, moy, 1).with(TemporalAdjusters.lastDayOfMonth());
|
||||
}
|
||||
}
|
||||
return date(y, moy, dom);
|
||||
}
|
||||
|
||||
ChronoLocalDate resolveYD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1);
|
||||
return dateYearDay(y, 1).plus(days, DAYS);
|
||||
}
|
||||
int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR);
|
||||
return dateYearDay(y, doy); // smart is same as strict
|
||||
}
|
||||
|
||||
ChronoLocalDate resolveYMAA(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
|
||||
long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1);
|
||||
long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), 1);
|
||||
return date(y, 1, 1).plus(months, MONTHS).plus(weeks, WEEKS).plus(days, DAYS);
|
||||
}
|
||||
int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
|
||||
int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH);
|
||||
int ad = range(ALIGNED_DAY_OF_WEEK_IN_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), ALIGNED_DAY_OF_WEEK_IN_MONTH);
|
||||
ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7 + (ad - 1), DAYS);
|
||||
if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) {
|
||||
throw new DateTimeException("Strict mode rejected resolved date as it is in a different month");
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
ChronoLocalDate resolveYMAD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
|
||||
long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1);
|
||||
long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1);
|
||||
return resolveAligned(date(y, 1, 1), months, weeks, dow);
|
||||
}
|
||||
int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
|
||||
int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH);
|
||||
int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK);
|
||||
ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow)));
|
||||
if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) {
|
||||
throw new DateTimeException("Strict mode rejected resolved date as it is in a different month");
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
ChronoLocalDate resolveYAA(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1);
|
||||
long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), 1);
|
||||
return dateYearDay(y, 1).plus(weeks, WEEKS).plus(days, DAYS);
|
||||
}
|
||||
int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR);
|
||||
int ad = range(ALIGNED_DAY_OF_WEEK_IN_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), ALIGNED_DAY_OF_WEEK_IN_YEAR);
|
||||
ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7 + (ad - 1), DAYS);
|
||||
if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) {
|
||||
throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
ChronoLocalDate resolveYAD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1);
|
||||
long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1);
|
||||
return resolveAligned(dateYearDay(y, 1), 0, weeks, dow);
|
||||
}
|
||||
int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR);
|
||||
int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK);
|
||||
ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow)));
|
||||
if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) {
|
||||
throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
ChronoLocalDate resolveAligned(ChronoLocalDate base, long months, long weeks, long dow) {
|
||||
ChronoLocalDate date = base.plus(months, MONTHS).plus(weeks, WEEKS);
|
||||
if (dow > 7) {
|
||||
date = date.plus((dow - 1) / 7, WEEKS);
|
||||
dow = ((dow - 1) % 7) + 1;
|
||||
} else if (dow < 1) {
|
||||
date = date.plus(Math.subtractExact(dow, 7) / 7, WEEKS);
|
||||
dow = ((dow + 6) % 7) + 1;
|
||||
}
|
||||
return date.with(nextOrSame(DayOfWeek.of((int) dow)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a field-value pair to the map, checking for conflicts.
|
||||
* <p>
|
||||
* If the field is not already present, then the field-value pair is added to the map.
|
||||
* If the field is already present and it has the same value as that specified, no action occurs.
|
||||
* If the field is already present and it has a different value to that specified, then
|
||||
* an exception is thrown.
|
||||
*
|
||||
* @param field the field to add, not null
|
||||
* @param value the value to add, not null
|
||||
* @throws java.time.DateTimeException if the field is already present with a different value
|
||||
*/
|
||||
void addFieldValue(Map<TemporalField, Long> fieldValues, ChronoField field, long value) {
|
||||
Long old = fieldValues.get(field); // check first for better error message
|
||||
if (old != null && old.longValue() != value) {
|
||||
throw new DateTimeException("Conflict found: " + field + " " + old + " differs from " + field + " " + value);
|
||||
}
|
||||
fieldValues.put(field, value);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this chronology to another chronology.
|
||||
* <p>
|
||||
* The comparison order first by the chronology ID string, then by any
|
||||
* additional information specific to the subclass.
|
||||
* It is "consistent with equals", as defined by {@link Comparable}.
|
||||
*
|
||||
* @implSpec
|
||||
* This implementation compares the chronology ID.
|
||||
* Subclasses must compare any additional state that they store.
|
||||
*
|
||||
* @param other the other chronology to compare to, not null
|
||||
* @return the comparator value, negative if less, positive if greater
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Chronology other) {
|
||||
return getId().compareTo(other.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this chronology is equal to another chronology.
|
||||
* <p>
|
||||
* The comparison is based on the entire state of the object.
|
||||
*
|
||||
* @implSpec
|
||||
* This implementation checks the type and calls
|
||||
* {@link #compareTo(java.time.chrono.Chronology)}.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other chronology
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof AbstractChronology) {
|
||||
return compareTo((AbstractChronology) obj) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for this chronology.
|
||||
* <p>
|
||||
* The hash code should be based on the entire state of the object.
|
||||
*
|
||||
* @implSpec
|
||||
* This implementation is based on the chronology ID and class.
|
||||
* Subclasses should add any additional state that they store.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode() ^ getId().hashCode();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Outputs this chronology as a {@code String}, using the chronology ID.
|
||||
*
|
||||
* @return a string representation of this chronology, not null
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getId();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the Chronology using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* <pre>
|
||||
* out.writeByte(1); // identifies this as a Chronology
|
||||
* out.writeUTF(getId());
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
Object writeReplace() {
|
||||
return new Ser(Ser.CHRONO_TYPE, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws java.io.InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws ObjectStreamException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
|
||||
void writeExternal(DataOutput out) throws IOException {
|
||||
out.writeUTF(getId());
|
||||
}
|
||||
|
||||
static Chronology readExternal(DataInput in) throws IOException {
|
||||
String id = in.readUTF();
|
||||
return Chronology.of(id);
|
||||
}
|
||||
|
||||
}
|
||||
799
jdkSrc/jdk8/java/time/chrono/ChronoLocalDate.java
Normal file
799
jdkSrc/jdk8/java/time/chrono/ChronoLocalDate.java
Normal file
@@ -0,0 +1,799 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.EPOCH_DAY;
|
||||
import static java.time.temporal.ChronoField.ERA;
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
import static java.time.temporal.ChronoUnit.DAYS;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQueries;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date without time-of-day or time-zone in an arbitrary chronology, intended
|
||||
* for advanced globalization use cases.
|
||||
* <p>
|
||||
* <b>Most applications should declare method signatures, fields and variables
|
||||
* as {@link LocalDate}, not this interface.</b>
|
||||
* <p>
|
||||
* A {@code ChronoLocalDate} is the abstract representation of a date where the
|
||||
* {@code Chronology chronology}, or calendar system, is pluggable.
|
||||
* The date is defined in terms of fields expressed by {@link TemporalField},
|
||||
* where most common implementations are defined in {@link ChronoField}.
|
||||
* The chronology defines how the calendar system operates and the meaning of
|
||||
* the standard fields.
|
||||
*
|
||||
* <h3>When to use this interface</h3>
|
||||
* The design of the API encourages the use of {@code LocalDate} rather than this
|
||||
* interface, even in the case where the application needs to deal with multiple
|
||||
* calendar systems.
|
||||
* <p>
|
||||
* This concept can seem surprising at first, as the natural way to globalize an
|
||||
* application might initially appear to be to abstract the calendar system.
|
||||
* However, as explored below, abstracting the calendar system is usually the wrong
|
||||
* approach, resulting in logic errors and hard to find bugs.
|
||||
* As such, it should be considered an application-wide architectural decision to choose
|
||||
* to use this interface as opposed to {@code LocalDate}.
|
||||
*
|
||||
* <h3>Architectural issues to consider</h3>
|
||||
* These are some of the points that must be considered before using this interface
|
||||
* throughout an application.
|
||||
* <p>
|
||||
* 1) Applications using this interface, as opposed to using just {@code LocalDate},
|
||||
* face a significantly higher probability of bugs. This is because the calendar system
|
||||
* in use is not known at development time. A key cause of bugs is where the developer
|
||||
* applies assumptions from their day-to-day knowledge of the ISO calendar system
|
||||
* to code that is intended to deal with any arbitrary calendar system.
|
||||
* The section below outlines how those assumptions can cause problems
|
||||
* The primary mechanism for reducing this increased risk of bugs is a strong code review process.
|
||||
* This should also be considered a extra cost in maintenance for the lifetime of the code.
|
||||
* <p>
|
||||
* 2) This interface does not enforce immutability of implementations.
|
||||
* While the implementation notes indicate that all implementations must be immutable
|
||||
* there is nothing in the code or type system to enforce this. Any method declared
|
||||
* to accept a {@code ChronoLocalDate} could therefore be passed a poorly or
|
||||
* maliciously written mutable implementation.
|
||||
* <p>
|
||||
* 3) Applications using this interface must consider the impact of eras.
|
||||
* {@code LocalDate} shields users from the concept of eras, by ensuring that {@code getYear()}
|
||||
* returns the proleptic year. That decision ensures that developers can think of
|
||||
* {@code LocalDate} instances as consisting of three fields - year, month-of-year and day-of-month.
|
||||
* By contrast, users of this interface must think of dates as consisting of four fields -
|
||||
* era, year-of-era, month-of-year and day-of-month. The extra era field is frequently
|
||||
* forgotten, yet it is of vital importance to dates in an arbitrary calendar system.
|
||||
* For example, in the Japanese calendar system, the era represents the reign of an Emperor.
|
||||
* Whenever one reign ends and another starts, the year-of-era is reset to one.
|
||||
* <p>
|
||||
* 4) The only agreed international standard for passing a date between two systems
|
||||
* is the ISO-8601 standard which requires the ISO calendar system. Using this interface
|
||||
* throughout the application will inevitably lead to the requirement to pass the date
|
||||
* across a network or component boundary, requiring an application specific protocol or format.
|
||||
* <p>
|
||||
* 5) Long term persistence, such as a database, will almost always only accept dates in the
|
||||
* ISO-8601 calendar system (or the related Julian-Gregorian). Passing around dates in other
|
||||
* calendar systems increases the complications of interacting with persistence.
|
||||
* <p>
|
||||
* 6) Most of the time, passing a {@code ChronoLocalDate} throughout an application
|
||||
* is unnecessary, as discussed in the last section below.
|
||||
*
|
||||
* <h3>False assumptions causing bugs in multi-calendar system code</h3>
|
||||
* As indicated above, there are many issues to consider when try to use and manipulate a
|
||||
* date in an arbitrary calendar system. These are some of the key issues.
|
||||
* <p>
|
||||
* Code that queries the day-of-month and assumes that the value will never be more than
|
||||
* 31 is invalid. Some calendar systems have more than 31 days in some months.
|
||||
* <p>
|
||||
* Code that adds 12 months to a date and assumes that a year has been added is invalid.
|
||||
* Some calendar systems have a different number of months, such as 13 in the Coptic or Ethiopic.
|
||||
* <p>
|
||||
* Code that adds one month to a date and assumes that the month-of-year value will increase
|
||||
* by one or wrap to the next year is invalid. Some calendar systems have a variable number
|
||||
* of months in a year, such as the Hebrew.
|
||||
* <p>
|
||||
* Code that adds one month, then adds a second one month and assumes that the day-of-month
|
||||
* will remain close to its original value is invalid. Some calendar systems have a large difference
|
||||
* between the length of the longest month and the length of the shortest month.
|
||||
* For example, the Coptic or Ethiopic have 12 months of 30 days and 1 month of 5 days.
|
||||
* <p>
|
||||
* Code that adds seven days and assumes that a week has been added is invalid.
|
||||
* Some calendar systems have weeks of other than seven days, such as the French Revolutionary.
|
||||
* <p>
|
||||
* Code that assumes that because the year of {@code date1} is greater than the year of {@code date2}
|
||||
* then {@code date1} is after {@code date2} is invalid. This is invalid for all calendar systems
|
||||
* when referring to the year-of-era, and especially untrue of the Japanese calendar system
|
||||
* where the year-of-era restarts with the reign of every new Emperor.
|
||||
* <p>
|
||||
* Code that treats month-of-year one and day-of-month one as the start of the year is invalid.
|
||||
* Not all calendar systems start the year when the month value is one.
|
||||
* <p>
|
||||
* In general, manipulating a date, and even querying a date, is wide open to bugs when the
|
||||
* calendar system is unknown at development time. This is why it is essential that code using
|
||||
* this interface is subjected to additional code reviews. It is also why an architectural
|
||||
* decision to avoid this interface type is usually the correct one.
|
||||
*
|
||||
* <h3>Using LocalDate instead</h3>
|
||||
* The primary alternative to using this interface throughout your application is as follows.
|
||||
* <ul>
|
||||
* <li>Declare all method signatures referring to dates in terms of {@code LocalDate}.
|
||||
* <li>Either store the chronology (calendar system) in the user profile or lookup
|
||||
* the chronology from the user locale
|
||||
* <li>Convert the ISO {@code LocalDate} to and from the user's preferred calendar system during
|
||||
* printing and parsing
|
||||
* </ul>
|
||||
* This approach treats the problem of globalized calendar systems as a localization issue
|
||||
* and confines it to the UI layer. This approach is in keeping with other localization
|
||||
* issues in the java platform.
|
||||
* <p>
|
||||
* As discussed above, performing calculations on a date where the rules of the calendar system
|
||||
* are pluggable requires skill and is not recommended.
|
||||
* Fortunately, the need to perform calculations on a date in an arbitrary calendar system
|
||||
* is extremely rare. For example, it is highly unlikely that the business rules of a library
|
||||
* book rental scheme will allow rentals to be for one month, where meaning of the month
|
||||
* is dependent on the user's preferred calendar system.
|
||||
* <p>
|
||||
* A key use case for calculations on a date in an arbitrary calendar system is producing
|
||||
* a month-by-month calendar for display and user interaction. Again, this is a UI issue,
|
||||
* and use of this interface solely within a few methods of the UI layer may be justified.
|
||||
* <p>
|
||||
* In any other part of the system, where a date must be manipulated in a calendar system
|
||||
* other than ISO, the use case will generally specify the calendar system to use.
|
||||
* For example, an application may need to calculate the next Islamic or Hebrew holiday
|
||||
* which may require manipulating the date.
|
||||
* This kind of use case can be handled as follows:
|
||||
* <ul>
|
||||
* <li>start from the ISO {@code LocalDate} being passed to the method
|
||||
* <li>convert the date to the alternate calendar system, which for this use case is known
|
||||
* rather than arbitrary
|
||||
* <li>perform the calculation
|
||||
* <li>convert back to {@code LocalDate}
|
||||
* </ul>
|
||||
* Developers writing low-level frameworks or libraries should also avoid this interface.
|
||||
* Instead, one of the two general purpose access interfaces should be used.
|
||||
* Use {@link TemporalAccessor} if read-only access is required, or use {@link Temporal}
|
||||
* if read-write access is required.
|
||||
*
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
* <p>
|
||||
* Additional calendar systems may be added to the system.
|
||||
* See {@link Chronology} for more details.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface ChronoLocalDate
|
||||
extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDate> {
|
||||
|
||||
/**
|
||||
* Gets a comparator that compares {@code ChronoLocalDate} in
|
||||
* time-line order ignoring the chronology.
|
||||
* <p>
|
||||
* This comparator differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the underlying date and not the chronology.
|
||||
* This allows dates in different calendar systems to be compared based
|
||||
* on the position of the date on the local time-line.
|
||||
* The underlying comparison is equivalent to comparing the epoch-day.
|
||||
*
|
||||
* @return a comparator that compares in time-line order ignoring the chronology
|
||||
* @see #isAfter
|
||||
* @see #isBefore
|
||||
* @see #isEqual
|
||||
*/
|
||||
static Comparator<ChronoLocalDate> timeLineOrder() {
|
||||
return AbstractChronology.DATE_ORDER;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code ChronoLocalDate} from a temporal object.
|
||||
* <p>
|
||||
* This obtains a local date based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code ChronoLocalDate}.
|
||||
* <p>
|
||||
* The conversion extracts and combines the chronology and the date
|
||||
* from the temporal object. The behavior is equivalent to using
|
||||
* {@link Chronology#date(TemporalAccessor)} with the extracted chronology.
|
||||
* Implementations are permitted to perform optimizations such as accessing
|
||||
* those fields that are equivalent to the relevant objects.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code ChronoLocalDate::from}.
|
||||
*
|
||||
* @param temporal the temporal object to convert, not null
|
||||
* @return the date, not null
|
||||
* @throws DateTimeException if unable to convert to a {@code ChronoLocalDate}
|
||||
* @see Chronology#date(TemporalAccessor)
|
||||
*/
|
||||
static ChronoLocalDate from(TemporalAccessor temporal) {
|
||||
if (temporal instanceof ChronoLocalDate) {
|
||||
return (ChronoLocalDate) temporal;
|
||||
}
|
||||
Objects.requireNonNull(temporal, "temporal");
|
||||
Chronology chrono = temporal.query(TemporalQueries.chronology());
|
||||
if (chrono == null) {
|
||||
throw new DateTimeException("Unable to obtain ChronoLocalDate from TemporalAccessor: " + temporal.getClass());
|
||||
}
|
||||
return chrono.date(temporal);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the chronology of this date.
|
||||
* <p>
|
||||
* The {@code Chronology} represents the calendar system in use.
|
||||
* The era and other fields in {@link ChronoField} are defined by the chronology.
|
||||
*
|
||||
* @return the chronology, not null
|
||||
*/
|
||||
Chronology getChronology();
|
||||
|
||||
/**
|
||||
* Gets the era, as defined by the chronology.
|
||||
* <p>
|
||||
* The era is, conceptually, the largest division of the time-line.
|
||||
* Most calendar systems have a single epoch dividing the time-line into two eras.
|
||||
* However, some have multiple eras, such as one for the reign of each leader.
|
||||
* The exact meaning is determined by the {@code Chronology}.
|
||||
* <p>
|
||||
* All correctly implemented {@code Era} classes are singletons, thus it
|
||||
* is valid code to write {@code date.getEra() == SomeChrono.ERA_NAME)}.
|
||||
* <p>
|
||||
* This default implementation uses {@link Chronology#eraOf(int)}.
|
||||
*
|
||||
* @return the chronology specific era constant applicable at this date, not null
|
||||
*/
|
||||
default Era getEra() {
|
||||
return getChronology().eraOf(get(ERA));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the year is a leap year, as defined by the calendar system.
|
||||
* <p>
|
||||
* A leap-year is a year of a longer length than normal.
|
||||
* The exact meaning is determined by the chronology with the constraint that
|
||||
* a leap-year must imply a year-length longer than a non leap-year.
|
||||
* <p>
|
||||
* This default implementation uses {@link Chronology#isLeapYear(long)}.
|
||||
*
|
||||
* @return true if this date is in a leap year, false otherwise
|
||||
*/
|
||||
default boolean isLeapYear() {
|
||||
return getChronology().isLeapYear(getLong(YEAR));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the month represented by this date, as defined by the calendar system.
|
||||
* <p>
|
||||
* This returns the length of the month in days.
|
||||
*
|
||||
* @return the length of the month in days
|
||||
*/
|
||||
int lengthOfMonth();
|
||||
|
||||
/**
|
||||
* Returns the length of the year represented by this date, as defined by the calendar system.
|
||||
* <p>
|
||||
* This returns the length of the year in days.
|
||||
* <p>
|
||||
* The default implementation uses {@link #isLeapYear()} and returns 365 or 366.
|
||||
*
|
||||
* @return the length of the year in days
|
||||
*/
|
||||
default int lengthOfYear() {
|
||||
return (isLeapYear() ? 366 : 365);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified field is supported.
|
||||
* <p>
|
||||
* This checks if the specified field can be queried on this date.
|
||||
* If false, then calling the {@link #range(TemporalField) range},
|
||||
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
|
||||
* methods will throw an exception.
|
||||
* <p>
|
||||
* The set of supported fields is defined by the chronology and normally includes
|
||||
* all {@code ChronoField} date fields.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the field is supported is determined by the field.
|
||||
*
|
||||
* @param field the field to check, null returns false
|
||||
* @return true if the field can be queried, false if not
|
||||
*/
|
||||
@Override
|
||||
default boolean isSupported(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
return field.isDateBased();
|
||||
}
|
||||
return field != null && field.isSupportedBy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified unit is supported.
|
||||
* <p>
|
||||
* This checks if the specified unit can be added to or subtracted from this date.
|
||||
* If false, then calling the {@link #plus(long, TemporalUnit)} and
|
||||
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
|
||||
* <p>
|
||||
* The set of supported units is defined by the chronology and normally includes
|
||||
* all {@code ChronoUnit} date units except {@code FOREVER}.
|
||||
* <p>
|
||||
* If the unit is not a {@code ChronoUnit}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the unit is supported is determined by the unit.
|
||||
*
|
||||
* @param unit the unit to check, null returns false
|
||||
* @return true if the unit can be added/subtracted, false if not
|
||||
*/
|
||||
@Override
|
||||
default boolean isSupported(TemporalUnit unit) {
|
||||
if (unit instanceof ChronoUnit) {
|
||||
return unit.isDateBased();
|
||||
}
|
||||
return unit != null && unit.isSupportedBy(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// override for covariant return type
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoLocalDate with(TemporalAdjuster adjuster) {
|
||||
return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws UnsupportedTemporalTypeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoLocalDate with(TemporalField field, long newValue) {
|
||||
if (field instanceof ChronoField) {
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
}
|
||||
return ChronoLocalDateImpl.ensureValid(getChronology(), field.adjustInto(this, newValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoLocalDate plus(TemporalAmount amount) {
|
||||
return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoLocalDate plus(long amountToAdd, TemporalUnit unit) {
|
||||
if (unit instanceof ChronoUnit) {
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
|
||||
}
|
||||
return ChronoLocalDateImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoLocalDate minus(TemporalAmount amount) {
|
||||
return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws UnsupportedTemporalTypeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit) {
|
||||
return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Queries this date using the specified query.
|
||||
* <p>
|
||||
* This queries this date using the specified query strategy object.
|
||||
* The {@code TemporalQuery} object defines the logic to be used to
|
||||
* obtain the result. Read the documentation of the query to understand
|
||||
* what the result of this method will be.
|
||||
* <p>
|
||||
* The result of this method is obtained by invoking the
|
||||
* {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
|
||||
* specified query passing {@code this} as the argument.
|
||||
*
|
||||
* @param <R> the type of the result
|
||||
* @param query the query to invoke, not null
|
||||
* @return the query result, null may be returned (defined by the query)
|
||||
* @throws DateTimeException if unable to query (defined by the query)
|
||||
* @throws ArithmeticException if numeric overflow occurs (defined by the query)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
default <R> R query(TemporalQuery<R> query) {
|
||||
if (query == TemporalQueries.zoneId() || query == TemporalQueries.zone() || query == TemporalQueries.offset()) {
|
||||
return null;
|
||||
} else if (query == TemporalQueries.localTime()) {
|
||||
return null;
|
||||
} else if (query == TemporalQueries.chronology()) {
|
||||
return (R) getChronology();
|
||||
} else if (query == TemporalQueries.precision()) {
|
||||
return (R) DAYS;
|
||||
}
|
||||
// inline TemporalAccessor.super.query(query) as an optimization
|
||||
// non-JDK classes are not permitted to make this optimization
|
||||
return query.queryFrom(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the specified temporal object to have the same date as this object.
|
||||
* <p>
|
||||
* This returns a temporal object of the same observable type as the input
|
||||
* with the date changed to be the same as this.
|
||||
* <p>
|
||||
* The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
|
||||
* passing {@link ChronoField#EPOCH_DAY} as the field.
|
||||
* <p>
|
||||
* In most cases, it is clearer to reverse the calling pattern by using
|
||||
* {@link Temporal#with(TemporalAdjuster)}:
|
||||
* <pre>
|
||||
* // these two lines are equivalent, but the second approach is recommended
|
||||
* temporal = thisLocalDate.adjustInto(temporal);
|
||||
* temporal = temporal.with(thisLocalDate);
|
||||
* </pre>
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param temporal the target object to be adjusted, not null
|
||||
* @return the adjusted object, not null
|
||||
* @throws DateTimeException if unable to make the adjustment
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
default Temporal adjustInto(Temporal temporal) {
|
||||
return temporal.with(EPOCH_DAY, toEpochDay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the amount of time until another date in terms of the specified unit.
|
||||
* <p>
|
||||
* This calculates the amount of time between two {@code ChronoLocalDate}
|
||||
* objects in terms of a single {@code TemporalUnit}.
|
||||
* The start and end points are {@code this} and the specified date.
|
||||
* The result will be negative if the end is before the start.
|
||||
* The {@code Temporal} passed to this method is converted to a
|
||||
* {@code ChronoLocalDate} using {@link Chronology#date(TemporalAccessor)}.
|
||||
* The calculation returns a whole number, representing the number of
|
||||
* complete units between the two dates.
|
||||
* For example, the amount in days between two dates can be calculated
|
||||
* using {@code startDate.until(endDate, DAYS)}.
|
||||
* <p>
|
||||
* There are two equivalent ways of using this method.
|
||||
* The first is to invoke this method.
|
||||
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
|
||||
* <pre>
|
||||
* // these two lines are equivalent
|
||||
* amount = start.until(end, MONTHS);
|
||||
* amount = MONTHS.between(start, end);
|
||||
* </pre>
|
||||
* The choice should be made based on which makes the code more readable.
|
||||
* <p>
|
||||
* The calculation is implemented in this method for {@link ChronoUnit}.
|
||||
* The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS},
|
||||
* {@code DECADES}, {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS}
|
||||
* should be supported by all implementations.
|
||||
* Other {@code ChronoUnit} values will throw an exception.
|
||||
* <p>
|
||||
* If the unit is not a {@code ChronoUnit}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
|
||||
* passing {@code this} as the first argument and the converted input temporal as
|
||||
* the second argument.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endExclusive the end date, exclusive, which is converted to a
|
||||
* {@code ChronoLocalDate} in the same chronology, not null
|
||||
* @param unit the unit to measure the amount in, not null
|
||||
* @return the amount of time between this date and the end date
|
||||
* @throws DateTimeException if the amount cannot be calculated, or the end
|
||||
* temporal cannot be converted to a {@code ChronoLocalDate}
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override // override for Javadoc
|
||||
long until(Temporal endExclusive, TemporalUnit unit);
|
||||
|
||||
/**
|
||||
* Calculates the period between this date and another date as a {@code ChronoPeriod}.
|
||||
* <p>
|
||||
* This calculates the period between two dates. All supplied chronologies
|
||||
* calculate the period using years, months and days, however the
|
||||
* {@code ChronoPeriod} API allows the period to be represented using other units.
|
||||
* <p>
|
||||
* The start and end points are {@code this} and the specified date.
|
||||
* The result will be negative if the end is before the start.
|
||||
* The negative sign will be the same in each of year, month and day.
|
||||
* <p>
|
||||
* The calculation is performed using the chronology of this date.
|
||||
* If necessary, the input date will be converted to match.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param endDateExclusive the end date, exclusive, which may be in any chronology, not null
|
||||
* @return the period between this date and the end date, not null
|
||||
* @throws DateTimeException if the period cannot be calculated
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
ChronoPeriod until(ChronoLocalDate endDateExclusive);
|
||||
|
||||
/**
|
||||
* Formats this date using the specified formatter.
|
||||
* <p>
|
||||
* This date will be passed to the formatter to produce a string.
|
||||
* <p>
|
||||
* The default implementation must behave as follows:
|
||||
* <pre>
|
||||
* return formatter.format(this);
|
||||
* </pre>
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted date string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
default String format(DateTimeFormatter formatter) {
|
||||
Objects.requireNonNull(formatter, "formatter");
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Combines this date with a time to create a {@code ChronoLocalDateTime}.
|
||||
* <p>
|
||||
* This returns a {@code ChronoLocalDateTime} formed from this date at the specified time.
|
||||
* All possible combinations of date and time are valid.
|
||||
*
|
||||
* @param localTime the local time to use, not null
|
||||
* @return the local date-time formed from this date and the specified time, not null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default ChronoLocalDateTime<?> atTime(LocalTime localTime) {
|
||||
return ChronoLocalDateTimeImpl.of(this, localTime);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Converts this date to the Epoch Day.
|
||||
* <p>
|
||||
* The {@link ChronoField#EPOCH_DAY Epoch Day count} is a simple
|
||||
* incrementing count of days where day 0 is 1970-01-01 (ISO).
|
||||
* This definition is the same for all chronologies, enabling conversion.
|
||||
* <p>
|
||||
* This default implementation queries the {@code EPOCH_DAY} field.
|
||||
*
|
||||
* @return the Epoch Day equivalent to this date
|
||||
*/
|
||||
default long toEpochDay() {
|
||||
return getLong(EPOCH_DAY);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this date to another date, including the chronology.
|
||||
* <p>
|
||||
* The comparison is based first on the underlying time-line date, then
|
||||
* on the chronology.
|
||||
* It is "consistent with equals", as defined by {@link Comparable}.
|
||||
* <p>
|
||||
* For example, the following is the comparator order:
|
||||
* <ol>
|
||||
* <li>{@code 2012-12-03 (ISO)}</li>
|
||||
* <li>{@code 2012-12-04 (ISO)}</li>
|
||||
* <li>{@code 2555-12-04 (ThaiBuddhist)}</li>
|
||||
* <li>{@code 2012-12-05 (ISO)}</li>
|
||||
* </ol>
|
||||
* Values #2 and #3 represent the same date on the time-line.
|
||||
* When two values represent the same date, the chronology ID is compared to distinguish them.
|
||||
* This step is needed to make the ordering "consistent with equals".
|
||||
* <p>
|
||||
* If all the date objects being compared are in the same chronology, then the
|
||||
* additional chronology stage is not required and only the local date is used.
|
||||
* To compare the dates of two {@code TemporalAccessor} instances, including dates
|
||||
* in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
|
||||
* <p>
|
||||
* This default implementation performs the comparison defined above.
|
||||
*
|
||||
* @param other the other date to compare to, not null
|
||||
* @return the comparator value, negative if less, positive if greater
|
||||
*/
|
||||
@Override
|
||||
default int compareTo(ChronoLocalDate other) {
|
||||
int cmp = Long.compare(toEpochDay(), other.toEpochDay());
|
||||
if (cmp == 0) {
|
||||
cmp = getChronology().compareTo(other.getChronology());
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this date is after the specified date ignoring the chronology.
|
||||
* <p>
|
||||
* This method differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the underlying date and not the chronology.
|
||||
* This allows dates in different calendar systems to be compared based
|
||||
* on the time-line position.
|
||||
* This is equivalent to using {@code date1.toEpochDay() > date2.toEpochDay()}.
|
||||
* <p>
|
||||
* This default implementation performs the comparison based on the epoch-day.
|
||||
*
|
||||
* @param other the other date to compare to, not null
|
||||
* @return true if this is after the specified date
|
||||
*/
|
||||
default boolean isAfter(ChronoLocalDate other) {
|
||||
return this.toEpochDay() > other.toEpochDay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this date is before the specified date ignoring the chronology.
|
||||
* <p>
|
||||
* This method differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the underlying date and not the chronology.
|
||||
* This allows dates in different calendar systems to be compared based
|
||||
* on the time-line position.
|
||||
* This is equivalent to using {@code date1.toEpochDay() < date2.toEpochDay()}.
|
||||
* <p>
|
||||
* This default implementation performs the comparison based on the epoch-day.
|
||||
*
|
||||
* @param other the other date to compare to, not null
|
||||
* @return true if this is before the specified date
|
||||
*/
|
||||
default boolean isBefore(ChronoLocalDate other) {
|
||||
return this.toEpochDay() < other.toEpochDay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this date is equal to the specified date ignoring the chronology.
|
||||
* <p>
|
||||
* This method differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the underlying date and not the chronology.
|
||||
* This allows dates in different calendar systems to be compared based
|
||||
* on the time-line position.
|
||||
* This is equivalent to using {@code date1.toEpochDay() == date2.toEpochDay()}.
|
||||
* <p>
|
||||
* This default implementation performs the comparison based on the epoch-day.
|
||||
*
|
||||
* @param other the other date to compare to, not null
|
||||
* @return true if the underlying date is equal to the specified date
|
||||
*/
|
||||
default boolean isEqual(ChronoLocalDate other) {
|
||||
return this.toEpochDay() == other.toEpochDay();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if this date is equal to another date, including the chronology.
|
||||
* <p>
|
||||
* Compares this date with another ensuring that the date and chronology are the same.
|
||||
* <p>
|
||||
* To compare the dates of two {@code TemporalAccessor} instances, including dates
|
||||
* in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other date
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* A hash code for this date.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Outputs this date as a {@code String}.
|
||||
* <p>
|
||||
* The output will include the full local date.
|
||||
*
|
||||
* @return the formatted date, not null
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
}
|
||||
444
jdkSrc/jdk8/java/time/chrono/ChronoLocalDateImpl.java
Normal file
444
jdkSrc/jdk8/java/time/chrono/ChronoLocalDateImpl.java
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.ERA;
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
|
||||
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date expressed in terms of a standard year-month-day calendar system.
|
||||
* <p>
|
||||
* This class is used by applications seeking to handle dates in non-ISO calendar systems.
|
||||
* For example, the Japanese, Minguo, Thai Buddhist and others.
|
||||
* <p>
|
||||
* {@code ChronoLocalDate} is built on the generic concepts of year, month and day.
|
||||
* The calendar system, represented by a {@link java.time.chrono.Chronology}, expresses the relationship between
|
||||
* the fields and this class allows the resulting date to be manipulated.
|
||||
* <p>
|
||||
* Note that not all calendar systems are suitable for use with this class.
|
||||
* For example, the Mayan calendar uses a system that bears no relation to years, months and days.
|
||||
* <p>
|
||||
* The API design encourages the use of {@code LocalDate} for the majority of the application.
|
||||
* This includes code to read and write from a persistent data store, such as a database,
|
||||
* and to send dates and times across a network. The {@code ChronoLocalDate} instance is then used
|
||||
* at the user interface level to deal with localized input/output.
|
||||
*
|
||||
* <P>Example: </p>
|
||||
* <pre>
|
||||
* System.out.printf("Example()%n");
|
||||
* // Enumerate the list of available calendars and print today for each
|
||||
* Set<Chronology> chronos = Chronology.getAvailableChronologies();
|
||||
* for (Chronology chrono : chronos) {
|
||||
* ChronoLocalDate date = chrono.dateNow();
|
||||
* System.out.printf(" %20s: %s%n", chrono.getID(), date.toString());
|
||||
* }
|
||||
*
|
||||
* // Print the Hijrah date and calendar
|
||||
* ChronoLocalDate date = Chronology.of("Hijrah").dateNow();
|
||||
* int day = date.get(ChronoField.DAY_OF_MONTH);
|
||||
* int dow = date.get(ChronoField.DAY_OF_WEEK);
|
||||
* int month = date.get(ChronoField.MONTH_OF_YEAR);
|
||||
* int year = date.get(ChronoField.YEAR);
|
||||
* System.out.printf(" Today is %s %s %d-%s-%d%n", date.getChronology().getID(),
|
||||
* dow, day, month, year);
|
||||
|
||||
* // Print today's date and the last day of the year
|
||||
* ChronoLocalDate now1 = Chronology.of("Hijrah").dateNow();
|
||||
* ChronoLocalDate first = now1.with(ChronoField.DAY_OF_MONTH, 1)
|
||||
* .with(ChronoField.MONTH_OF_YEAR, 1);
|
||||
* ChronoLocalDate last = first.plus(1, ChronoUnit.YEARS)
|
||||
* .minus(1, ChronoUnit.DAYS);
|
||||
* System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChronology().getID(),
|
||||
* first, last);
|
||||
* </pre>
|
||||
*
|
||||
* <h3>Adding Calendars</h3>
|
||||
* <p> The set of calendars is extensible by defining a subclass of {@link ChronoLocalDate}
|
||||
* to represent a date instance and an implementation of {@code Chronology}
|
||||
* to be the factory for the ChronoLocalDate subclass.
|
||||
* </p>
|
||||
* <p> To permit the discovery of the additional calendar types the implementation of
|
||||
* {@code Chronology} must be registered as a Service implementing the {@code Chronology} interface
|
||||
* in the {@code META-INF/Services} file as per the specification of {@link java.util.ServiceLoader}.
|
||||
* The subclass must function according to the {@code Chronology} class description and must provide its
|
||||
* {@link java.time.chrono.Chronology#getId() chronlogy ID} and {@link Chronology#getCalendarType() calendar type}. </p>
|
||||
*
|
||||
* @implSpec
|
||||
* This abstract class must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
*
|
||||
* @param <D> the ChronoLocalDate of this date-time
|
||||
* @since 1.8
|
||||
*/
|
||||
abstract class ChronoLocalDateImpl<D extends ChronoLocalDate>
|
||||
implements ChronoLocalDate, Temporal, TemporalAdjuster, Serializable {
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = 6282433883239719096L;
|
||||
|
||||
/**
|
||||
* Casts the {@code Temporal} to {@code ChronoLocalDate} ensuring it bas the specified chronology.
|
||||
*
|
||||
* @param chrono the chronology to check for, not null
|
||||
* @param temporal a date-time to cast, not null
|
||||
* @return the date-time checked and cast to {@code ChronoLocalDate}, not null
|
||||
* @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate
|
||||
* or the chronology is not equal this Chronology
|
||||
*/
|
||||
static <D extends ChronoLocalDate> D ensureValid(Chronology chrono, Temporal temporal) {
|
||||
@SuppressWarnings("unchecked")
|
||||
D other = (D) temporal;
|
||||
if (chrono.equals(other.getChronology()) == false) {
|
||||
throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + other.getChronology().getId());
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Creates an instance.
|
||||
*/
|
||||
ChronoLocalDateImpl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public D with(TemporalAdjuster adjuster) {
|
||||
return (D) ChronoLocalDate.super.with(adjuster);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public D with(TemporalField field, long value) {
|
||||
return (D) ChronoLocalDate.super.with(field, value);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public D plus(TemporalAmount amount) {
|
||||
return (D) ChronoLocalDate.super.plus(amount);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public D plus(long amountToAdd, TemporalUnit unit) {
|
||||
if (unit instanceof ChronoUnit) {
|
||||
ChronoUnit f = (ChronoUnit) unit;
|
||||
switch (f) {
|
||||
case DAYS: return plusDays(amountToAdd);
|
||||
case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7));
|
||||
case MONTHS: return plusMonths(amountToAdd);
|
||||
case YEARS: return plusYears(amountToAdd);
|
||||
case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
|
||||
case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
|
||||
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
|
||||
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
|
||||
}
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
|
||||
}
|
||||
return (D) ChronoLocalDate.super.plus(amountToAdd, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public D minus(TemporalAmount amount) {
|
||||
return (D) ChronoLocalDate.super.minus(amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public D minus(long amountToSubtract, TemporalUnit unit) {
|
||||
return (D) ChronoLocalDate.super.minus(amountToSubtract, unit);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a copy of this date with the specified number of years added.
|
||||
* <p>
|
||||
* This adds the specified period in years to the date.
|
||||
* In some cases, adding years can cause the resulting date to become invalid.
|
||||
* If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
|
||||
* that the result is valid. Typically this will select the last valid day of the month.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param yearsToAdd the years to add, may be negative
|
||||
* @return a date based on this one with the years added, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
abstract D plusYears(long yearsToAdd);
|
||||
|
||||
/**
|
||||
* Returns a copy of this date with the specified number of months added.
|
||||
* <p>
|
||||
* This adds the specified period in months to the date.
|
||||
* In some cases, adding months can cause the resulting date to become invalid.
|
||||
* If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
|
||||
* that the result is valid. Typically this will select the last valid day of the month.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param monthsToAdd the months to add, may be negative
|
||||
* @return a date based on this one with the months added, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
abstract D plusMonths(long monthsToAdd);
|
||||
|
||||
/**
|
||||
* Returns a copy of this date with the specified number of weeks added.
|
||||
* <p>
|
||||
* This adds the specified period in weeks to the date.
|
||||
* In some cases, adding weeks can cause the resulting date to become invalid.
|
||||
* If this occurs, then other fields will be adjusted to ensure that the result is valid.
|
||||
* <p>
|
||||
* The default implementation uses {@link #plusDays(long)} using a 7 day week.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param weeksToAdd the weeks to add, may be negative
|
||||
* @return a date based on this one with the weeks added, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
D plusWeeks(long weeksToAdd) {
|
||||
return plusDays(Math.multiplyExact(weeksToAdd, 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this date with the specified number of days added.
|
||||
* <p>
|
||||
* This adds the specified period in days to the date.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param daysToAdd the days to add, may be negative
|
||||
* @return a date based on this one with the days added, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
abstract D plusDays(long daysToAdd);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a copy of this date with the specified number of years subtracted.
|
||||
* <p>
|
||||
* This subtracts the specified period in years to the date.
|
||||
* In some cases, subtracting years can cause the resulting date to become invalid.
|
||||
* If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
|
||||
* that the result is valid. Typically this will select the last valid day of the month.
|
||||
* <p>
|
||||
* The default implementation uses {@link #plusYears(long)}.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param yearsToSubtract the years to subtract, may be negative
|
||||
* @return a date based on this one with the years subtracted, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
D minusYears(long yearsToSubtract) {
|
||||
return (yearsToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl<D>)plusYears(Long.MAX_VALUE)).plusYears(1) : plusYears(-yearsToSubtract));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this date with the specified number of months subtracted.
|
||||
* <p>
|
||||
* This subtracts the specified period in months to the date.
|
||||
* In some cases, subtracting months can cause the resulting date to become invalid.
|
||||
* If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
|
||||
* that the result is valid. Typically this will select the last valid day of the month.
|
||||
* <p>
|
||||
* The default implementation uses {@link #plusMonths(long)}.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param monthsToSubtract the months to subtract, may be negative
|
||||
* @return a date based on this one with the months subtracted, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
D minusMonths(long monthsToSubtract) {
|
||||
return (monthsToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl<D>)plusMonths(Long.MAX_VALUE)).plusMonths(1) : plusMonths(-monthsToSubtract));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this date with the specified number of weeks subtracted.
|
||||
* <p>
|
||||
* This subtracts the specified period in weeks to the date.
|
||||
* In some cases, subtracting weeks can cause the resulting date to become invalid.
|
||||
* If this occurs, then other fields will be adjusted to ensure that the result is valid.
|
||||
* <p>
|
||||
* The default implementation uses {@link #plusWeeks(long)}.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param weeksToSubtract the weeks to subtract, may be negative
|
||||
* @return a date based on this one with the weeks subtracted, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
D minusWeeks(long weeksToSubtract) {
|
||||
return (weeksToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl<D>)plusWeeks(Long.MAX_VALUE)).plusWeeks(1) : plusWeeks(-weeksToSubtract));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this date with the specified number of days subtracted.
|
||||
* <p>
|
||||
* This subtracts the specified period in days to the date.
|
||||
* <p>
|
||||
* The default implementation uses {@link #plusDays(long)}.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param daysToSubtract the days to subtract, may be negative
|
||||
* @return a date based on this one with the days subtracted, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
D minusDays(long daysToSubtract) {
|
||||
return (daysToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl<D>)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public long until(Temporal endExclusive, TemporalUnit unit) {
|
||||
Objects.requireNonNull(endExclusive, "endExclusive");
|
||||
ChronoLocalDate end = getChronology().date(endExclusive);
|
||||
if (unit instanceof ChronoUnit) {
|
||||
switch ((ChronoUnit) unit) {
|
||||
case DAYS: return daysUntil(end);
|
||||
case WEEKS: return daysUntil(end) / 7;
|
||||
case MONTHS: return monthsUntil(end);
|
||||
case YEARS: return monthsUntil(end) / 12;
|
||||
case DECADES: return monthsUntil(end) / 120;
|
||||
case CENTURIES: return monthsUntil(end) / 1200;
|
||||
case MILLENNIA: return monthsUntil(end) / 12000;
|
||||
case ERAS: return end.getLong(ERA) - getLong(ERA);
|
||||
}
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
|
||||
}
|
||||
Objects.requireNonNull(unit, "unit");
|
||||
return unit.between(this, end);
|
||||
}
|
||||
|
||||
private long daysUntil(ChronoLocalDate end) {
|
||||
return end.toEpochDay() - toEpochDay(); // no overflow
|
||||
}
|
||||
|
||||
private long monthsUntil(ChronoLocalDate end) {
|
||||
ValueRange range = getChronology().range(MONTH_OF_YEAR);
|
||||
if (range.getMaximum() != 12) {
|
||||
throw new IllegalStateException("ChronoLocalDateImpl only supports Chronologies with 12 months per year");
|
||||
}
|
||||
long packed1 = getLong(PROLEPTIC_MONTH) * 32L + get(DAY_OF_MONTH); // no overflow
|
||||
long packed2 = end.getLong(PROLEPTIC_MONTH) * 32L + end.get(DAY_OF_MONTH); // no overflow
|
||||
return (packed2 - packed1) / 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof ChronoLocalDate) {
|
||||
return compareTo((ChronoLocalDate) obj) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
long epDay = toEpochDay();
|
||||
return getChronology().hashCode() ^ ((int) (epDay ^ (epDay >>> 32)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// getLong() reduces chances of exceptions in toString()
|
||||
long yoe = getLong(YEAR_OF_ERA);
|
||||
long moy = getLong(MONTH_OF_YEAR);
|
||||
long dom = getLong(DAY_OF_MONTH);
|
||||
StringBuilder buf = new StringBuilder(30);
|
||||
buf.append(getChronology().toString())
|
||||
.append(" ")
|
||||
.append(getEra())
|
||||
.append(" ")
|
||||
.append(yoe)
|
||||
.append(moy < 10 ? "-0" : "-").append(moy)
|
||||
.append(dom < 10 ? "-0" : "-").append(dom);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
602
jdkSrc/jdk8/java/time/chrono/ChronoLocalDateTime.java
Normal file
602
jdkSrc/jdk8/java/time/chrono/ChronoLocalDateTime.java
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.EPOCH_DAY;
|
||||
import static java.time.temporal.ChronoField.NANO_OF_DAY;
|
||||
import static java.time.temporal.ChronoUnit.FOREVER;
|
||||
import static java.time.temporal.ChronoUnit.NANOS;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQueries;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.zone.ZoneRules;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date-time without a time-zone in an arbitrary chronology, intended
|
||||
* for advanced globalization use cases.
|
||||
* <p>
|
||||
* <b>Most applications should declare method signatures, fields and variables
|
||||
* as {@link LocalDateTime}, not this interface.</b>
|
||||
* <p>
|
||||
* A {@code ChronoLocalDateTime} is the abstract representation of a local date-time
|
||||
* where the {@code Chronology chronology}, or calendar system, is pluggable.
|
||||
* The date-time is defined in terms of fields expressed by {@link TemporalField},
|
||||
* where most common implementations are defined in {@link ChronoField}.
|
||||
* The chronology defines how the calendar system operates and the meaning of
|
||||
* the standard fields.
|
||||
*
|
||||
* <h3>When to use this interface</h3>
|
||||
* The design of the API encourages the use of {@code LocalDateTime} rather than this
|
||||
* interface, even in the case where the application needs to deal with multiple
|
||||
* calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}.
|
||||
* <p>
|
||||
* Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
|
||||
* before using this interface.
|
||||
*
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
*
|
||||
* @param <D> the concrete type for the date of this date-time
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface ChronoLocalDateTime<D extends ChronoLocalDate>
|
||||
extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDateTime<?>> {
|
||||
|
||||
/**
|
||||
* Gets a comparator that compares {@code ChronoLocalDateTime} in
|
||||
* time-line order ignoring the chronology.
|
||||
* <p>
|
||||
* This comparator differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the underlying date-time and not the chronology.
|
||||
* This allows dates in different calendar systems to be compared based
|
||||
* on the position of the date-time on the local time-line.
|
||||
* The underlying comparison is equivalent to comparing the epoch-day and nano-of-day.
|
||||
*
|
||||
* @return a comparator that compares in time-line order ignoring the chronology
|
||||
* @see #isAfter
|
||||
* @see #isBefore
|
||||
* @see #isEqual
|
||||
*/
|
||||
static Comparator<ChronoLocalDateTime<?>> timeLineOrder() {
|
||||
return AbstractChronology.DATE_TIME_ORDER;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code ChronoLocalDateTime} from a temporal object.
|
||||
* <p>
|
||||
* This obtains a local date-time based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code ChronoLocalDateTime}.
|
||||
* <p>
|
||||
* The conversion extracts and combines the chronology and the date-time
|
||||
* from the temporal object. The behavior is equivalent to using
|
||||
* {@link Chronology#localDateTime(TemporalAccessor)} with the extracted chronology.
|
||||
* Implementations are permitted to perform optimizations such as accessing
|
||||
* those fields that are equivalent to the relevant objects.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code ChronoLocalDateTime::from}.
|
||||
*
|
||||
* @param temporal the temporal object to convert, not null
|
||||
* @return the date-time, not null
|
||||
* @throws DateTimeException if unable to convert to a {@code ChronoLocalDateTime}
|
||||
* @see Chronology#localDateTime(TemporalAccessor)
|
||||
*/
|
||||
static ChronoLocalDateTime<?> from(TemporalAccessor temporal) {
|
||||
if (temporal instanceof ChronoLocalDateTime) {
|
||||
return (ChronoLocalDateTime<?>) temporal;
|
||||
}
|
||||
Objects.requireNonNull(temporal, "temporal");
|
||||
Chronology chrono = temporal.query(TemporalQueries.chronology());
|
||||
if (chrono == null) {
|
||||
throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass());
|
||||
}
|
||||
return chrono.localDateTime(temporal);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the chronology of this date-time.
|
||||
* <p>
|
||||
* The {@code Chronology} represents the calendar system in use.
|
||||
* The era and other fields in {@link ChronoField} are defined by the chronology.
|
||||
*
|
||||
* @return the chronology, not null
|
||||
*/
|
||||
default Chronology getChronology() {
|
||||
return toLocalDate().getChronology();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local date part of this date-time.
|
||||
* <p>
|
||||
* This returns a local date with the same year, month and day
|
||||
* as this date-time.
|
||||
*
|
||||
* @return the date part of this date-time, not null
|
||||
*/
|
||||
D toLocalDate() ;
|
||||
|
||||
/**
|
||||
* Gets the local time part of this date-time.
|
||||
* <p>
|
||||
* This returns a local time with the same hour, minute, second and
|
||||
* nanosecond as this date-time.
|
||||
*
|
||||
* @return the time part of this date-time, not null
|
||||
*/
|
||||
LocalTime toLocalTime();
|
||||
|
||||
/**
|
||||
* Checks if the specified field is supported.
|
||||
* <p>
|
||||
* This checks if the specified field can be queried on this date-time.
|
||||
* If false, then calling the {@link #range(TemporalField) range},
|
||||
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
|
||||
* methods will throw an exception.
|
||||
* <p>
|
||||
* The set of supported fields is defined by the chronology and normally includes
|
||||
* all {@code ChronoField} date and time fields.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the field is supported is determined by the field.
|
||||
*
|
||||
* @param field the field to check, null returns false
|
||||
* @return true if the field can be queried, false if not
|
||||
*/
|
||||
@Override
|
||||
boolean isSupported(TemporalField field);
|
||||
|
||||
/**
|
||||
* Checks if the specified unit is supported.
|
||||
* <p>
|
||||
* This checks if the specified unit can be added to or subtracted from this date-time.
|
||||
* If false, then calling the {@link #plus(long, TemporalUnit)} and
|
||||
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
|
||||
* <p>
|
||||
* The set of supported units is defined by the chronology and normally includes
|
||||
* all {@code ChronoUnit} units except {@code FOREVER}.
|
||||
* <p>
|
||||
* If the unit is not a {@code ChronoUnit}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the unit is supported is determined by the unit.
|
||||
*
|
||||
* @param unit the unit to check, null returns false
|
||||
* @return true if the unit can be added/subtracted, false if not
|
||||
*/
|
||||
@Override
|
||||
default boolean isSupported(TemporalUnit unit) {
|
||||
if (unit instanceof ChronoUnit) {
|
||||
return unit != FOREVER;
|
||||
}
|
||||
return unit != null && unit.isSupportedBy(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// override for covariant return type
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoLocalDateTime<D> with(TemporalAdjuster adjuster) {
|
||||
return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
ChronoLocalDateTime<D> with(TemporalField field, long newValue);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoLocalDateTime<D> plus(TemporalAmount amount) {
|
||||
return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
ChronoLocalDateTime<D> plus(long amountToAdd, TemporalUnit unit);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoLocalDateTime<D> minus(TemporalAmount amount) {
|
||||
return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoLocalDateTime<D> minus(long amountToSubtract, TemporalUnit unit) {
|
||||
return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Queries this date-time using the specified query.
|
||||
* <p>
|
||||
* This queries this date-time using the specified query strategy object.
|
||||
* The {@code TemporalQuery} object defines the logic to be used to
|
||||
* obtain the result. Read the documentation of the query to understand
|
||||
* what the result of this method will be.
|
||||
* <p>
|
||||
* The result of this method is obtained by invoking the
|
||||
* {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
|
||||
* specified query passing {@code this} as the argument.
|
||||
*
|
||||
* @param <R> the type of the result
|
||||
* @param query the query to invoke, not null
|
||||
* @return the query result, null may be returned (defined by the query)
|
||||
* @throws DateTimeException if unable to query (defined by the query)
|
||||
* @throws ArithmeticException if numeric overflow occurs (defined by the query)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
default <R> R query(TemporalQuery<R> query) {
|
||||
if (query == TemporalQueries.zoneId() || query == TemporalQueries.zone() || query == TemporalQueries.offset()) {
|
||||
return null;
|
||||
} else if (query == TemporalQueries.localTime()) {
|
||||
return (R) toLocalTime();
|
||||
} else if (query == TemporalQueries.chronology()) {
|
||||
return (R) getChronology();
|
||||
} else if (query == TemporalQueries.precision()) {
|
||||
return (R) NANOS;
|
||||
}
|
||||
// inline TemporalAccessor.super.query(query) as an optimization
|
||||
// non-JDK classes are not permitted to make this optimization
|
||||
return query.queryFrom(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the specified temporal object to have the same date and time as this object.
|
||||
* <p>
|
||||
* This returns a temporal object of the same observable type as the input
|
||||
* with the date and time changed to be the same as this.
|
||||
* <p>
|
||||
* The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
|
||||
* twice, passing {@link ChronoField#EPOCH_DAY} and
|
||||
* {@link ChronoField#NANO_OF_DAY} as the fields.
|
||||
* <p>
|
||||
* In most cases, it is clearer to reverse the calling pattern by using
|
||||
* {@link Temporal#with(TemporalAdjuster)}:
|
||||
* <pre>
|
||||
* // these two lines are equivalent, but the second approach is recommended
|
||||
* temporal = thisLocalDateTime.adjustInto(temporal);
|
||||
* temporal = temporal.with(thisLocalDateTime);
|
||||
* </pre>
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param temporal the target object to be adjusted, not null
|
||||
* @return the adjusted object, not null
|
||||
* @throws DateTimeException if unable to make the adjustment
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
default Temporal adjustInto(Temporal temporal) {
|
||||
return temporal
|
||||
.with(EPOCH_DAY, toLocalDate().toEpochDay())
|
||||
.with(NANO_OF_DAY, toLocalTime().toNanoOfDay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats this date-time using the specified formatter.
|
||||
* <p>
|
||||
* This date-time will be passed to the formatter to produce a string.
|
||||
* <p>
|
||||
* The default implementation must behave as follows:
|
||||
* <pre>
|
||||
* return formatter.format(this);
|
||||
* </pre>
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted date-time string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
default String format(DateTimeFormatter formatter) {
|
||||
Objects.requireNonNull(formatter, "formatter");
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Combines this time with a time-zone to create a {@code ChronoZonedDateTime}.
|
||||
* <p>
|
||||
* This returns a {@code ChronoZonedDateTime} formed from this date-time at the
|
||||
* specified time-zone. The result will match this date-time as closely as possible.
|
||||
* Time-zone rules, such as daylight savings, mean that not every local date-time
|
||||
* is valid for the specified zone, thus the local date-time may be adjusted.
|
||||
* <p>
|
||||
* The local date-time is resolved to a single instant on the time-line.
|
||||
* This is achieved by finding a valid offset from UTC/Greenwich for the local
|
||||
* date-time as defined by the {@link ZoneRules rules} of the zone ID.
|
||||
*<p>
|
||||
* In most cases, there is only one valid offset for a local date-time.
|
||||
* In the case of an overlap, where clocks are set back, there are two valid offsets.
|
||||
* This method uses the earlier offset typically corresponding to "summer".
|
||||
* <p>
|
||||
* In the case of a gap, where clocks jump forward, there is no valid offset.
|
||||
* Instead, the local date-time is adjusted to be later by the length of the gap.
|
||||
* For a typical one hour daylight savings change, the local date-time will be
|
||||
* moved one hour later into the offset typically corresponding to "summer".
|
||||
* <p>
|
||||
* To obtain the later offset during an overlap, call
|
||||
* {@link ChronoZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method.
|
||||
*
|
||||
* @param zone the time-zone to use, not null
|
||||
* @return the zoned date-time formed from this date-time, not null
|
||||
*/
|
||||
ChronoZonedDateTime<D> atZone(ZoneId zone);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Converts this date-time to an {@code Instant}.
|
||||
* <p>
|
||||
* This combines this local date-time and the specified offset to form
|
||||
* an {@code Instant}.
|
||||
* <p>
|
||||
* This default implementation calculates from the epoch-day of the date and the
|
||||
* second-of-day of the time.
|
||||
*
|
||||
* @param offset the offset to use for the conversion, not null
|
||||
* @return an {@code Instant} representing the same instant, not null
|
||||
*/
|
||||
default Instant toInstant(ZoneOffset offset) {
|
||||
return Instant.ofEpochSecond(toEpochSecond(offset), toLocalTime().getNano());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this date-time to the number of seconds from the epoch
|
||||
* of 1970-01-01T00:00:00Z.
|
||||
* <p>
|
||||
* This combines this local date-time and the specified offset to calculate the
|
||||
* epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
|
||||
* Instants on the time-line after the epoch are positive, earlier are negative.
|
||||
* <p>
|
||||
* This default implementation calculates from the epoch-day of the date and the
|
||||
* second-of-day of the time.
|
||||
*
|
||||
* @param offset the offset to use for the conversion, not null
|
||||
* @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
|
||||
*/
|
||||
default long toEpochSecond(ZoneOffset offset) {
|
||||
Objects.requireNonNull(offset, "offset");
|
||||
long epochDay = toLocalDate().toEpochDay();
|
||||
long secs = epochDay * 86400 + toLocalTime().toSecondOfDay();
|
||||
secs -= offset.getTotalSeconds();
|
||||
return secs;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this date-time to another date-time, including the chronology.
|
||||
* <p>
|
||||
* The comparison is based first on the underlying time-line date-time, then
|
||||
* on the chronology.
|
||||
* It is "consistent with equals", as defined by {@link Comparable}.
|
||||
* <p>
|
||||
* For example, the following is the comparator order:
|
||||
* <ol>
|
||||
* <li>{@code 2012-12-03T12:00 (ISO)}</li>
|
||||
* <li>{@code 2012-12-04T12:00 (ISO)}</li>
|
||||
* <li>{@code 2555-12-04T12:00 (ThaiBuddhist)}</li>
|
||||
* <li>{@code 2012-12-05T12:00 (ISO)}</li>
|
||||
* </ol>
|
||||
* Values #2 and #3 represent the same date-time on the time-line.
|
||||
* When two values represent the same date-time, the chronology ID is compared to distinguish them.
|
||||
* This step is needed to make the ordering "consistent with equals".
|
||||
* <p>
|
||||
* If all the date-time objects being compared are in the same chronology, then the
|
||||
* additional chronology stage is not required and only the local date-time is used.
|
||||
* <p>
|
||||
* This default implementation performs the comparison defined above.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return the comparator value, negative if less, positive if greater
|
||||
*/
|
||||
@Override
|
||||
default int compareTo(ChronoLocalDateTime<?> other) {
|
||||
int cmp = toLocalDate().compareTo(other.toLocalDate());
|
||||
if (cmp == 0) {
|
||||
cmp = toLocalTime().compareTo(other.toLocalTime());
|
||||
if (cmp == 0) {
|
||||
cmp = getChronology().compareTo(other.getChronology());
|
||||
}
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this date-time is after the specified date-time ignoring the chronology.
|
||||
* <p>
|
||||
* This method differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the underlying date-time and not the chronology.
|
||||
* This allows dates in different calendar systems to be compared based
|
||||
* on the time-line position.
|
||||
* <p>
|
||||
* This default implementation performs the comparison based on the epoch-day
|
||||
* and nano-of-day.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return true if this is after the specified date-time
|
||||
*/
|
||||
default boolean isAfter(ChronoLocalDateTime<?> other) {
|
||||
long thisEpDay = this.toLocalDate().toEpochDay();
|
||||
long otherEpDay = other.toLocalDate().toEpochDay();
|
||||
return thisEpDay > otherEpDay ||
|
||||
(thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() > other.toLocalTime().toNanoOfDay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this date-time is before the specified date-time ignoring the chronology.
|
||||
* <p>
|
||||
* This method differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the underlying date-time and not the chronology.
|
||||
* This allows dates in different calendar systems to be compared based
|
||||
* on the time-line position.
|
||||
* <p>
|
||||
* This default implementation performs the comparison based on the epoch-day
|
||||
* and nano-of-day.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return true if this is before the specified date-time
|
||||
*/
|
||||
default boolean isBefore(ChronoLocalDateTime<?> other) {
|
||||
long thisEpDay = this.toLocalDate().toEpochDay();
|
||||
long otherEpDay = other.toLocalDate().toEpochDay();
|
||||
return thisEpDay < otherEpDay ||
|
||||
(thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() < other.toLocalTime().toNanoOfDay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this date-time is equal to the specified date-time ignoring the chronology.
|
||||
* <p>
|
||||
* This method differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the underlying date and time and not the chronology.
|
||||
* This allows date-times in different calendar systems to be compared based
|
||||
* on the time-line position.
|
||||
* <p>
|
||||
* This default implementation performs the comparison based on the epoch-day
|
||||
* and nano-of-day.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return true if the underlying date-time is equal to the specified date-time on the timeline
|
||||
*/
|
||||
default boolean isEqual(ChronoLocalDateTime<?> other) {
|
||||
// Do the time check first, it is cheaper than computing EPOCH day.
|
||||
return this.toLocalTime().toNanoOfDay() == other.toLocalTime().toNanoOfDay() &&
|
||||
this.toLocalDate().toEpochDay() == other.toLocalDate().toEpochDay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this date-time is equal to another date-time, including the chronology.
|
||||
* <p>
|
||||
* Compares this date-time with another ensuring that the date-time and chronology are the same.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other date
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* A hash code for this date-time.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Outputs this date-time as a {@code String}.
|
||||
* <p>
|
||||
* The output will include the full local date-time.
|
||||
*
|
||||
* @return a string representation of this date-time, not null
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
}
|
||||
459
jdkSrc/jdk8/java/time/chrono/ChronoLocalDateTimeImpl.java
Normal file
459
jdkSrc/jdk8/java/time/chrono/ChronoLocalDateTimeImpl.java
Normal file
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.EPOCH_DAY;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date-time without a time-zone for the calendar neutral API.
|
||||
* <p>
|
||||
* {@code ChronoLocalDateTime} is an immutable date-time object that represents a date-time, often
|
||||
* viewed as year-month-day-hour-minute-second. This object can also access other
|
||||
* fields such as day-of-year, day-of-week and week-of-year.
|
||||
* <p>
|
||||
* This class stores all date and time fields, to a precision of nanoseconds.
|
||||
* It does not store or represent a time-zone. For example, the value
|
||||
* "2nd October 2007 at 13:45.30.123456789" can be stored in an {@code ChronoLocalDateTime}.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
* @serial
|
||||
* @param <D> the concrete type for the date of this date-time
|
||||
* @since 1.8
|
||||
*/
|
||||
final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate>
|
||||
implements ChronoLocalDateTime<D>, Temporal, TemporalAdjuster, Serializable {
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = 4556003607393004514L;
|
||||
/**
|
||||
* Hours per day.
|
||||
*/
|
||||
static final int HOURS_PER_DAY = 24;
|
||||
/**
|
||||
* Minutes per hour.
|
||||
*/
|
||||
static final int MINUTES_PER_HOUR = 60;
|
||||
/**
|
||||
* Minutes per day.
|
||||
*/
|
||||
static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
|
||||
/**
|
||||
* Seconds per minute.
|
||||
*/
|
||||
static final int SECONDS_PER_MINUTE = 60;
|
||||
/**
|
||||
* Seconds per hour.
|
||||
*/
|
||||
static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
|
||||
/**
|
||||
* Seconds per day.
|
||||
*/
|
||||
static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
|
||||
/**
|
||||
* Milliseconds per day.
|
||||
*/
|
||||
static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
|
||||
/**
|
||||
* Microseconds per day.
|
||||
*/
|
||||
static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
|
||||
/**
|
||||
* Nanos per second.
|
||||
*/
|
||||
static final long NANOS_PER_SECOND = 1000_000_000L;
|
||||
/**
|
||||
* Nanos per minute.
|
||||
*/
|
||||
static final long NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE;
|
||||
/**
|
||||
* Nanos per hour.
|
||||
*/
|
||||
static final long NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR;
|
||||
/**
|
||||
* Nanos per day.
|
||||
*/
|
||||
static final long NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY;
|
||||
|
||||
/**
|
||||
* The date part.
|
||||
*/
|
||||
private final transient D date;
|
||||
/**
|
||||
* The time part.
|
||||
*/
|
||||
private final transient LocalTime time;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code ChronoLocalDateTime} from a date and time.
|
||||
*
|
||||
* @param date the local date, not null
|
||||
* @param time the local time, not null
|
||||
* @return the local date-time, not null
|
||||
*/
|
||||
static <R extends ChronoLocalDate> ChronoLocalDateTimeImpl<R> of(R date, LocalTime time) {
|
||||
return new ChronoLocalDateTimeImpl<>(date, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts the {@code Temporal} to {@code ChronoLocalDateTime} ensuring it bas the specified chronology.
|
||||
*
|
||||
* @param chrono the chronology to check for, not null
|
||||
* @param temporal a date-time to cast, not null
|
||||
* @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null
|
||||
* @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl
|
||||
* or the chronology is not equal this Chronology
|
||||
*/
|
||||
static <R extends ChronoLocalDate> ChronoLocalDateTimeImpl<R> ensureValid(Chronology chrono, Temporal temporal) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ChronoLocalDateTimeImpl<R> other = (ChronoLocalDateTimeImpl<R>) temporal;
|
||||
if (chrono.equals(other.getChronology()) == false) {
|
||||
throw new ClassCastException("Chronology mismatch, required: " + chrono.getId()
|
||||
+ ", actual: " + other.getChronology().getId());
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param date the date part of the date-time, not null
|
||||
* @param time the time part of the date-time, not null
|
||||
*/
|
||||
private ChronoLocalDateTimeImpl(D date, LocalTime time) {
|
||||
Objects.requireNonNull(date, "date");
|
||||
Objects.requireNonNull(time, "time");
|
||||
this.date = date;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this date-time with the new date and time, checking
|
||||
* to see if a new object is in fact required.
|
||||
*
|
||||
* @param newDate the date of the new date-time, not null
|
||||
* @param newTime the time of the new date-time, not null
|
||||
* @return the date-time, not null
|
||||
*/
|
||||
private ChronoLocalDateTimeImpl<D> with(Temporal newDate, LocalTime newTime) {
|
||||
if (date == newDate && time == newTime) {
|
||||
return this;
|
||||
}
|
||||
// Validate that the new Temporal is a ChronoLocalDate (and not something else)
|
||||
D cd = ChronoLocalDateImpl.ensureValid(date.getChronology(), newDate);
|
||||
return new ChronoLocalDateTimeImpl<>(cd, newTime);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public D toLocalDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTime toLocalTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public boolean isSupported(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
return f.isDateBased() || f.isTimeBased();
|
||||
}
|
||||
return field != null && field.isSupportedBy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueRange range(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
return (f.isTimeBased() ? time.range(field) : date.range(field));
|
||||
}
|
||||
return field.rangeRefinedBy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
return (f.isTimeBased() ? time.get(field) : date.get(field));
|
||||
}
|
||||
return range(field).checkValidIntValue(getLong(field), field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
return (f.isTimeBased() ? time.getLong(field) : date.getLong(field));
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ChronoLocalDateTimeImpl<D> with(TemporalAdjuster adjuster) {
|
||||
if (adjuster instanceof ChronoLocalDate) {
|
||||
// The Chronology is checked in with(date,time)
|
||||
return with((ChronoLocalDate) adjuster, time);
|
||||
} else if (adjuster instanceof LocalTime) {
|
||||
return with(date, (LocalTime) adjuster);
|
||||
} else if (adjuster instanceof ChronoLocalDateTimeImpl) {
|
||||
return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), (ChronoLocalDateTimeImpl<?>) adjuster);
|
||||
}
|
||||
return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), (ChronoLocalDateTimeImpl<?>) adjuster.adjustInto(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronoLocalDateTimeImpl<D> with(TemporalField field, long newValue) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
if (f.isTimeBased()) {
|
||||
return with(date, time.with(field, newValue));
|
||||
} else {
|
||||
return with(date.with(field, newValue), time);
|
||||
}
|
||||
}
|
||||
return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), field.adjustInto(this, newValue));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ChronoLocalDateTimeImpl<D> plus(long amountToAdd, TemporalUnit unit) {
|
||||
if (unit instanceof ChronoUnit) {
|
||||
ChronoUnit f = (ChronoUnit) unit;
|
||||
switch (f) {
|
||||
case NANOS: return plusNanos(amountToAdd);
|
||||
case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
|
||||
case MILLIS: return plusDays(amountToAdd / MILLIS_PER_DAY).plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000000);
|
||||
case SECONDS: return plusSeconds(amountToAdd);
|
||||
case MINUTES: return plusMinutes(amountToAdd);
|
||||
case HOURS: return plusHours(amountToAdd);
|
||||
case HALF_DAYS: return plusDays(amountToAdd / 256).plusHours((amountToAdd % 256) * 12); // no overflow (256 is multiple of 2)
|
||||
}
|
||||
return with(date.plus(amountToAdd, unit), time);
|
||||
}
|
||||
return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), unit.addTo(this, amountToAdd));
|
||||
}
|
||||
|
||||
private ChronoLocalDateTimeImpl<D> plusDays(long days) {
|
||||
return with(date.plus(days, ChronoUnit.DAYS), time);
|
||||
}
|
||||
|
||||
private ChronoLocalDateTimeImpl<D> plusHours(long hours) {
|
||||
return plusWithOverflow(date, hours, 0, 0, 0);
|
||||
}
|
||||
|
||||
private ChronoLocalDateTimeImpl<D> plusMinutes(long minutes) {
|
||||
return plusWithOverflow(date, 0, minutes, 0, 0);
|
||||
}
|
||||
|
||||
ChronoLocalDateTimeImpl<D> plusSeconds(long seconds) {
|
||||
return plusWithOverflow(date, 0, 0, seconds, 0);
|
||||
}
|
||||
|
||||
private ChronoLocalDateTimeImpl<D> plusNanos(long nanos) {
|
||||
return plusWithOverflow(date, 0, 0, 0, nanos);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
private ChronoLocalDateTimeImpl<D> plusWithOverflow(D newDate, long hours, long minutes, long seconds, long nanos) {
|
||||
// 9223372036854775808 long, 2147483648 int
|
||||
if ((hours | minutes | seconds | nanos) == 0) {
|
||||
return with(newDate, time);
|
||||
}
|
||||
long totDays = nanos / NANOS_PER_DAY + // max/24*60*60*1B
|
||||
seconds / SECONDS_PER_DAY + // max/24*60*60
|
||||
minutes / MINUTES_PER_DAY + // max/24*60
|
||||
hours / HOURS_PER_DAY; // max/24
|
||||
long totNanos = nanos % NANOS_PER_DAY + // max 86400000000000
|
||||
(seconds % SECONDS_PER_DAY) * NANOS_PER_SECOND + // max 86400000000000
|
||||
(minutes % MINUTES_PER_DAY) * NANOS_PER_MINUTE + // max 86400000000000
|
||||
(hours % HOURS_PER_DAY) * NANOS_PER_HOUR; // max 86400000000000
|
||||
long curNoD = time.toNanoOfDay(); // max 86400000000000
|
||||
totNanos = totNanos + curNoD; // total 432000000000000
|
||||
totDays += Math.floorDiv(totNanos, NANOS_PER_DAY);
|
||||
long newNoD = Math.floorMod(totNanos, NANOS_PER_DAY);
|
||||
LocalTime newTime = (newNoD == curNoD ? time : LocalTime.ofNanoOfDay(newNoD));
|
||||
return with(newDate.plus(totDays, ChronoUnit.DAYS), newTime);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ChronoZonedDateTime<D> atZone(ZoneId zone) {
|
||||
return ChronoZonedDateTimeImpl.ofBest(this, zone, null);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public long until(Temporal endExclusive, TemporalUnit unit) {
|
||||
Objects.requireNonNull(endExclusive, "endExclusive");
|
||||
@SuppressWarnings("unchecked")
|
||||
ChronoLocalDateTime<D> end = (ChronoLocalDateTime<D>) getChronology().localDateTime(endExclusive);
|
||||
if (unit instanceof ChronoUnit) {
|
||||
if (unit.isTimeBased()) {
|
||||
long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY);
|
||||
switch ((ChronoUnit) unit) {
|
||||
case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break;
|
||||
case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break;
|
||||
case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break;
|
||||
case SECONDS: amount = Math.multiplyExact(amount, SECONDS_PER_DAY); break;
|
||||
case MINUTES: amount = Math.multiplyExact(amount, MINUTES_PER_DAY); break;
|
||||
case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
|
||||
case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
|
||||
}
|
||||
return Math.addExact(amount, time.until(end.toLocalTime(), unit));
|
||||
}
|
||||
ChronoLocalDate endDate = end.toLocalDate();
|
||||
if (end.toLocalTime().isBefore(time)) {
|
||||
endDate = endDate.minus(1, ChronoUnit.DAYS);
|
||||
}
|
||||
return date.until(endDate, unit);
|
||||
}
|
||||
Objects.requireNonNull(unit, "unit");
|
||||
return unit.between(this, end);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the ChronoLocalDateTime using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(2); // identifies a ChronoLocalDateTime
|
||||
* out.writeObject(toLocalDate());
|
||||
* out.witeObject(toLocalTime());
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
private Object writeReplace() {
|
||||
return new Ser(Ser.CHRONO_LOCAL_DATE_TIME_TYPE, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
|
||||
void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeObject(date);
|
||||
out.writeObject(time);
|
||||
}
|
||||
|
||||
static ChronoLocalDateTime<?> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
ChronoLocalDate date = (ChronoLocalDate) in.readObject();
|
||||
LocalTime time = (LocalTime) in.readObject();
|
||||
return date.atTime(time);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof ChronoLocalDateTime) {
|
||||
return compareTo((ChronoLocalDateTime<?>) obj) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toLocalDate().hashCode() ^ toLocalTime().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toLocalDate().toString() + 'T' + toLocalTime().toString();
|
||||
}
|
||||
|
||||
}
|
||||
365
jdkSrc/jdk8/java/time/chrono/ChronoPeriod.java
Normal file
365
jdkSrc/jdk8/java/time/chrono/ChronoPeriod.java
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date-based amount of time, such as '3 years, 4 months and 5 days' in an
|
||||
* arbitrary chronology, intended for advanced globalization use cases.
|
||||
* <p>
|
||||
* This interface models a date-based amount of time in a calendar system.
|
||||
* While most calendar systems use years, months and days, some do not.
|
||||
* Therefore, this interface operates solely in terms of a set of supported
|
||||
* units that are defined by the {@code Chronology}.
|
||||
* The set of supported units is fixed for a given chronology.
|
||||
* The amount of a supported unit may be set to zero.
|
||||
* <p>
|
||||
* The period is modeled as a directed amount of time, meaning that individual
|
||||
* parts of the period may be negative.
|
||||
*
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface ChronoPeriod
|
||||
extends TemporalAmount {
|
||||
|
||||
/**
|
||||
* Obtains a {@code ChronoPeriod} consisting of amount of time between two dates.
|
||||
* <p>
|
||||
* The start date is included, but the end date is not.
|
||||
* The period is calculated using {@link ChronoLocalDate#until(ChronoLocalDate)}.
|
||||
* As such, the calculation is chronology specific.
|
||||
* <p>
|
||||
* The chronology of the first date is used.
|
||||
* The chronology of the second date is ignored, with the date being converted
|
||||
* to the target chronology system before the calculation starts.
|
||||
* <p>
|
||||
* The result of this method can be a negative period if the end is before the start.
|
||||
* In most cases, the positive/negative sign will be the same in each of the supported fields.
|
||||
*
|
||||
* @param startDateInclusive the start date, inclusive, specifying the chronology of the calculation, not null
|
||||
* @param endDateExclusive the end date, exclusive, in any chronology, not null
|
||||
* @return the period between this date and the end date, not null
|
||||
* @see ChronoLocalDate#until(ChronoLocalDate)
|
||||
*/
|
||||
public static ChronoPeriod between(ChronoLocalDate startDateInclusive, ChronoLocalDate endDateExclusive) {
|
||||
Objects.requireNonNull(startDateInclusive, "startDateInclusive");
|
||||
Objects.requireNonNull(endDateExclusive, "endDateExclusive");
|
||||
return startDateInclusive.until(endDateExclusive);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the value of the requested unit.
|
||||
* <p>
|
||||
* The supported units are chronology specific.
|
||||
* They will typically be {@link ChronoUnit#YEARS YEARS},
|
||||
* {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
|
||||
* Requesting an unsupported unit will throw an exception.
|
||||
*
|
||||
* @param unit the {@code TemporalUnit} for which to return the value
|
||||
* @return the long value of the unit
|
||||
* @throws DateTimeException if the unit is not supported
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
*/
|
||||
@Override
|
||||
long get(TemporalUnit unit);
|
||||
|
||||
/**
|
||||
* Gets the set of units supported by this period.
|
||||
* <p>
|
||||
* The supported units are chronology specific.
|
||||
* They will typically be {@link ChronoUnit#YEARS YEARS},
|
||||
* {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
|
||||
* They are returned in order from largest to smallest.
|
||||
* <p>
|
||||
* This set can be used in conjunction with {@link #get(TemporalUnit)}
|
||||
* to access the entire state of the period.
|
||||
*
|
||||
* @return a list containing the supported units, not null
|
||||
*/
|
||||
@Override
|
||||
List<TemporalUnit> getUnits();
|
||||
|
||||
/**
|
||||
* Gets the chronology that defines the meaning of the supported units.
|
||||
* <p>
|
||||
* The period is defined by the chronology.
|
||||
* It controls the supported units and restricts addition/subtraction
|
||||
* to {@code ChronoLocalDate} instances of the same chronology.
|
||||
*
|
||||
* @return the chronology defining the period, not null
|
||||
*/
|
||||
Chronology getChronology();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if all the supported units of this period are zero.
|
||||
*
|
||||
* @return true if this period is zero-length
|
||||
*/
|
||||
default boolean isZero() {
|
||||
for (TemporalUnit unit : getUnits()) {
|
||||
if (get(unit) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any of the supported units of this period are negative.
|
||||
*
|
||||
* @return true if any unit of this period is negative
|
||||
*/
|
||||
default boolean isNegative() {
|
||||
for (TemporalUnit unit : getUnits()) {
|
||||
if (get(unit) < 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a copy of this period with the specified period added.
|
||||
* <p>
|
||||
* If the specified amount is a {@code ChronoPeriod} then it must have
|
||||
* the same chronology as this period. Implementations may choose to
|
||||
* accept or reject other {@code TemporalAmount} implementations.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param amountToAdd the period to add, not null
|
||||
* @return a {@code ChronoPeriod} based on this period with the requested period added, not null
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
ChronoPeriod plus(TemporalAmount amountToAdd);
|
||||
|
||||
/**
|
||||
* Returns a copy of this period with the specified period subtracted.
|
||||
* <p>
|
||||
* If the specified amount is a {@code ChronoPeriod} then it must have
|
||||
* the same chronology as this period. Implementations may choose to
|
||||
* accept or reject other {@code TemporalAmount} implementations.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param amountToSubtract the period to subtract, not null
|
||||
* @return a {@code ChronoPeriod} based on this period with the requested period subtracted, not null
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
ChronoPeriod minus(TemporalAmount amountToSubtract);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a new instance with each amount in this period in this period
|
||||
* multiplied by the specified scalar.
|
||||
* <p>
|
||||
* This returns a period with each supported unit individually multiplied.
|
||||
* For example, a period of "2 years, -3 months and 4 days" multiplied by
|
||||
* 3 will return "6 years, -9 months and 12 days".
|
||||
* No normalization is performed.
|
||||
*
|
||||
* @param scalar the scalar to multiply by, not null
|
||||
* @return a {@code ChronoPeriod} based on this period with the amounts multiplied
|
||||
* by the scalar, not null
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
ChronoPeriod multipliedBy(int scalar);
|
||||
|
||||
/**
|
||||
* Returns a new instance with each amount in this period negated.
|
||||
* <p>
|
||||
* This returns a period with each supported unit individually negated.
|
||||
* For example, a period of "2 years, -3 months and 4 days" will be
|
||||
* negated to "-2 years, 3 months and -4 days".
|
||||
* No normalization is performed.
|
||||
*
|
||||
* @return a {@code ChronoPeriod} based on this period with the amounts negated, not null
|
||||
* @throws ArithmeticException if numeric overflow occurs, which only happens if
|
||||
* one of the units has the value {@code Long.MIN_VALUE}
|
||||
*/
|
||||
default ChronoPeriod negated() {
|
||||
return multipliedBy(-1);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a copy of this period with the amounts of each unit normalized.
|
||||
* <p>
|
||||
* The process of normalization is specific to each calendar system.
|
||||
* For example, in the ISO calendar system, the years and months are
|
||||
* normalized but the days are not, such that "15 months" would be
|
||||
* normalized to "1 year and 3 months".
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @return a {@code ChronoPeriod} based on this period with the amounts of each
|
||||
* unit normalized, not null
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
ChronoPeriod normalized();
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Adds this period to the specified temporal object.
|
||||
* <p>
|
||||
* This returns a temporal object of the same observable type as the input
|
||||
* with this period added.
|
||||
* <p>
|
||||
* In most cases, it is clearer to reverse the calling pattern by using
|
||||
* {@link Temporal#plus(TemporalAmount)}.
|
||||
* <pre>
|
||||
* // these two lines are equivalent, but the second approach is recommended
|
||||
* dateTime = thisPeriod.addTo(dateTime);
|
||||
* dateTime = dateTime.plus(thisPeriod);
|
||||
* </pre>
|
||||
* <p>
|
||||
* The specified temporal must have the same chronology as this period.
|
||||
* This returns a temporal with the non-zero supported units added.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param temporal the temporal object to adjust, not null
|
||||
* @return an object of the same type with the adjustment made, not null
|
||||
* @throws DateTimeException if unable to add
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
Temporal addTo(Temporal temporal);
|
||||
|
||||
/**
|
||||
* Subtracts this period from the specified temporal object.
|
||||
* <p>
|
||||
* This returns a temporal object of the same observable type as the input
|
||||
* with this period subtracted.
|
||||
* <p>
|
||||
* In most cases, it is clearer to reverse the calling pattern by using
|
||||
* {@link Temporal#minus(TemporalAmount)}.
|
||||
* <pre>
|
||||
* // these two lines are equivalent, but the second approach is recommended
|
||||
* dateTime = thisPeriod.subtractFrom(dateTime);
|
||||
* dateTime = dateTime.minus(thisPeriod);
|
||||
* </pre>
|
||||
* <p>
|
||||
* The specified temporal must have the same chronology as this period.
|
||||
* This returns a temporal with the non-zero supported units subtracted.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param temporal the temporal object to adjust, not null
|
||||
* @return an object of the same type with the adjustment made, not null
|
||||
* @throws DateTimeException if unable to subtract
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
Temporal subtractFrom(Temporal temporal);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if this period is equal to another period, including the chronology.
|
||||
* <p>
|
||||
* Compares this period with another ensuring that the type, each amount and
|
||||
* the chronology are the same.
|
||||
* Note that this means that a period of "15 Months" is not equal to a period
|
||||
* of "1 Year and 3 Months".
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other period
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* A hash code for this period.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Outputs this period as a {@code String}.
|
||||
* <p>
|
||||
* The output will include the period amounts and chronology.
|
||||
*
|
||||
* @return a string representation of this period, not null
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
}
|
||||
401
jdkSrc/jdk8/java/time/chrono/ChronoPeriodImpl.java
Normal file
401
jdkSrc/jdk8/java/time/chrono/ChronoPeriodImpl.java
Normal file
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoUnit.DAYS;
|
||||
import static java.time.temporal.ChronoUnit.MONTHS;
|
||||
import static java.time.temporal.ChronoUnit.YEARS;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalQueries;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A period expressed in terms of a standard year-month-day calendar system.
|
||||
* <p>
|
||||
* This class is used by applications seeking to handle dates in non-ISO calendar systems.
|
||||
* For example, the Japanese, Minguo, Thai Buddhist and others.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable nad thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
final class ChronoPeriodImpl
|
||||
implements ChronoPeriod, Serializable {
|
||||
// this class is only used by JDK chronology implementations and makes assumptions based on that fact
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = 57387258289L;
|
||||
|
||||
/**
|
||||
* The set of supported units.
|
||||
*/
|
||||
private static final List<TemporalUnit> SUPPORTED_UNITS =
|
||||
Collections.unmodifiableList(Arrays.<TemporalUnit>asList(YEARS, MONTHS, DAYS));
|
||||
|
||||
/**
|
||||
* The chronology.
|
||||
*/
|
||||
private final Chronology chrono;
|
||||
/**
|
||||
* The number of years.
|
||||
*/
|
||||
final int years;
|
||||
/**
|
||||
* The number of months.
|
||||
*/
|
||||
final int months;
|
||||
/**
|
||||
* The number of days.
|
||||
*/
|
||||
final int days;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*/
|
||||
ChronoPeriodImpl(Chronology chrono, int years, int months, int days) {
|
||||
Objects.requireNonNull(chrono, "chrono");
|
||||
this.chrono = chrono;
|
||||
this.years = years;
|
||||
this.months = months;
|
||||
this.days = days;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public long get(TemporalUnit unit) {
|
||||
if (unit == ChronoUnit.YEARS) {
|
||||
return years;
|
||||
} else if (unit == ChronoUnit.MONTHS) {
|
||||
return months;
|
||||
} else if (unit == ChronoUnit.DAYS) {
|
||||
return days;
|
||||
} else {
|
||||
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TemporalUnit> getUnits() {
|
||||
return ChronoPeriodImpl.SUPPORTED_UNITS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chronology getChronology() {
|
||||
return chrono;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public boolean isZero() {
|
||||
return years == 0 && months == 0 && days == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegative() {
|
||||
return years < 0 || months < 0 || days < 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ChronoPeriod plus(TemporalAmount amountToAdd) {
|
||||
ChronoPeriodImpl amount = validateAmount(amountToAdd);
|
||||
return new ChronoPeriodImpl(
|
||||
chrono,
|
||||
Math.addExact(years, amount.years),
|
||||
Math.addExact(months, amount.months),
|
||||
Math.addExact(days, amount.days));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronoPeriod minus(TemporalAmount amountToSubtract) {
|
||||
ChronoPeriodImpl amount = validateAmount(amountToSubtract);
|
||||
return new ChronoPeriodImpl(
|
||||
chrono,
|
||||
Math.subtractExact(years, amount.years),
|
||||
Math.subtractExact(months, amount.months),
|
||||
Math.subtractExact(days, amount.days));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code ChronoPeriodImpl} from a temporal amount.
|
||||
*
|
||||
* @param amount the temporal amount to convert, not null
|
||||
* @return the period, not null
|
||||
*/
|
||||
private ChronoPeriodImpl validateAmount(TemporalAmount amount) {
|
||||
Objects.requireNonNull(amount, "amount");
|
||||
if (amount instanceof ChronoPeriodImpl == false) {
|
||||
throw new DateTimeException("Unable to obtain ChronoPeriod from TemporalAmount: " + amount.getClass());
|
||||
}
|
||||
ChronoPeriodImpl period = (ChronoPeriodImpl) amount;
|
||||
if (chrono.equals(period.getChronology()) == false) {
|
||||
throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + period.getChronology().getId());
|
||||
}
|
||||
return period;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ChronoPeriod multipliedBy(int scalar) {
|
||||
if (this.isZero() || scalar == 1) {
|
||||
return this;
|
||||
}
|
||||
return new ChronoPeriodImpl(
|
||||
chrono,
|
||||
Math.multiplyExact(years, scalar),
|
||||
Math.multiplyExact(months, scalar),
|
||||
Math.multiplyExact(days, scalar));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ChronoPeriod normalized() {
|
||||
long monthRange = monthRange();
|
||||
if (monthRange > 0) {
|
||||
long totalMonths = years * monthRange + months;
|
||||
long splitYears = totalMonths / monthRange;
|
||||
int splitMonths = (int) (totalMonths % monthRange); // no overflow
|
||||
if (splitYears == years && splitMonths == months) {
|
||||
return this;
|
||||
}
|
||||
return new ChronoPeriodImpl(chrono, Math.toIntExact(splitYears), splitMonths, days);
|
||||
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the range of months.
|
||||
*
|
||||
* @return the month range, -1 if not fixed range
|
||||
*/
|
||||
private long monthRange() {
|
||||
ValueRange startRange = chrono.range(MONTH_OF_YEAR);
|
||||
if (startRange.isFixed() && startRange.isIntValue()) {
|
||||
return startRange.getMaximum() - startRange.getMinimum() + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@Override
|
||||
public Temporal addTo(Temporal temporal) {
|
||||
validateChrono(temporal);
|
||||
if (months == 0) {
|
||||
if (years != 0) {
|
||||
temporal = temporal.plus(years, YEARS);
|
||||
}
|
||||
} else {
|
||||
long monthRange = monthRange();
|
||||
if (monthRange > 0) {
|
||||
temporal = temporal.plus(years * monthRange + months, MONTHS);
|
||||
} else {
|
||||
if (years != 0) {
|
||||
temporal = temporal.plus(years, YEARS);
|
||||
}
|
||||
temporal = temporal.plus(months, MONTHS);
|
||||
}
|
||||
}
|
||||
if (days != 0) {
|
||||
temporal = temporal.plus(days, DAYS);
|
||||
}
|
||||
return temporal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Temporal subtractFrom(Temporal temporal) {
|
||||
validateChrono(temporal);
|
||||
if (months == 0) {
|
||||
if (years != 0) {
|
||||
temporal = temporal.minus(years, YEARS);
|
||||
}
|
||||
} else {
|
||||
long monthRange = monthRange();
|
||||
if (monthRange > 0) {
|
||||
temporal = temporal.minus(years * monthRange + months, MONTHS);
|
||||
} else {
|
||||
if (years != 0) {
|
||||
temporal = temporal.minus(years, YEARS);
|
||||
}
|
||||
temporal = temporal.minus(months, MONTHS);
|
||||
}
|
||||
}
|
||||
if (days != 0) {
|
||||
temporal = temporal.minus(days, DAYS);
|
||||
}
|
||||
return temporal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the temporal has the correct chronology.
|
||||
*/
|
||||
private void validateChrono(TemporalAccessor temporal) {
|
||||
Objects.requireNonNull(temporal, "temporal");
|
||||
Chronology temporalChrono = temporal.query(TemporalQueries.chronology());
|
||||
if (temporalChrono != null && chrono.equals(temporalChrono) == false) {
|
||||
throw new DateTimeException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + temporalChrono.getId());
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof ChronoPeriodImpl) {
|
||||
ChronoPeriodImpl other = (ChronoPeriodImpl) obj;
|
||||
return years == other.years && months == other.months &&
|
||||
days == other.days && chrono.equals(other.chrono);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (years + Integer.rotateLeft(months, 8) + Integer.rotateLeft(days, 16)) ^ chrono.hashCode();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isZero()) {
|
||||
return getChronology().toString() + " P0D";
|
||||
} else {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(getChronology().toString()).append(' ').append('P');
|
||||
if (years != 0) {
|
||||
buf.append(years).append('Y');
|
||||
}
|
||||
if (months != 0) {
|
||||
buf.append(months).append('M');
|
||||
}
|
||||
if (days != 0) {
|
||||
buf.append(days).append('D');
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the Chronology using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* <pre>
|
||||
* out.writeByte(12); // identifies this as a ChronoPeriodImpl
|
||||
* out.writeUTF(getId()); // the chronology
|
||||
* out.writeInt(years);
|
||||
* out.writeInt(months);
|
||||
* out.writeInt(days);
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
protected Object writeReplace() {
|
||||
return new Ser(Ser.CHRONO_PERIOD_TYPE, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws ObjectStreamException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
|
||||
void writeExternal(DataOutput out) throws IOException {
|
||||
out.writeUTF(chrono.getId());
|
||||
out.writeInt(years);
|
||||
out.writeInt(months);
|
||||
out.writeInt(days);
|
||||
}
|
||||
|
||||
static ChronoPeriodImpl readExternal(DataInput in) throws IOException {
|
||||
Chronology chrono = Chronology.of(in.readUTF());
|
||||
int years = in.readInt();
|
||||
int months = in.readInt();
|
||||
int days = in.readInt();
|
||||
return new ChronoPeriodImpl(chrono, years, months, days);
|
||||
}
|
||||
|
||||
}
|
||||
677
jdkSrc/jdk8/java/time/chrono/ChronoZonedDateTime.java
Normal file
677
jdkSrc/jdk8/java/time/chrono/ChronoZonedDateTime.java
Normal file
@@ -0,0 +1,677 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.INSTANT_SECONDS;
|
||||
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
|
||||
import static java.time.temporal.ChronoUnit.FOREVER;
|
||||
import static java.time.temporal.ChronoUnit.NANOS;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQueries;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date-time with a time-zone in an arbitrary chronology,
|
||||
* intended for advanced globalization use cases.
|
||||
* <p>
|
||||
* <b>Most applications should declare method signatures, fields and variables
|
||||
* as {@link ZonedDateTime}, not this interface.</b>
|
||||
* <p>
|
||||
* A {@code ChronoZonedDateTime} is the abstract representation of an offset date-time
|
||||
* where the {@code Chronology chronology}, or calendar system, is pluggable.
|
||||
* The date-time is defined in terms of fields expressed by {@link TemporalField},
|
||||
* where most common implementations are defined in {@link ChronoField}.
|
||||
* The chronology defines how the calendar system operates and the meaning of
|
||||
* the standard fields.
|
||||
*
|
||||
* <h3>When to use this interface</h3>
|
||||
* The design of the API encourages the use of {@code ZonedDateTime} rather than this
|
||||
* interface, even in the case where the application needs to deal with multiple
|
||||
* calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}.
|
||||
* <p>
|
||||
* Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
|
||||
* before using this interface.
|
||||
*
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
*
|
||||
* @param <D> the concrete type for the date of this date-time
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface ChronoZonedDateTime<D extends ChronoLocalDate>
|
||||
extends Temporal, Comparable<ChronoZonedDateTime<?>> {
|
||||
|
||||
/**
|
||||
* Gets a comparator that compares {@code ChronoZonedDateTime} in
|
||||
* time-line order ignoring the chronology.
|
||||
* <p>
|
||||
* This comparator differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the underlying instant and not the chronology.
|
||||
* This allows dates in different calendar systems to be compared based
|
||||
* on the position of the date-time on the instant time-line.
|
||||
* The underlying comparison is equivalent to comparing the epoch-second and nano-of-second.
|
||||
*
|
||||
* @return a comparator that compares in time-line order ignoring the chronology
|
||||
* @see #isAfter
|
||||
* @see #isBefore
|
||||
* @see #isEqual
|
||||
*/
|
||||
static Comparator<ChronoZonedDateTime<?>> timeLineOrder() {
|
||||
return AbstractChronology.INSTANT_ORDER;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code ChronoZonedDateTime} from a temporal object.
|
||||
* <p>
|
||||
* This creates a zoned date-time based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code ChronoZonedDateTime}.
|
||||
* <p>
|
||||
* The conversion extracts and combines the chronology, date, time and zone
|
||||
* from the temporal object. The behavior is equivalent to using
|
||||
* {@link Chronology#zonedDateTime(TemporalAccessor)} with the extracted chronology.
|
||||
* Implementations are permitted to perform optimizations such as accessing
|
||||
* those fields that are equivalent to the relevant objects.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code ChronoZonedDateTime::from}.
|
||||
*
|
||||
* @param temporal the temporal object to convert, not null
|
||||
* @return the date-time, not null
|
||||
* @throws DateTimeException if unable to convert to a {@code ChronoZonedDateTime}
|
||||
* @see Chronology#zonedDateTime(TemporalAccessor)
|
||||
*/
|
||||
static ChronoZonedDateTime<?> from(TemporalAccessor temporal) {
|
||||
if (temporal instanceof ChronoZonedDateTime) {
|
||||
return (ChronoZonedDateTime<?>) temporal;
|
||||
}
|
||||
Objects.requireNonNull(temporal, "temporal");
|
||||
Chronology chrono = temporal.query(TemporalQueries.chronology());
|
||||
if (chrono == null) {
|
||||
throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass());
|
||||
}
|
||||
return chrono.zonedDateTime(temporal);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
default ValueRange range(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {
|
||||
return field.range();
|
||||
}
|
||||
return toLocalDateTime().range(field);
|
||||
}
|
||||
return field.rangeRefinedBy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int get(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
switch ((ChronoField) field) {
|
||||
case INSTANT_SECONDS:
|
||||
throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead");
|
||||
case OFFSET_SECONDS:
|
||||
return getOffset().getTotalSeconds();
|
||||
}
|
||||
return toLocalDateTime().get(field);
|
||||
}
|
||||
return Temporal.super.get(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
default long getLong(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
switch ((ChronoField) field) {
|
||||
case INSTANT_SECONDS: return toEpochSecond();
|
||||
case OFFSET_SECONDS: return getOffset().getTotalSeconds();
|
||||
}
|
||||
return toLocalDateTime().getLong(field);
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local date part of this date-time.
|
||||
* <p>
|
||||
* This returns a local date with the same year, month and day
|
||||
* as this date-time.
|
||||
*
|
||||
* @return the date part of this date-time, not null
|
||||
*/
|
||||
default D toLocalDate() {
|
||||
return toLocalDateTime().toLocalDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local time part of this date-time.
|
||||
* <p>
|
||||
* This returns a local time with the same hour, minute, second and
|
||||
* nanosecond as this date-time.
|
||||
*
|
||||
* @return the time part of this date-time, not null
|
||||
*/
|
||||
default LocalTime toLocalTime() {
|
||||
return toLocalDateTime().toLocalTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local date-time part of this date-time.
|
||||
* <p>
|
||||
* This returns a local date with the same year, month and day
|
||||
* as this date-time.
|
||||
*
|
||||
* @return the local date-time part of this date-time, not null
|
||||
*/
|
||||
ChronoLocalDateTime<D> toLocalDateTime();
|
||||
|
||||
/**
|
||||
* Gets the chronology of this date-time.
|
||||
* <p>
|
||||
* The {@code Chronology} represents the calendar system in use.
|
||||
* The era and other fields in {@link ChronoField} are defined by the chronology.
|
||||
*
|
||||
* @return the chronology, not null
|
||||
*/
|
||||
default Chronology getChronology() {
|
||||
return toLocalDate().getChronology();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the zone offset, such as '+01:00'.
|
||||
* <p>
|
||||
* This is the offset of the local date-time from UTC/Greenwich.
|
||||
*
|
||||
* @return the zone offset, not null
|
||||
*/
|
||||
ZoneOffset getOffset();
|
||||
|
||||
/**
|
||||
* Gets the zone ID, such as 'Europe/Paris'.
|
||||
* <p>
|
||||
* This returns the stored time-zone id used to determine the time-zone rules.
|
||||
*
|
||||
* @return the zone ID, not null
|
||||
*/
|
||||
ZoneId getZone();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a copy of this date-time changing the zone offset to the
|
||||
* earlier of the two valid offsets at a local time-line overlap.
|
||||
* <p>
|
||||
* This method only has any effect when the local time-line overlaps, such as
|
||||
* at an autumn daylight savings cutover. In this scenario, there are two
|
||||
* valid offsets for the local date-time. Calling this method will return
|
||||
* a zoned date-time with the earlier of the two selected.
|
||||
* <p>
|
||||
* If this method is called when it is not an overlap, {@code this}
|
||||
* is returned.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @return a {@code ChronoZonedDateTime} based on this date-time with the earlier offset, not null
|
||||
* @throws DateTimeException if no rules can be found for the zone
|
||||
* @throws DateTimeException if no rules are valid for this date-time
|
||||
*/
|
||||
ChronoZonedDateTime<D> withEarlierOffsetAtOverlap();
|
||||
|
||||
/**
|
||||
* Returns a copy of this date-time changing the zone offset to the
|
||||
* later of the two valid offsets at a local time-line overlap.
|
||||
* <p>
|
||||
* This method only has any effect when the local time-line overlaps, such as
|
||||
* at an autumn daylight savings cutover. In this scenario, there are two
|
||||
* valid offsets for the local date-time. Calling this method will return
|
||||
* a zoned date-time with the later of the two selected.
|
||||
* <p>
|
||||
* If this method is called when it is not an overlap, {@code this}
|
||||
* is returned.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @return a {@code ChronoZonedDateTime} based on this date-time with the later offset, not null
|
||||
* @throws DateTimeException if no rules can be found for the zone
|
||||
* @throws DateTimeException if no rules are valid for this date-time
|
||||
*/
|
||||
ChronoZonedDateTime<D> withLaterOffsetAtOverlap();
|
||||
|
||||
/**
|
||||
* Returns a copy of this date-time with a different time-zone,
|
||||
* retaining the local date-time if possible.
|
||||
* <p>
|
||||
* This method changes the time-zone and retains the local date-time.
|
||||
* The local date-time is only changed if it is invalid for the new zone.
|
||||
* <p>
|
||||
* To change the zone and adjust the local date-time,
|
||||
* use {@link #withZoneSameInstant(ZoneId)}.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param zone the time-zone to change to, not null
|
||||
* @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null
|
||||
*/
|
||||
ChronoZonedDateTime<D> withZoneSameLocal(ZoneId zone);
|
||||
|
||||
/**
|
||||
* Returns a copy of this date-time with a different time-zone,
|
||||
* retaining the instant.
|
||||
* <p>
|
||||
* This method changes the time-zone and retains the instant.
|
||||
* This normally results in a change to the local date-time.
|
||||
* <p>
|
||||
* This method is based on retaining the same instant, thus gaps and overlaps
|
||||
* in the local time-line have no effect on the result.
|
||||
* <p>
|
||||
* To change the offset while keeping the local time,
|
||||
* use {@link #withZoneSameLocal(ZoneId)}.
|
||||
*
|
||||
* @param zone the time-zone to change to, not null
|
||||
* @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null
|
||||
* @throws DateTimeException if the result exceeds the supported date range
|
||||
*/
|
||||
ChronoZonedDateTime<D> withZoneSameInstant(ZoneId zone);
|
||||
|
||||
/**
|
||||
* Checks if the specified field is supported.
|
||||
* <p>
|
||||
* This checks if the specified field can be queried on this date-time.
|
||||
* If false, then calling the {@link #range(TemporalField) range},
|
||||
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
|
||||
* methods will throw an exception.
|
||||
* <p>
|
||||
* The set of supported fields is defined by the chronology and normally includes
|
||||
* all {@code ChronoField} fields.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the field is supported is determined by the field.
|
||||
*
|
||||
* @param field the field to check, null returns false
|
||||
* @return true if the field can be queried, false if not
|
||||
*/
|
||||
@Override
|
||||
boolean isSupported(TemporalField field);
|
||||
|
||||
/**
|
||||
* Checks if the specified unit is supported.
|
||||
* <p>
|
||||
* This checks if the specified unit can be added to or subtracted from this date-time.
|
||||
* If false, then calling the {@link #plus(long, TemporalUnit)} and
|
||||
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
|
||||
* <p>
|
||||
* The set of supported units is defined by the chronology and normally includes
|
||||
* all {@code ChronoUnit} units except {@code FOREVER}.
|
||||
* <p>
|
||||
* If the unit is not a {@code ChronoUnit}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the unit is supported is determined by the unit.
|
||||
*
|
||||
* @param unit the unit to check, null returns false
|
||||
* @return true if the unit can be added/subtracted, false if not
|
||||
*/
|
||||
@Override
|
||||
default boolean isSupported(TemporalUnit unit) {
|
||||
if (unit instanceof ChronoUnit) {
|
||||
return unit != FOREVER;
|
||||
}
|
||||
return unit != null && unit.isSupportedBy(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// override for covariant return type
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoZonedDateTime<D> with(TemporalAdjuster adjuster) {
|
||||
return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
ChronoZonedDateTime<D> with(TemporalField field, long newValue);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoZonedDateTime<D> plus(TemporalAmount amount) {
|
||||
return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
ChronoZonedDateTime<D> plus(long amountToAdd, TemporalUnit unit);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoZonedDateTime<D> minus(TemporalAmount amount) {
|
||||
return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default ChronoZonedDateTime<D> minus(long amountToSubtract, TemporalUnit unit) {
|
||||
return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Queries this date-time using the specified query.
|
||||
* <p>
|
||||
* This queries this date-time using the specified query strategy object.
|
||||
* The {@code TemporalQuery} object defines the logic to be used to
|
||||
* obtain the result. Read the documentation of the query to understand
|
||||
* what the result of this method will be.
|
||||
* <p>
|
||||
* The result of this method is obtained by invoking the
|
||||
* {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
|
||||
* specified query passing {@code this} as the argument.
|
||||
*
|
||||
* @param <R> the type of the result
|
||||
* @param query the query to invoke, not null
|
||||
* @return the query result, null may be returned (defined by the query)
|
||||
* @throws DateTimeException if unable to query (defined by the query)
|
||||
* @throws ArithmeticException if numeric overflow occurs (defined by the query)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
default <R> R query(TemporalQuery<R> query) {
|
||||
if (query == TemporalQueries.zone() || query == TemporalQueries.zoneId()) {
|
||||
return (R) getZone();
|
||||
} else if (query == TemporalQueries.offset()) {
|
||||
return (R) getOffset();
|
||||
} else if (query == TemporalQueries.localTime()) {
|
||||
return (R) toLocalTime();
|
||||
} else if (query == TemporalQueries.chronology()) {
|
||||
return (R) getChronology();
|
||||
} else if (query == TemporalQueries.precision()) {
|
||||
return (R) NANOS;
|
||||
}
|
||||
// inline TemporalAccessor.super.query(query) as an optimization
|
||||
// non-JDK classes are not permitted to make this optimization
|
||||
return query.queryFrom(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats this date-time using the specified formatter.
|
||||
* <p>
|
||||
* This date-time will be passed to the formatter to produce a string.
|
||||
* <p>
|
||||
* The default implementation must behave as follows:
|
||||
* <pre>
|
||||
* return formatter.format(this);
|
||||
* </pre>
|
||||
*
|
||||
* @param formatter the formatter to use, not null
|
||||
* @return the formatted date-time string, not null
|
||||
* @throws DateTimeException if an error occurs during printing
|
||||
*/
|
||||
default String format(DateTimeFormatter formatter) {
|
||||
Objects.requireNonNull(formatter, "formatter");
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Converts this date-time to an {@code Instant}.
|
||||
* <p>
|
||||
* This returns an {@code Instant} representing the same point on the
|
||||
* time-line as this date-time. The calculation combines the
|
||||
* {@linkplain #toLocalDateTime() local date-time} and
|
||||
* {@linkplain #getOffset() offset}.
|
||||
*
|
||||
* @return an {@code Instant} representing the same instant, not null
|
||||
*/
|
||||
default Instant toInstant() {
|
||||
return Instant.ofEpochSecond(toEpochSecond(), toLocalTime().getNano());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this date-time to the number of seconds from the epoch
|
||||
* of 1970-01-01T00:00:00Z.
|
||||
* <p>
|
||||
* This uses the {@linkplain #toLocalDateTime() local date-time} and
|
||||
* {@linkplain #getOffset() offset} to calculate the epoch-second value,
|
||||
* which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
|
||||
* Instants on the time-line after the epoch are positive, earlier are negative.
|
||||
*
|
||||
* @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
|
||||
*/
|
||||
default long toEpochSecond() {
|
||||
long epochDay = toLocalDate().toEpochDay();
|
||||
long secs = epochDay * 86400 + toLocalTime().toSecondOfDay();
|
||||
secs -= getOffset().getTotalSeconds();
|
||||
return secs;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this date-time to another date-time, including the chronology.
|
||||
* <p>
|
||||
* The comparison is based first on the instant, then on the local date-time,
|
||||
* then on the zone ID, then on the chronology.
|
||||
* It is "consistent with equals", as defined by {@link Comparable}.
|
||||
* <p>
|
||||
* If all the date-time objects being compared are in the same chronology, then the
|
||||
* additional chronology stage is not required.
|
||||
* <p>
|
||||
* This default implementation performs the comparison defined above.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return the comparator value, negative if less, positive if greater
|
||||
*/
|
||||
@Override
|
||||
default int compareTo(ChronoZonedDateTime<?> other) {
|
||||
int cmp = Long.compare(toEpochSecond(), other.toEpochSecond());
|
||||
if (cmp == 0) {
|
||||
cmp = toLocalTime().getNano() - other.toLocalTime().getNano();
|
||||
if (cmp == 0) {
|
||||
cmp = toLocalDateTime().compareTo(other.toLocalDateTime());
|
||||
if (cmp == 0) {
|
||||
cmp = getZone().getId().compareTo(other.getZone().getId());
|
||||
if (cmp == 0) {
|
||||
cmp = getChronology().compareTo(other.getChronology());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the instant of this date-time is before that of the specified date-time.
|
||||
* <p>
|
||||
* This method differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the instant of the date-time. This is equivalent to using
|
||||
* {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}.
|
||||
* <p>
|
||||
* This default implementation performs the comparison based on the epoch-second
|
||||
* and nano-of-second.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return true if this point is before the specified date-time
|
||||
*/
|
||||
default boolean isBefore(ChronoZonedDateTime<?> other) {
|
||||
long thisEpochSec = toEpochSecond();
|
||||
long otherEpochSec = other.toEpochSecond();
|
||||
return thisEpochSec < otherEpochSec ||
|
||||
(thisEpochSec == otherEpochSec && toLocalTime().getNano() < other.toLocalTime().getNano());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the instant of this date-time is after that of the specified date-time.
|
||||
* <p>
|
||||
* This method differs from the comparison in {@link #compareTo} in that it
|
||||
* only compares the instant of the date-time. This is equivalent to using
|
||||
* {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}.
|
||||
* <p>
|
||||
* This default implementation performs the comparison based on the epoch-second
|
||||
* and nano-of-second.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return true if this is after the specified date-time
|
||||
*/
|
||||
default boolean isAfter(ChronoZonedDateTime<?> other) {
|
||||
long thisEpochSec = toEpochSecond();
|
||||
long otherEpochSec = other.toEpochSecond();
|
||||
return thisEpochSec > otherEpochSec ||
|
||||
(thisEpochSec == otherEpochSec && toLocalTime().getNano() > other.toLocalTime().getNano());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the instant of this date-time is equal to that of the specified date-time.
|
||||
* <p>
|
||||
* This method differs from the comparison in {@link #compareTo} and {@link #equals}
|
||||
* in that it only compares the instant of the date-time. This is equivalent to using
|
||||
* {@code dateTime1.toInstant().equals(dateTime2.toInstant());}.
|
||||
* <p>
|
||||
* This default implementation performs the comparison based on the epoch-second
|
||||
* and nano-of-second.
|
||||
*
|
||||
* @param other the other date-time to compare to, not null
|
||||
* @return true if the instant equals the instant of the specified date-time
|
||||
*/
|
||||
default boolean isEqual(ChronoZonedDateTime<?> other) {
|
||||
return toEpochSecond() == other.toEpochSecond() &&
|
||||
toLocalTime().getNano() == other.toLocalTime().getNano();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if this date-time is equal to another date-time.
|
||||
* <p>
|
||||
* The comparison is based on the offset date-time and the zone.
|
||||
* To compare for the same instant on the time-line, use {@link #compareTo}.
|
||||
* Only objects of type {@code ChronoZonedDateTime} are compared, other types return false.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other date-time
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* A hash code for this date-time.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Outputs this date-time as a {@code String}.
|
||||
* <p>
|
||||
* The output will include the full zoned date-time.
|
||||
*
|
||||
* @return a string representation of this date-time, not null
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
}
|
||||
391
jdkSrc/jdk8/java/time/chrono/ChronoZonedDateTimeImpl.java
Normal file
391
jdkSrc/jdk8/java/time/chrono/ChronoZonedDateTimeImpl.java
Normal file
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoUnit.SECONDS;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.zone.ZoneOffsetTransition;
|
||||
import java.time.zone.ZoneRules;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date-time with a time-zone in the calendar neutral API.
|
||||
* <p>
|
||||
* {@code ZoneChronoDateTime} is an immutable representation of a date-time with a time-zone.
|
||||
* This class stores all date and time fields, to a precision of nanoseconds,
|
||||
* as well as a time-zone and zone offset.
|
||||
* <p>
|
||||
* The purpose of storing the time-zone is to distinguish the ambiguous case where
|
||||
* the local time-line overlaps, typically as a result of the end of daylight time.
|
||||
* Information about the local-time can be obtained using methods on the time-zone.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @serial Document the delegation of this class in the serialized-form specification.
|
||||
* @param <D> the concrete type for the date of this date-time
|
||||
* @since 1.8
|
||||
*/
|
||||
final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate>
|
||||
implements ChronoZonedDateTime<D>, Serializable {
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = -5261813987200935591L;
|
||||
|
||||
/**
|
||||
* The local date-time.
|
||||
*/
|
||||
private final transient ChronoLocalDateTimeImpl<D> dateTime;
|
||||
/**
|
||||
* The zone offset.
|
||||
*/
|
||||
private final transient ZoneOffset offset;
|
||||
/**
|
||||
* The zone ID.
|
||||
*/
|
||||
private final transient ZoneId zone;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance from a local date-time using the preferred offset if possible.
|
||||
*
|
||||
* @param localDateTime the local date-time, not null
|
||||
* @param zone the zone identifier, not null
|
||||
* @param preferredOffset the zone offset, null if no preference
|
||||
* @return the zoned date-time, not null
|
||||
*/
|
||||
static <R extends ChronoLocalDate> ChronoZonedDateTime<R> ofBest(
|
||||
ChronoLocalDateTimeImpl<R> localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
|
||||
Objects.requireNonNull(localDateTime, "localDateTime");
|
||||
Objects.requireNonNull(zone, "zone");
|
||||
if (zone instanceof ZoneOffset) {
|
||||
return new ChronoZonedDateTimeImpl<>(localDateTime, (ZoneOffset) zone, zone);
|
||||
}
|
||||
ZoneRules rules = zone.getRules();
|
||||
LocalDateTime isoLDT = LocalDateTime.from(localDateTime);
|
||||
List<ZoneOffset> validOffsets = rules.getValidOffsets(isoLDT);
|
||||
ZoneOffset offset;
|
||||
if (validOffsets.size() == 1) {
|
||||
offset = validOffsets.get(0);
|
||||
} else if (validOffsets.size() == 0) {
|
||||
ZoneOffsetTransition trans = rules.getTransition(isoLDT);
|
||||
localDateTime = localDateTime.plusSeconds(trans.getDuration().getSeconds());
|
||||
offset = trans.getOffsetAfter();
|
||||
} else {
|
||||
if (preferredOffset != null && validOffsets.contains(preferredOffset)) {
|
||||
offset = preferredOffset;
|
||||
} else {
|
||||
offset = validOffsets.get(0);
|
||||
}
|
||||
}
|
||||
Objects.requireNonNull(offset, "offset"); // protect against bad ZoneRules
|
||||
return new ChronoZonedDateTimeImpl<>(localDateTime, offset, zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance from an instant using the specified time-zone.
|
||||
*
|
||||
* @param chrono the chronology, not null
|
||||
* @param instant the instant, not null
|
||||
* @param zone the zone identifier, not null
|
||||
* @return the zoned date-time, not null
|
||||
*/
|
||||
static ChronoZonedDateTimeImpl<?> ofInstant(Chronology chrono, Instant instant, ZoneId zone) {
|
||||
ZoneRules rules = zone.getRules();
|
||||
ZoneOffset offset = rules.getOffset(instant);
|
||||
Objects.requireNonNull(offset, "offset"); // protect against bad ZoneRules
|
||||
LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
|
||||
ChronoLocalDateTimeImpl<?> cldt = (ChronoLocalDateTimeImpl<?>)chrono.localDateTime(ldt);
|
||||
return new ChronoZonedDateTimeImpl<>(cldt, offset, zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance from an {@code Instant}.
|
||||
*
|
||||
* @param instant the instant to create the date-time from, not null
|
||||
* @param zone the time-zone to use, validated not null
|
||||
* @return the zoned date-time, validated not null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private ChronoZonedDateTimeImpl<D> create(Instant instant, ZoneId zone) {
|
||||
return (ChronoZonedDateTimeImpl<D>)ofInstant(getChronology(), instant, zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} ensuring it bas the specified chronology.
|
||||
*
|
||||
* @param chrono the chronology to check for, not null
|
||||
* @param temporal a date-time to cast, not null
|
||||
* @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null
|
||||
* @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl
|
||||
* or the chronology is not equal this Chronology
|
||||
*/
|
||||
static <R extends ChronoLocalDate> ChronoZonedDateTimeImpl<R> ensureValid(Chronology chrono, Temporal temporal) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ChronoZonedDateTimeImpl<R> other = (ChronoZonedDateTimeImpl<R>) temporal;
|
||||
if (chrono.equals(other.getChronology()) == false) {
|
||||
throw new ClassCastException("Chronology mismatch, required: " + chrono.getId()
|
||||
+ ", actual: " + other.getChronology().getId());
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param dateTime the date-time, not null
|
||||
* @param offset the zone offset, not null
|
||||
* @param zone the zone ID, not null
|
||||
*/
|
||||
private ChronoZonedDateTimeImpl(ChronoLocalDateTimeImpl<D> dateTime, ZoneOffset offset, ZoneId zone) {
|
||||
this.dateTime = Objects.requireNonNull(dateTime, "dateTime");
|
||||
this.offset = Objects.requireNonNull(offset, "offset");
|
||||
this.zone = Objects.requireNonNull(zone, "zone");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ZoneOffset getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronoZonedDateTime<D> withEarlierOffsetAtOverlap() {
|
||||
ZoneOffsetTransition trans = getZone().getRules().getTransition(LocalDateTime.from(this));
|
||||
if (trans != null && trans.isOverlap()) {
|
||||
ZoneOffset earlierOffset = trans.getOffsetBefore();
|
||||
if (earlierOffset.equals(offset) == false) {
|
||||
return new ChronoZonedDateTimeImpl<>(dateTime, earlierOffset, zone);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronoZonedDateTime<D> withLaterOffsetAtOverlap() {
|
||||
ZoneOffsetTransition trans = getZone().getRules().getTransition(LocalDateTime.from(this));
|
||||
if (trans != null) {
|
||||
ZoneOffset offset = trans.getOffsetAfter();
|
||||
if (offset.equals(getOffset()) == false) {
|
||||
return new ChronoZonedDateTimeImpl<>(dateTime, offset, zone);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ChronoLocalDateTime<D> toLocalDateTime() {
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZoneId getZone() {
|
||||
return zone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronoZonedDateTime<D> withZoneSameLocal(ZoneId zone) {
|
||||
return ofBest(dateTime, zone, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronoZonedDateTime<D> withZoneSameInstant(ZoneId zone) {
|
||||
Objects.requireNonNull(zone, "zone");
|
||||
return this.zone.equals(zone) ? this : create(dateTime.toInstant(offset), zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public boolean isSupported(TemporalField field) {
|
||||
return field instanceof ChronoField || (field != null && field.isSupportedBy(this));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ChronoZonedDateTime<D> with(TemporalField field, long newValue) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
switch (f) {
|
||||
case INSTANT_SECONDS: return plus(newValue - toEpochSecond(), SECONDS);
|
||||
case OFFSET_SECONDS: {
|
||||
ZoneOffset offset = ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue));
|
||||
return create(dateTime.toInstant(offset), zone);
|
||||
}
|
||||
}
|
||||
return ofBest(dateTime.with(field, newValue), zone, offset);
|
||||
}
|
||||
return ChronoZonedDateTimeImpl.ensureValid(getChronology(), field.adjustInto(this, newValue));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ChronoZonedDateTime<D> plus(long amountToAdd, TemporalUnit unit) {
|
||||
if (unit instanceof ChronoUnit) {
|
||||
return with(dateTime.plus(amountToAdd, unit));
|
||||
}
|
||||
return ChronoZonedDateTimeImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd)); /// TODO: Generics replacement Risk!
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public long until(Temporal endExclusive, TemporalUnit unit) {
|
||||
Objects.requireNonNull(endExclusive, "endExclusive");
|
||||
@SuppressWarnings("unchecked")
|
||||
ChronoZonedDateTime<D> end = (ChronoZonedDateTime<D>) getChronology().zonedDateTime(endExclusive);
|
||||
if (unit instanceof ChronoUnit) {
|
||||
end = end.withZoneSameInstant(offset);
|
||||
return dateTime.until(end.toLocalDateTime(), unit);
|
||||
}
|
||||
Objects.requireNonNull(unit, "unit");
|
||||
return unit.between(this, end);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the ChronoZonedDateTime using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(3); // identifies a ChronoZonedDateTime
|
||||
* out.writeObject(toLocalDateTime());
|
||||
* out.writeObject(getOffset());
|
||||
* out.writeObject(getZone());
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
private Object writeReplace() {
|
||||
return new Ser(Ser.CHRONO_ZONE_DATE_TIME_TYPE, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
|
||||
void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeObject(dateTime);
|
||||
out.writeObject(offset);
|
||||
out.writeObject(zone);
|
||||
}
|
||||
|
||||
static ChronoZonedDateTime<?> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
ChronoLocalDateTime<?> dateTime = (ChronoLocalDateTime<?>) in.readObject();
|
||||
ZoneOffset offset = (ZoneOffset) in.readObject();
|
||||
ZoneId zone = (ZoneId) in.readObject();
|
||||
return dateTime.atZone(offset).withZoneSameLocal(zone);
|
||||
// TODO: ZDT uses ofLenient()
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof ChronoZonedDateTime) {
|
||||
return compareTo((ChronoZonedDateTime<?>) obj) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toLocalDateTime().hashCode() ^ getOffset().hashCode() ^ Integer.rotateLeft(getZone().hashCode(), 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String str = toLocalDateTime().toString() + getOffset().toString();
|
||||
if (getOffset() != getZone()) {
|
||||
str += '[' + getZone().toString() + ']';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
754
jdkSrc/jdk8/java/time/chrono/Chronology.java
Normal file
754
jdkSrc/jdk8/java/time/chrono/Chronology.java
Normal file
@@ -0,0 +1,754 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.ResolverStyle;
|
||||
import java.time.format.TextStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQueries;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A calendar system, used to organize and identify dates.
|
||||
* <p>
|
||||
* The main date and time API is built on the ISO calendar system.
|
||||
* The chronology operates behind the scenes to represent the general concept of a calendar system.
|
||||
* For example, the Japanese, Minguo, Thai Buddhist and others.
|
||||
* <p>
|
||||
* Most other calendar systems also operate on the shared concepts of year, month and day,
|
||||
* linked to the cycles of the Earth around the Sun, and the Moon around the Earth.
|
||||
* These shared concepts are defined by {@link ChronoField} and are available
|
||||
* for use by any {@code Chronology} implementation:
|
||||
* <pre>
|
||||
* LocalDate isoDate = ...
|
||||
* ThaiBuddhistDate thaiDate = ...
|
||||
* int isoYear = isoDate.get(ChronoField.YEAR);
|
||||
* int thaiYear = thaiDate.get(ChronoField.YEAR);
|
||||
* </pre>
|
||||
* As shown, although the date objects are in different calendar systems, represented by different
|
||||
* {@code Chronology} instances, both can be queried using the same constant on {@code ChronoField}.
|
||||
* For a full discussion of the implications of this, see {@link ChronoLocalDate}.
|
||||
* In general, the advice is to use the known ISO-based {@code LocalDate}, rather than
|
||||
* {@code ChronoLocalDate}.
|
||||
* <p>
|
||||
* While a {@code Chronology} object typically uses {@code ChronoField} and is based on
|
||||
* an era, year-of-era, month-of-year, day-of-month model of a date, this is not required.
|
||||
* A {@code Chronology} instance may represent a totally different kind of calendar system,
|
||||
* such as the Mayan.
|
||||
* <p>
|
||||
* In practical terms, the {@code Chronology} instance also acts as a factory.
|
||||
* The {@link #of(String)} method allows an instance to be looked up by identifier,
|
||||
* while the {@link #ofLocale(Locale)} method allows lookup by locale.
|
||||
* <p>
|
||||
* The {@code Chronology} instance provides a set of methods to create {@code ChronoLocalDate} instances.
|
||||
* The date classes are used to manipulate specific dates.
|
||||
* <ul>
|
||||
* <li> {@link #dateNow() dateNow()}
|
||||
* <li> {@link #dateNow(Clock) dateNow(clock)}
|
||||
* <li> {@link #dateNow(ZoneId) dateNow(zone)}
|
||||
* <li> {@link #date(int, int, int) date(yearProleptic, month, day)}
|
||||
* <li> {@link #date(Era, int, int, int) date(era, yearOfEra, month, day)}
|
||||
* <li> {@link #dateYearDay(int, int) dateYearDay(yearProleptic, dayOfYear)}
|
||||
* <li> {@link #dateYearDay(Era, int, int) dateYearDay(era, yearOfEra, dayOfYear)}
|
||||
* <li> {@link #date(TemporalAccessor) date(TemporalAccessor)}
|
||||
* </ul>
|
||||
*
|
||||
* <h3 id="addcalendars">Adding New Calendars</h3>
|
||||
* The set of available chronologies can be extended by applications.
|
||||
* Adding a new calendar system requires the writing of an implementation of
|
||||
* {@code Chronology}, {@code ChronoLocalDate} and {@code Era}.
|
||||
* The majority of the logic specific to the calendar system will be in the
|
||||
* {@code ChronoLocalDate} implementation.
|
||||
* The {@code Chronology} implementation acts as a factory.
|
||||
* <p>
|
||||
* To permit the discovery of additional chronologies, the {@link java.util.ServiceLoader ServiceLoader}
|
||||
* is used. A file must be added to the {@code META-INF/services} directory with the
|
||||
* name 'java.time.chrono.Chronology' listing the implementation classes.
|
||||
* See the ServiceLoader for more details on service loading.
|
||||
* For lookup by id or calendarType, the system provided calendars are found
|
||||
* first followed by application provided calendars.
|
||||
* <p>
|
||||
* Each chronology must define a chronology ID that is unique within the system.
|
||||
* If the chronology represents a calendar system defined by the
|
||||
* CLDR specification then the calendar type is the concatenation of the
|
||||
* CLDR type and, if applicable, the CLDR variant,
|
||||
*
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations that can be instantiated must be final, immutable and thread-safe.
|
||||
* Subclasses should be Serializable wherever possible.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface Chronology extends Comparable<Chronology> {
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code Chronology} from a temporal object.
|
||||
* <p>
|
||||
* This obtains a chronology based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code Chronology}.
|
||||
* <p>
|
||||
* The conversion will obtain the chronology using {@link TemporalQueries#chronology()}.
|
||||
* If the specified temporal object does not have a chronology, {@link IsoChronology} is returned.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code Chronology::from}.
|
||||
*
|
||||
* @param temporal the temporal to convert, not null
|
||||
* @return the chronology, not null
|
||||
* @throws DateTimeException if unable to convert to an {@code Chronology}
|
||||
*/
|
||||
static Chronology from(TemporalAccessor temporal) {
|
||||
Objects.requireNonNull(temporal, "temporal");
|
||||
Chronology obj = temporal.query(TemporalQueries.chronology());
|
||||
return (obj != null ? obj : IsoChronology.INSTANCE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code Chronology} from a locale.
|
||||
* <p>
|
||||
* This returns a {@code Chronology} based on the specified locale,
|
||||
* typically returning {@code IsoChronology}. Other calendar systems
|
||||
* are only returned if they are explicitly selected within the locale.
|
||||
* <p>
|
||||
* The {@link Locale} class provide access to a range of information useful
|
||||
* for localizing an application. This includes the language and region,
|
||||
* such as "en-GB" for English as used in Great Britain.
|
||||
* <p>
|
||||
* The {@code Locale} class also supports an extension mechanism that
|
||||
* can be used to identify a calendar system. The mechanism is a form
|
||||
* of key-value pairs, where the calendar system has the key "ca".
|
||||
* For example, the locale "en-JP-u-ca-japanese" represents the English
|
||||
* language as used in Japan with the Japanese calendar system.
|
||||
* <p>
|
||||
* This method finds the desired calendar system by in a manner equivalent
|
||||
* to passing "ca" to {@link Locale#getUnicodeLocaleType(String)}.
|
||||
* If the "ca" key is not present, then {@code IsoChronology} is returned.
|
||||
* <p>
|
||||
* Note that the behavior of this method differs from the older
|
||||
* {@link java.util.Calendar#getInstance(Locale)} method.
|
||||
* If that method receives a locale of "th_TH" it will return {@code BuddhistCalendar}.
|
||||
* By contrast, this method will return {@code IsoChronology}.
|
||||
* Passing the locale "th-TH-u-ca-buddhist" into either method will
|
||||
* result in the Thai Buddhist calendar system and is therefore the
|
||||
* recommended approach going forward for Thai calendar system localization.
|
||||
* <p>
|
||||
* A similar, but simpler, situation occurs for the Japanese calendar system.
|
||||
* The locale "jp_JP_JP" has previously been used to access the calendar.
|
||||
* However, unlike the Thai locale, "ja_JP_JP" is automatically converted by
|
||||
* {@code Locale} to the modern and recommended form of "ja-JP-u-ca-japanese".
|
||||
* Thus, there is no difference in behavior between this method and
|
||||
* {@code Calendar#getInstance(Locale)}.
|
||||
*
|
||||
* @param locale the locale to use to obtain the calendar system, not null
|
||||
* @return the calendar system associated with the locale, not null
|
||||
* @throws DateTimeException if the locale-specified calendar cannot be found
|
||||
*/
|
||||
static Chronology ofLocale(Locale locale) {
|
||||
return AbstractChronology.ofLocale(locale);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code Chronology} from a chronology ID or
|
||||
* calendar system type.
|
||||
* <p>
|
||||
* This returns a chronology based on either the ID or the type.
|
||||
* The {@link #getId() chronology ID} uniquely identifies the chronology.
|
||||
* The {@link #getCalendarType() calendar system type} is defined by the
|
||||
* CLDR specification.
|
||||
* <p>
|
||||
* The chronology may be a system chronology or a chronology
|
||||
* provided by the application via ServiceLoader configuration.
|
||||
* <p>
|
||||
* Since some calendars can be customized, the ID or type typically refers
|
||||
* to the default customization. For example, the Gregorian calendar can have multiple
|
||||
* cutover dates from the Julian, but the lookup only provides the default cutover date.
|
||||
*
|
||||
* @param id the chronology ID or calendar system type, not null
|
||||
* @return the chronology with the identifier requested, not null
|
||||
* @throws DateTimeException if the chronology cannot be found
|
||||
*/
|
||||
static Chronology of(String id) {
|
||||
return AbstractChronology.of(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the available chronologies.
|
||||
* <p>
|
||||
* Each returned {@code Chronology} is available for use in the system.
|
||||
* The set of chronologies includes the system chronologies and
|
||||
* any chronologies provided by the application via ServiceLoader
|
||||
* configuration.
|
||||
*
|
||||
* @return the independent, modifiable set of the available chronology IDs, not null
|
||||
*/
|
||||
static Set<Chronology> getAvailableChronologies() {
|
||||
return AbstractChronology.getAvailableChronologies();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the ID of the chronology.
|
||||
* <p>
|
||||
* The ID uniquely identifies the {@code Chronology}.
|
||||
* It can be used to lookup the {@code Chronology} using {@link #of(String)}.
|
||||
*
|
||||
* @return the chronology ID, not null
|
||||
* @see #getCalendarType()
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Gets the calendar type of the calendar system.
|
||||
* <p>
|
||||
* The calendar type is an identifier defined by the CLDR and
|
||||
* <em>Unicode Locale Data Markup Language (LDML)</em> specifications
|
||||
* to uniquely identification a calendar.
|
||||
* The {@code getCalendarType} is the concatenation of the CLDR calendar type
|
||||
* and the variant, if applicable, is appended separated by "-".
|
||||
* The calendar type is used to lookup the {@code Chronology} using {@link #of(String)}.
|
||||
*
|
||||
* @return the calendar system type, null if the calendar is not defined by CLDR/LDML
|
||||
* @see #getId()
|
||||
*/
|
||||
String getCalendarType();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a local date in this chronology from the era, year-of-era,
|
||||
* month-of-year and day-of-month fields.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation combines the era and year-of-era into a proleptic
|
||||
* year before calling {@link #date(int, int, int)}.
|
||||
*
|
||||
* @param era the era of the correct type for the chronology, not null
|
||||
* @param yearOfEra the chronology year-of-era
|
||||
* @param month the chronology month-of-year
|
||||
* @param dayOfMonth the chronology day-of-month
|
||||
* @return the local date in this chronology, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
* @throws ClassCastException if the {@code era} is not of the correct type for the chronology
|
||||
*/
|
||||
default ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
|
||||
return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in this chronology from the proleptic-year,
|
||||
* month-of-year and day-of-month fields.
|
||||
*
|
||||
* @param prolepticYear the chronology proleptic-year
|
||||
* @param month the chronology month-of-year
|
||||
* @param dayOfMonth the chronology day-of-month
|
||||
* @return the local date in this chronology, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth);
|
||||
|
||||
/**
|
||||
* Obtains a local date in this chronology from the era, year-of-era and
|
||||
* day-of-year fields.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation combines the era and year-of-era into a proleptic
|
||||
* year before calling {@link #dateYearDay(int, int)}.
|
||||
*
|
||||
* @param era the era of the correct type for the chronology, not null
|
||||
* @param yearOfEra the chronology year-of-era
|
||||
* @param dayOfYear the chronology day-of-year
|
||||
* @return the local date in this chronology, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
* @throws ClassCastException if the {@code era} is not of the correct type for the chronology
|
||||
*/
|
||||
default ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
|
||||
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in this chronology from the proleptic-year and
|
||||
* day-of-year fields.
|
||||
*
|
||||
* @param prolepticYear the chronology proleptic-year
|
||||
* @param dayOfYear the chronology day-of-year
|
||||
* @return the local date in this chronology, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear);
|
||||
|
||||
/**
|
||||
* Obtains a local date in this chronology from the epoch-day.
|
||||
* <p>
|
||||
* The definition of {@link ChronoField#EPOCH_DAY EPOCH_DAY} is the same
|
||||
* for all calendar systems, thus it can be used for conversion.
|
||||
*
|
||||
* @param epochDay the epoch day
|
||||
* @return the local date in this chronology, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
ChronoLocalDate dateEpochDay(long epochDay);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains the current local date in this chronology from the system clock in the default time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
|
||||
* time-zone to obtain the current date.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes {@link #dateNow(Clock)}.
|
||||
*
|
||||
* @return the current local date using the system clock and default time-zone, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
default ChronoLocalDate dateNow() {
|
||||
return dateNow(Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current local date in this chronology from the system clock in the specified time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
|
||||
* Specifying the time-zone avoids dependence on the default time-zone.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes {@link #dateNow(Clock)}.
|
||||
*
|
||||
* @param zone the zone ID to use, not null
|
||||
* @return the current local date using the system clock, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
default ChronoLocalDate dateNow(ZoneId zone) {
|
||||
return dateNow(Clock.system(zone));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current local date in this chronology from the specified clock.
|
||||
* <p>
|
||||
* This will query the specified clock to obtain the current date - today.
|
||||
* Using this method allows the use of an alternate clock for testing.
|
||||
* The alternate clock may be introduced using {@link Clock dependency injection}.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation invokes {@link #date(TemporalAccessor)}.
|
||||
*
|
||||
* @param clock the clock to use, not null
|
||||
* @return the current local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
default ChronoLocalDate dateNow(Clock clock) {
|
||||
Objects.requireNonNull(clock, "clock");
|
||||
return date(LocalDate.now(clock));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a local date in this chronology from another temporal object.
|
||||
* <p>
|
||||
* This obtains a date in this chronology based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code ChronoLocalDate}.
|
||||
* <p>
|
||||
* The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
|
||||
* field, which is standardized across calendar systems.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code aChronology::date}.
|
||||
*
|
||||
* @param temporal the temporal object to convert, not null
|
||||
* @return the local date in this chronology, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
* @see ChronoLocalDate#from(TemporalAccessor)
|
||||
*/
|
||||
ChronoLocalDate date(TemporalAccessor temporal);
|
||||
|
||||
/**
|
||||
* Obtains a local date-time in this chronology from another temporal object.
|
||||
* <p>
|
||||
* This obtains a date-time in this chronology based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code ChronoLocalDateTime}.
|
||||
* <p>
|
||||
* The conversion extracts and combines the {@code ChronoLocalDate} and the
|
||||
* {@code LocalTime} from the temporal object.
|
||||
* Implementations are permitted to perform optimizations such as accessing
|
||||
* those fields that are equivalent to the relevant objects.
|
||||
* The result uses this chronology.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code aChronology::localDateTime}.
|
||||
*
|
||||
* @param temporal the temporal object to convert, not null
|
||||
* @return the local date-time in this chronology, not null
|
||||
* @throws DateTimeException if unable to create the date-time
|
||||
* @see ChronoLocalDateTime#from(TemporalAccessor)
|
||||
*/
|
||||
default ChronoLocalDateTime<? extends ChronoLocalDate> localDateTime(TemporalAccessor temporal) {
|
||||
try {
|
||||
return date(temporal).atTime(LocalTime.from(temporal));
|
||||
} catch (DateTimeException ex) {
|
||||
throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code ChronoZonedDateTime} in this chronology from another temporal object.
|
||||
* <p>
|
||||
* This obtains a zoned date-time in this chronology based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code ChronoZonedDateTime}.
|
||||
* <p>
|
||||
* The conversion will first obtain a {@code ZoneId} from the temporal object,
|
||||
* falling back to a {@code ZoneOffset} if necessary. It will then try to obtain
|
||||
* an {@code Instant}, falling back to a {@code ChronoLocalDateTime} if necessary.
|
||||
* The result will be either the combination of {@code ZoneId} or {@code ZoneOffset}
|
||||
* with {@code Instant} or {@code ChronoLocalDateTime}.
|
||||
* Implementations are permitted to perform optimizations such as accessing
|
||||
* those fields that are equivalent to the relevant objects.
|
||||
* The result uses this chronology.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code aChronology::zonedDateTime}.
|
||||
*
|
||||
* @param temporal the temporal object to convert, not null
|
||||
* @return the zoned date-time in this chronology, not null
|
||||
* @throws DateTimeException if unable to create the date-time
|
||||
* @see ChronoZonedDateTime#from(TemporalAccessor)
|
||||
*/
|
||||
default ChronoZonedDateTime<? extends ChronoLocalDate> zonedDateTime(TemporalAccessor temporal) {
|
||||
try {
|
||||
ZoneId zone = ZoneId.from(temporal);
|
||||
try {
|
||||
Instant instant = Instant.from(temporal);
|
||||
return zonedDateTime(instant, zone);
|
||||
|
||||
} catch (DateTimeException ex1) {
|
||||
ChronoLocalDateTimeImpl<?> cldt = ChronoLocalDateTimeImpl.ensureValid(this, localDateTime(temporal));
|
||||
return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null);
|
||||
}
|
||||
} catch (DateTimeException ex) {
|
||||
throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code ChronoZonedDateTime} in this chronology from an {@code Instant}.
|
||||
* <p>
|
||||
* This obtains a zoned date-time with the same instant as that specified.
|
||||
*
|
||||
* @param instant the instant to create the date-time from, not null
|
||||
* @param zone the time-zone, not null
|
||||
* @return the zoned date-time, not null
|
||||
* @throws DateTimeException if the result exceeds the supported range
|
||||
*/
|
||||
default ChronoZonedDateTime<? extends ChronoLocalDate> zonedDateTime(Instant instant, ZoneId zone) {
|
||||
return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if the specified year is a leap year.
|
||||
* <p>
|
||||
* A leap-year is a year of a longer length than normal.
|
||||
* The exact meaning is determined by the chronology according to the following constraints.
|
||||
* <ul>
|
||||
* <li>a leap-year must imply a year-length longer than a non leap-year.
|
||||
* <li>a chronology that does not support the concept of a year must return false.
|
||||
* </ul>
|
||||
*
|
||||
* @param prolepticYear the proleptic-year to check, not validated for range
|
||||
* @return true if the year is a leap year
|
||||
*/
|
||||
boolean isLeapYear(long prolepticYear);
|
||||
|
||||
/**
|
||||
* Calculates the proleptic-year given the era and year-of-era.
|
||||
* <p>
|
||||
* This combines the era and year-of-era into the single proleptic-year field.
|
||||
* <p>
|
||||
* If the chronology makes active use of eras, such as {@code JapaneseChronology}
|
||||
* then the year-of-era will be validated against the era.
|
||||
* For other chronologies, validation is optional.
|
||||
*
|
||||
* @param era the era of the correct type for the chronology, not null
|
||||
* @param yearOfEra the chronology year-of-era
|
||||
* @return the proleptic-year
|
||||
* @throws DateTimeException if unable to convert to a proleptic-year,
|
||||
* such as if the year is invalid for the era
|
||||
* @throws ClassCastException if the {@code era} is not of the correct type for the chronology
|
||||
*/
|
||||
int prolepticYear(Era era, int yearOfEra);
|
||||
|
||||
/**
|
||||
* Creates the chronology era object from the numeric value.
|
||||
* <p>
|
||||
* The era is, conceptually, the largest division of the time-line.
|
||||
* Most calendar systems have a single epoch dividing the time-line into two eras.
|
||||
* However, some have multiple eras, such as one for the reign of each leader.
|
||||
* The exact meaning is determined by the chronology according to the following constraints.
|
||||
* <p>
|
||||
* The era in use at 1970-01-01 must have the value 1.
|
||||
* Later eras must have sequentially higher values.
|
||||
* Earlier eras must have sequentially lower values.
|
||||
* Each chronology must refer to an enum or similar singleton to provide the era values.
|
||||
* <p>
|
||||
* This method returns the singleton era of the correct type for the specified era value.
|
||||
*
|
||||
* @param eraValue the era value
|
||||
* @return the calendar system era, not null
|
||||
* @throws DateTimeException if unable to create the era
|
||||
*/
|
||||
Era eraOf(int eraValue);
|
||||
|
||||
/**
|
||||
* Gets the list of eras for the chronology.
|
||||
* <p>
|
||||
* Most calendar systems have an era, within which the year has meaning.
|
||||
* If the calendar system does not support the concept of eras, an empty
|
||||
* list must be returned.
|
||||
*
|
||||
* @return the list of eras for the chronology, may be immutable, not null
|
||||
*/
|
||||
List<Era> eras();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the range of valid values for the specified field.
|
||||
* <p>
|
||||
* All fields can be expressed as a {@code long} integer.
|
||||
* This method returns an object that describes the valid range for that value.
|
||||
* <p>
|
||||
* Note that the result only describes the minimum and maximum valid values
|
||||
* and it is important not to read too much into them. For example, there
|
||||
* could be values within the range that are invalid for the field.
|
||||
* <p>
|
||||
* This method will return a result whether or not the chronology supports the field.
|
||||
*
|
||||
* @param field the field to get the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
*/
|
||||
ValueRange range(ChronoField field);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the textual representation of this chronology.
|
||||
* <p>
|
||||
* This returns the textual name used to identify the chronology,
|
||||
* suitable for presentation to the user.
|
||||
* The parameters control the style of the returned text and the locale.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation behaves as though the formatter was used to
|
||||
* format the chronology textual name.
|
||||
*
|
||||
* @param style the style of the text required, not null
|
||||
* @param locale the locale to use, not null
|
||||
* @return the text value of the chronology, not null
|
||||
*/
|
||||
default String getDisplayName(TextStyle style, Locale locale) {
|
||||
TemporalAccessor temporal = new TemporalAccessor() {
|
||||
@Override
|
||||
public boolean isSupported(TemporalField field) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public long getLong(TemporalField field) {
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R> R query(TemporalQuery<R> query) {
|
||||
if (query == TemporalQueries.chronology()) {
|
||||
return (R) Chronology.this;
|
||||
}
|
||||
return TemporalAccessor.super.query(query);
|
||||
}
|
||||
};
|
||||
return new DateTimeFormatterBuilder().appendChronologyText(style).toFormatter(locale).format(temporal);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Resolves parsed {@code ChronoField} values into a date during parsing.
|
||||
* <p>
|
||||
* Most {@code TemporalField} implementations are resolved using the
|
||||
* resolve method on the field. By contrast, the {@code ChronoField} class
|
||||
* defines fields that only have meaning relative to the chronology.
|
||||
* As such, {@code ChronoField} date fields are resolved here in the
|
||||
* context of a specific chronology.
|
||||
* <p>
|
||||
* The default implementation, which explains typical resolve behaviour,
|
||||
* is provided in {@link AbstractChronology}.
|
||||
*
|
||||
* @param fieldValues the map of fields to values, which can be updated, not null
|
||||
* @param resolverStyle the requested type of resolve, not null
|
||||
* @return the resolved date, null if insufficient information to create a date
|
||||
* @throws DateTimeException if the date cannot be resolved, typically
|
||||
* because of a conflict in the input data
|
||||
*/
|
||||
ChronoLocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a period for this chronology based on years, months and days.
|
||||
* <p>
|
||||
* This returns a period tied to this chronology using the specified
|
||||
* years, months and days. All supplied chronologies use periods
|
||||
* based on years, months and days, however the {@code ChronoPeriod} API
|
||||
* allows the period to be represented using other units.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation returns an implementation class suitable
|
||||
* for most calendar systems. It is based solely on the three units.
|
||||
* Normalization, addition and subtraction derive the number of months
|
||||
* in a year from the {@link #range(ChronoField)}. If the number of
|
||||
* months within a year is fixed, then the calculation approach for
|
||||
* addition, subtraction and normalization is slightly different.
|
||||
* <p>
|
||||
* If implementing an unusual calendar system that is not based on
|
||||
* years, months and days, or where you want direct control, then
|
||||
* the {@code ChronoPeriod} interface must be directly implemented.
|
||||
* <p>
|
||||
* The returned period is immutable and thread-safe.
|
||||
*
|
||||
* @param years the number of years, may be negative
|
||||
* @param months the number of years, may be negative
|
||||
* @param days the number of years, may be negative
|
||||
* @return the period in terms of this chronology, not null
|
||||
*/
|
||||
default ChronoPeriod period(int years, int months, int days) {
|
||||
return new ChronoPeriodImpl(this, years, months, days);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this chronology to another chronology.
|
||||
* <p>
|
||||
* The comparison order first by the chronology ID string, then by any
|
||||
* additional information specific to the subclass.
|
||||
* It is "consistent with equals", as defined by {@link Comparable}.
|
||||
*
|
||||
* @param other the other chronology to compare to, not null
|
||||
* @return the comparator value, negative if less, positive if greater
|
||||
*/
|
||||
@Override
|
||||
int compareTo(Chronology other);
|
||||
|
||||
/**
|
||||
* Checks if this chronology is equal to another chronology.
|
||||
* <p>
|
||||
* The comparison is based on the entire state of the object.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other chronology
|
||||
*/
|
||||
@Override
|
||||
boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* A hash code for this chronology.
|
||||
* <p>
|
||||
* The hash code should be based on the entire state of the object.
|
||||
*
|
||||
* @return a suitable hash code
|
||||
*/
|
||||
@Override
|
||||
int hashCode();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Outputs this chronology as a {@code String}.
|
||||
* <p>
|
||||
* The format should include the entire state of the object.
|
||||
*
|
||||
* @return a string representation of this chronology, not null
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
|
||||
}
|
||||
325
jdkSrc/jdk8/java/time/chrono/Era.java
Normal file
325
jdkSrc/jdk8/java/time/chrono/Era.java
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.ERA;
|
||||
import static java.time.temporal.ChronoUnit.ERAS;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.TextStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.Temporal;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQueries;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* An era of the time-line.
|
||||
* <p>
|
||||
* Most calendar systems have a single epoch dividing the time-line into two eras.
|
||||
* However, some calendar systems, have multiple eras, such as one for the reign
|
||||
* of each leader.
|
||||
* In all cases, the era is conceptually the largest division of the time-line.
|
||||
* Each chronology defines the Era's that are known Eras and a
|
||||
* {@link Chronology#eras Chronology.eras} to get the valid eras.
|
||||
* <p>
|
||||
* For example, the Thai Buddhist calendar system divides time into two eras,
|
||||
* before and after a single date. By contrast, the Japanese calendar system
|
||||
* has one era for the reign of each Emperor.
|
||||
* <p>
|
||||
* Instances of {@code Era} may be compared using the {@code ==} operator.
|
||||
*
|
||||
* @implSpec
|
||||
* This interface must be implemented with care to ensure other classes operate correctly.
|
||||
* All implementations must be singletons - final, immutable and thread-safe.
|
||||
* It is recommended to use an enum whenever possible.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface Era extends TemporalAccessor, TemporalAdjuster {
|
||||
|
||||
/**
|
||||
* Gets the numeric value associated with the era as defined by the chronology.
|
||||
* Each chronology defines the predefined Eras and methods to list the Eras
|
||||
* of the chronology.
|
||||
* <p>
|
||||
* All fields, including eras, have an associated numeric value.
|
||||
* The meaning of the numeric value for era is determined by the chronology
|
||||
* according to these principles:
|
||||
* <ul>
|
||||
* <li>The era in use at the epoch 1970-01-01 (ISO) has the value 1.
|
||||
* <li>Later eras have sequentially higher values.
|
||||
* <li>Earlier eras have sequentially lower values, which may be negative.
|
||||
* </ul>
|
||||
*
|
||||
* @return the numeric era value
|
||||
*/
|
||||
int getValue();
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if the specified field is supported.
|
||||
* <p>
|
||||
* This checks if this era can be queried for the specified field.
|
||||
* If false, then calling the {@link #range(TemporalField) range} and
|
||||
* {@link #get(TemporalField) get} methods will throw an exception.
|
||||
* <p>
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@code ERA} field returns true.
|
||||
* All other {@code ChronoField} instances will return false.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the field is supported is determined by the field.
|
||||
*
|
||||
* @param field the field to check, null returns false
|
||||
* @return true if the field is supported on this era, false if not
|
||||
*/
|
||||
@Override
|
||||
default boolean isSupported(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
return field == ERA;
|
||||
}
|
||||
return field != null && field.isSupportedBy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the range of valid values for the specified field.
|
||||
* <p>
|
||||
* The range object expresses the minimum and maximum valid values for a field.
|
||||
* This era is used to enhance the accuracy of the returned range.
|
||||
* If it is not possible to return the range, because the field is not supported
|
||||
* or for some other reason, an exception is thrown.
|
||||
* <p>
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@code ERA} field returns the range.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the range can be obtained is determined by the field.
|
||||
* <p>
|
||||
* The default implementation must return a range for {@code ERA} from
|
||||
* zero to one, suitable for two era calendar systems such as ISO.
|
||||
*
|
||||
* @param field the field to query the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
*/
|
||||
@Override // override for Javadoc
|
||||
default ValueRange range(TemporalField field) {
|
||||
return TemporalAccessor.super.range(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the specified field from this era as an {@code int}.
|
||||
* <p>
|
||||
* This queries this era for the value of the specified field.
|
||||
* The returned value will always be within the valid range of values for the field.
|
||||
* If it is not possible to return the value, because the field is not supported
|
||||
* or for some other reason, an exception is thrown.
|
||||
* <p>
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@code ERA} field returns the value of the era.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
* passing {@code this} as the argument. Whether the value can be obtained,
|
||||
* and what the value represents, is determined by the field.
|
||||
*
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained or
|
||||
* the value is outside the range of valid values for the field
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported or
|
||||
* the range of values exceeds an {@code int}
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override // override for Javadoc and performance
|
||||
default int get(TemporalField field) {
|
||||
if (field == ERA) {
|
||||
return getValue();
|
||||
}
|
||||
return TemporalAccessor.super.get(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the specified field from this era as a {@code long}.
|
||||
* <p>
|
||||
* This queries this era for the value of the specified field.
|
||||
* If it is not possible to return the value, because the field is not supported
|
||||
* or for some other reason, an exception is thrown.
|
||||
* <p>
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@code ERA} field returns the value of the era.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
|
||||
* passing {@code this} as the argument. Whether the value can be obtained,
|
||||
* and what the value represents, is determined by the field.
|
||||
*
|
||||
* @param field the field to get, not null
|
||||
* @return the value for the field
|
||||
* @throws DateTimeException if a value for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the field is not supported
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
default long getLong(TemporalField field) {
|
||||
if (field == ERA) {
|
||||
return getValue();
|
||||
} else if (field instanceof ChronoField) {
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Queries this era using the specified query.
|
||||
* <p>
|
||||
* This queries this era using the specified query strategy object.
|
||||
* The {@code TemporalQuery} object defines the logic to be used to
|
||||
* obtain the result. Read the documentation of the query to understand
|
||||
* what the result of this method will be.
|
||||
* <p>
|
||||
* The result of this method is obtained by invoking the
|
||||
* {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
|
||||
* specified query passing {@code this} as the argument.
|
||||
*
|
||||
* @param <R> the type of the result
|
||||
* @param query the query to invoke, not null
|
||||
* @return the query result, null may be returned (defined by the query)
|
||||
* @throws DateTimeException if unable to query (defined by the query)
|
||||
* @throws ArithmeticException if numeric overflow occurs (defined by the query)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
default <R> R query(TemporalQuery<R> query) {
|
||||
if (query == TemporalQueries.precision()) {
|
||||
return (R) ERAS;
|
||||
}
|
||||
return TemporalAccessor.super.query(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the specified temporal object to have the same era as this object.
|
||||
* <p>
|
||||
* This returns a temporal object of the same observable type as the input
|
||||
* with the era changed to be the same as this.
|
||||
* <p>
|
||||
* The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
|
||||
* passing {@link ChronoField#ERA} as the field.
|
||||
* <p>
|
||||
* In most cases, it is clearer to reverse the calling pattern by using
|
||||
* {@link Temporal#with(TemporalAdjuster)}:
|
||||
* <pre>
|
||||
* // these two lines are equivalent, but the second approach is recommended
|
||||
* temporal = thisEra.adjustInto(temporal);
|
||||
* temporal = temporal.with(thisEra);
|
||||
* </pre>
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param temporal the target object to be adjusted, not null
|
||||
* @return the adjusted object, not null
|
||||
* @throws DateTimeException if unable to make the adjustment
|
||||
* @throws ArithmeticException if numeric overflow occurs
|
||||
*/
|
||||
@Override
|
||||
default Temporal adjustInto(Temporal temporal) {
|
||||
return temporal.with(ERA, getValue());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the textual representation of this era.
|
||||
* <p>
|
||||
* This returns the textual name used to identify the era,
|
||||
* suitable for presentation to the user.
|
||||
* The parameters control the style of the returned text and the locale.
|
||||
* <p>
|
||||
* If no textual mapping is found then the {@link #getValue() numeric value} is returned.
|
||||
*
|
||||
* @apiNote This default implementation is suitable for most implementations.
|
||||
*
|
||||
* @param style the style of the text required, not null
|
||||
* @param locale the locale to use, not null
|
||||
* @return the text value of the era, not null
|
||||
*/
|
||||
default String getDisplayName(TextStyle style, Locale locale) {
|
||||
return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).format(this);
|
||||
}
|
||||
|
||||
// NOTE: methods to convert year-of-era/proleptic-year cannot be here as they may depend on month/day (Japanese)
|
||||
}
|
||||
1104
jdkSrc/jdk8/java/time/chrono/HijrahChronology.java
Normal file
1104
jdkSrc/jdk8/java/time/chrono/HijrahChronology.java
Normal file
File diff suppressed because it is too large
Load Diff
698
jdkSrc/jdk8/java/time/chrono/HijrahDate.java
Normal file
698
jdkSrc/jdk8/java/time/chrono/HijrahDate.java
Normal file
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
|
||||
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
|
||||
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.Serializable;
|
||||
import java.time.Clock;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
|
||||
/**
|
||||
* A date in the Hijrah calendar system.
|
||||
* <p>
|
||||
* This date operates using one of several variants of the
|
||||
* {@linkplain HijrahChronology Hijrah calendar}.
|
||||
* <p>
|
||||
* The Hijrah calendar has a different total of days in a year than
|
||||
* Gregorian calendar, and the length of each month is based on the period
|
||||
* of a complete revolution of the moon around the earth
|
||||
* (as between successive new moons).
|
||||
* Refer to the {@link HijrahChronology} for details of supported variants.
|
||||
* <p>
|
||||
* Each HijrahDate is created bound to a particular HijrahChronology,
|
||||
* The same chronology is propagated to each HijrahDate computed from the date.
|
||||
* To use a different Hijrah variant, its HijrahChronology can be used
|
||||
* to create new HijrahDate instances.
|
||||
* Alternatively, the {@link #withVariant} method can be used to convert
|
||||
* to a new HijrahChronology.
|
||||
*
|
||||
* <p>
|
||||
* This is a <a href="{@docRoot}/java/lang/doc-files/ValueBased.html">value-based</a>
|
||||
* class; use of identity-sensitive operations (including reference equality
|
||||
* ({@code ==}), identity hash code, or synchronization) on instances of
|
||||
* {@code HijrahDate} may have unpredictable results and should be avoided.
|
||||
* The {@code equals} method should be used for comparisons.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class HijrahDate
|
||||
extends ChronoLocalDateImpl<HijrahDate>
|
||||
implements ChronoLocalDate, Serializable {
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = -5207853542612002020L;
|
||||
/**
|
||||
* The Chronology of this HijrahDate.
|
||||
*/
|
||||
private final transient HijrahChronology chrono;
|
||||
/**
|
||||
* The proleptic year.
|
||||
*/
|
||||
private final transient int prolepticYear;
|
||||
/**
|
||||
* The month-of-year.
|
||||
*/
|
||||
private final transient int monthOfYear;
|
||||
/**
|
||||
* The day-of-month.
|
||||
*/
|
||||
private final transient int dayOfMonth;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code HijrahDate} from the Hijrah proleptic year,
|
||||
* month-of-year and day-of-month.
|
||||
*
|
||||
* @param prolepticYear the proleptic year to represent in the Hijrah calendar
|
||||
* @param monthOfYear the month-of-year to represent, from 1 to 12
|
||||
* @param dayOfMonth the day-of-month to represent, from 1 to 30
|
||||
* @return the Hijrah date, never null
|
||||
* @throws DateTimeException if the value of any field is out of range
|
||||
*/
|
||||
static HijrahDate of(HijrahChronology chrono, int prolepticYear, int monthOfYear, int dayOfMonth) {
|
||||
return new HijrahDate(chrono, prolepticYear, monthOfYear, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a HijrahDate for the chronology and epochDay.
|
||||
* @param chrono The Hijrah chronology
|
||||
* @param epochDay the epoch day
|
||||
* @return a HijrahDate for the epoch day; non-null
|
||||
*/
|
||||
static HijrahDate ofEpochDay(HijrahChronology chrono, long epochDay) {
|
||||
return new HijrahDate(chrono, epochDay);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains the current {@code HijrahDate} of the Islamic Umm Al-Qura calendar
|
||||
* in the default time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
|
||||
* time-zone to obtain the current date.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @return the current date using the system clock and default time-zone, not null
|
||||
*/
|
||||
public static HijrahDate now() {
|
||||
return now(Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current {@code HijrahDate} of the Islamic Umm Al-Qura calendar
|
||||
* in the specified time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
|
||||
* Specifying the time-zone avoids dependence on the default time-zone.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @param zone the zone ID to use, not null
|
||||
* @return the current date using the system clock, not null
|
||||
*/
|
||||
public static HijrahDate now(ZoneId zone) {
|
||||
return now(Clock.system(zone));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current {@code HijrahDate} of the Islamic Umm Al-Qura calendar
|
||||
* from the specified clock.
|
||||
* <p>
|
||||
* This will query the specified clock to obtain the current date - today.
|
||||
* Using this method allows the use of an alternate clock for testing.
|
||||
* The alternate clock may be introduced using {@linkplain Clock dependency injection}.
|
||||
*
|
||||
* @param clock the clock to use, not null
|
||||
* @return the current date, not null
|
||||
* @throws DateTimeException if the current date cannot be obtained
|
||||
*/
|
||||
public static HijrahDate now(Clock clock) {
|
||||
return HijrahDate.ofEpochDay(HijrahChronology.INSTANCE, LocalDate.now(clock).toEpochDay());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code HijrahDate} of the Islamic Umm Al-Qura calendar
|
||||
* from the proleptic-year, month-of-year and day-of-month fields.
|
||||
* <p>
|
||||
* This returns a {@code HijrahDate} with the specified fields.
|
||||
* The day must be valid for the year and month, otherwise an exception will be thrown.
|
||||
*
|
||||
* @param prolepticYear the Hijrah proleptic-year
|
||||
* @param month the Hijrah month-of-year, from 1 to 12
|
||||
* @param dayOfMonth the Hijrah day-of-month, from 1 to 30
|
||||
* @return the date in Hijrah calendar system, not null
|
||||
* @throws DateTimeException if the value of any field is out of range,
|
||||
* or if the day-of-month is invalid for the month-year
|
||||
*/
|
||||
public static HijrahDate of(int prolepticYear, int month, int dayOfMonth) {
|
||||
return HijrahChronology.INSTANCE.date(prolepticYear, month, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code HijrahDate} of the Islamic Umm Al-Qura calendar from a temporal object.
|
||||
* <p>
|
||||
* This obtains a date in the Hijrah calendar system based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code HijrahDate}.
|
||||
* <p>
|
||||
* The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
|
||||
* field, which is standardized across calendar systems.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code HijrahDate::from}.
|
||||
*
|
||||
* @param temporal the temporal object to convert, not null
|
||||
* @return the date in Hijrah calendar system, not null
|
||||
* @throws DateTimeException if unable to convert to a {@code HijrahDate}
|
||||
*/
|
||||
public static HijrahDate from(TemporalAccessor temporal) {
|
||||
return HijrahChronology.INSTANCE.date(temporal);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Constructs an {@code HijrahDate} with the proleptic-year, month-of-year and
|
||||
* day-of-month fields.
|
||||
*
|
||||
* @param chrono The chronology to create the date with
|
||||
* @param prolepticYear the proleptic year
|
||||
* @param monthOfYear the month of year
|
||||
* @param dayOfMonth the day of month
|
||||
*/
|
||||
private HijrahDate(HijrahChronology chrono, int prolepticYear, int monthOfYear, int dayOfMonth) {
|
||||
// Computing the Gregorian day checks the valid ranges
|
||||
chrono.getEpochDay(prolepticYear, monthOfYear, dayOfMonth);
|
||||
|
||||
this.chrono = chrono;
|
||||
this.prolepticYear = prolepticYear;
|
||||
this.monthOfYear = monthOfYear;
|
||||
this.dayOfMonth = dayOfMonth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance with the Epoch Day.
|
||||
*
|
||||
* @param epochDay the epochDay
|
||||
*/
|
||||
private HijrahDate(HijrahChronology chrono, long epochDay) {
|
||||
int[] dateInfo = chrono.getHijrahDateInfo((int)epochDay);
|
||||
|
||||
this.chrono = chrono;
|
||||
this.prolepticYear = dateInfo[0];
|
||||
this.monthOfYear = dateInfo[1];
|
||||
this.dayOfMonth = dateInfo[2];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the chronology of this date, which is the Hijrah calendar system.
|
||||
* <p>
|
||||
* The {@code Chronology} represents the calendar system in use.
|
||||
* The era and other fields in {@link ChronoField} are defined by the chronology.
|
||||
*
|
||||
* @return the Hijrah chronology, not null
|
||||
*/
|
||||
@Override
|
||||
public HijrahChronology getChronology() {
|
||||
return chrono;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the era applicable at this date.
|
||||
* <p>
|
||||
* The Hijrah calendar system has one era, 'AH',
|
||||
* defined by {@link HijrahEra}.
|
||||
*
|
||||
* @return the era applicable at this date, not null
|
||||
*/
|
||||
@Override
|
||||
public HijrahEra getEra() {
|
||||
return HijrahEra.AH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the month represented by this date.
|
||||
* <p>
|
||||
* This returns the length of the month in days.
|
||||
* Month lengths in the Hijrah calendar system vary between 29 and 30 days.
|
||||
*
|
||||
* @return the length of the month in days
|
||||
*/
|
||||
@Override
|
||||
public int lengthOfMonth() {
|
||||
return chrono.getMonthLength(prolepticYear, monthOfYear);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the year represented by this date.
|
||||
* <p>
|
||||
* This returns the length of the year in days.
|
||||
* A Hijrah calendar system year is typically shorter than
|
||||
* that of the ISO calendar system.
|
||||
*
|
||||
* @return the length of the year in days
|
||||
*/
|
||||
@Override
|
||||
public int lengthOfYear() {
|
||||
return chrono.getYearLength(prolepticYear);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ValueRange range(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
if (isSupported(field)) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
switch (f) {
|
||||
case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
|
||||
case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
|
||||
case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, 5); // TODO
|
||||
// TODO does the limited range of valid years cause years to
|
||||
// start/end part way through? that would affect range
|
||||
}
|
||||
return getChronology().range(f);
|
||||
}
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
}
|
||||
return field.rangeRefinedBy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
switch ((ChronoField) field) {
|
||||
case DAY_OF_WEEK: return getDayOfWeek();
|
||||
case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((getDayOfWeek() - 1) % 7) + 1;
|
||||
case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
|
||||
case DAY_OF_MONTH: return this.dayOfMonth;
|
||||
case DAY_OF_YEAR: return this.getDayOfYear();
|
||||
case EPOCH_DAY: return toEpochDay();
|
||||
case ALIGNED_WEEK_OF_MONTH: return ((dayOfMonth - 1) / 7) + 1;
|
||||
case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
|
||||
case MONTH_OF_YEAR: return monthOfYear;
|
||||
case PROLEPTIC_MONTH: return getProlepticMonth();
|
||||
case YEAR_OF_ERA: return prolepticYear;
|
||||
case YEAR: return prolepticYear;
|
||||
case ERA: return getEraValue();
|
||||
}
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
|
||||
private long getProlepticMonth() {
|
||||
return prolepticYear * 12L + monthOfYear - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HijrahDate with(TemporalField field, long newValue) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
// not using checkValidIntValue so EPOCH_DAY and PROLEPTIC_MONTH work
|
||||
chrono.range(f).checkValidValue(newValue, f); // TODO: validate value
|
||||
int nvalue = (int) newValue;
|
||||
switch (f) {
|
||||
case DAY_OF_WEEK: return plusDays(newValue - getDayOfWeek());
|
||||
case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
|
||||
case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
|
||||
case DAY_OF_MONTH: return resolvePreviousValid(prolepticYear, monthOfYear, nvalue);
|
||||
case DAY_OF_YEAR: return plusDays(Math.min(nvalue, lengthOfYear()) - getDayOfYear());
|
||||
case EPOCH_DAY: return new HijrahDate(chrono, newValue);
|
||||
case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7);
|
||||
case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7);
|
||||
case MONTH_OF_YEAR: return resolvePreviousValid(prolepticYear, nvalue, dayOfMonth);
|
||||
case PROLEPTIC_MONTH: return plusMonths(newValue - getProlepticMonth());
|
||||
case YEAR_OF_ERA: return resolvePreviousValid(prolepticYear >= 1 ? nvalue : 1 - nvalue, monthOfYear, dayOfMonth);
|
||||
case YEAR: return resolvePreviousValid(nvalue, monthOfYear, dayOfMonth);
|
||||
case ERA: return resolvePreviousValid(1 - prolepticYear, monthOfYear, dayOfMonth);
|
||||
}
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
}
|
||||
return super.with(field, newValue);
|
||||
}
|
||||
|
||||
private HijrahDate resolvePreviousValid(int prolepticYear, int month, int day) {
|
||||
int monthDays = chrono.getMonthLength(prolepticYear, month);
|
||||
if (day > monthDays) {
|
||||
day = monthDays;
|
||||
}
|
||||
return HijrahDate.of(chrono, prolepticYear, month, day);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException if unable to make the adjustment.
|
||||
* For example, if the adjuster requires an ISO chronology
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public HijrahDate with(TemporalAdjuster adjuster) {
|
||||
return super.with(adjuster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code HijrahDate} with the Chronology requested.
|
||||
* <p>
|
||||
* The year, month, and day are checked against the new requested
|
||||
* HijrahChronology. If the chronology has a shorter month length
|
||||
* for the month, the day is reduced to be the last day of the month.
|
||||
*
|
||||
* @param chronology the new HijrahChonology, non-null
|
||||
* @return a HijrahDate with the requested HijrahChronology, non-null
|
||||
*/
|
||||
public HijrahDate withVariant(HijrahChronology chronology) {
|
||||
if (chrono == chronology) {
|
||||
return this;
|
||||
}
|
||||
// Like resolvePreviousValid the day is constrained to stay in the same month
|
||||
int monthDays = chronology.getDayOfYear(prolepticYear, monthOfYear);
|
||||
return HijrahDate.of(chronology, prolepticYear, monthOfYear,(dayOfMonth > monthDays) ? monthDays : dayOfMonth );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public HijrahDate plus(TemporalAmount amount) {
|
||||
return super.plus(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public HijrahDate minus(TemporalAmount amount) {
|
||||
return super.minus(amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long toEpochDay() {
|
||||
return chrono.getEpochDay(prolepticYear, monthOfYear, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the day-of-year field.
|
||||
* <p>
|
||||
* This method returns the primitive {@code int} value for the day-of-year.
|
||||
*
|
||||
* @return the day-of-year
|
||||
*/
|
||||
private int getDayOfYear() {
|
||||
return chrono.getDayOfYear(prolepticYear, monthOfYear) + dayOfMonth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the day-of-week value.
|
||||
*
|
||||
* @return the day-of-week; computed from the epochday
|
||||
*/
|
||||
private int getDayOfWeek() {
|
||||
int dow0 = (int)Math.floorMod(toEpochDay() + 3, 7);
|
||||
return dow0 + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Era of this date.
|
||||
*
|
||||
* @return the Era of this date; computed from epochDay
|
||||
*/
|
||||
private int getEraValue() {
|
||||
return (prolepticYear > 1 ? 1 : 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if the year is a leap year, according to the Hijrah calendar system rules.
|
||||
*
|
||||
* @return true if this date is in a leap year
|
||||
*/
|
||||
@Override
|
||||
public boolean isLeapYear() {
|
||||
return chrono.isLeapYear(prolepticYear);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
HijrahDate plusYears(long years) {
|
||||
if (years == 0) {
|
||||
return this;
|
||||
}
|
||||
int newYear = Math.addExact(this.prolepticYear, (int)years);
|
||||
return resolvePreviousValid(newYear, monthOfYear, dayOfMonth);
|
||||
}
|
||||
|
||||
@Override
|
||||
HijrahDate plusMonths(long monthsToAdd) {
|
||||
if (monthsToAdd == 0) {
|
||||
return this;
|
||||
}
|
||||
long monthCount = prolepticYear * 12L + (monthOfYear - 1);
|
||||
long calcMonths = monthCount + monthsToAdd; // safe overflow
|
||||
int newYear = chrono.checkValidYear(Math.floorDiv(calcMonths, 12L));
|
||||
int newMonth = (int)Math.floorMod(calcMonths, 12L) + 1;
|
||||
return resolvePreviousValid(newYear, newMonth, dayOfMonth);
|
||||
}
|
||||
|
||||
@Override
|
||||
HijrahDate plusWeeks(long weeksToAdd) {
|
||||
return super.plusWeeks(weeksToAdd);
|
||||
}
|
||||
|
||||
@Override
|
||||
HijrahDate plusDays(long days) {
|
||||
return new HijrahDate(chrono, toEpochDay() + days);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HijrahDate plus(long amountToAdd, TemporalUnit unit) {
|
||||
return super.plus(amountToAdd, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HijrahDate minus(long amountToSubtract, TemporalUnit unit) {
|
||||
return super.minus(amountToSubtract, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
HijrahDate minusYears(long yearsToSubtract) {
|
||||
return super.minusYears(yearsToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
HijrahDate minusMonths(long monthsToSubtract) {
|
||||
return super.minusMonths(monthsToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
HijrahDate minusWeeks(long weeksToSubtract) {
|
||||
return super.minusWeeks(weeksToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
HijrahDate minusDays(long daysToSubtract) {
|
||||
return super.minusDays(daysToSubtract);
|
||||
}
|
||||
|
||||
@Override // for javadoc and covariant return type
|
||||
@SuppressWarnings("unchecked")
|
||||
public final ChronoLocalDateTime<HijrahDate> atTime(LocalTime localTime) {
|
||||
return (ChronoLocalDateTime<HijrahDate>)super.atTime(localTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronoPeriod until(ChronoLocalDate endDate) {
|
||||
// TODO: untested
|
||||
HijrahDate end = getChronology().date(endDate);
|
||||
long totalMonths = (end.prolepticYear - this.prolepticYear) * 12 + (end.monthOfYear - this.monthOfYear); // safe
|
||||
int days = end.dayOfMonth - this.dayOfMonth;
|
||||
if (totalMonths > 0 && days < 0) {
|
||||
totalMonths--;
|
||||
HijrahDate calcDate = this.plusMonths(totalMonths);
|
||||
days = (int) (end.toEpochDay() - calcDate.toEpochDay()); // safe
|
||||
} else if (totalMonths < 0 && days > 0) {
|
||||
totalMonths++;
|
||||
days -= end.lengthOfMonth();
|
||||
}
|
||||
long years = totalMonths / 12; // safe
|
||||
int months = (int) (totalMonths % 12); // safe
|
||||
return getChronology().period(Math.toIntExact(years), months, days);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this date to another date, including the chronology.
|
||||
* <p>
|
||||
* Compares this {@code HijrahDate} with another ensuring that the date is the same.
|
||||
* <p>
|
||||
* Only objects of type {@code HijrahDate} are compared, other types return false.
|
||||
* To compare the dates of two {@code TemporalAccessor} instances, including dates
|
||||
* in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other date and the Chronologies are equal
|
||||
*/
|
||||
@Override // override for performance
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof HijrahDate) {
|
||||
HijrahDate otherDate = (HijrahDate) obj;
|
||||
return prolepticYear == otherDate.prolepticYear
|
||||
&& this.monthOfYear == otherDate.monthOfYear
|
||||
&& this.dayOfMonth == otherDate.dayOfMonth
|
||||
&& getChronology().equals(otherDate.getChronology());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for this date.
|
||||
*
|
||||
* @return a suitable hash code based only on the Chronology and the date
|
||||
*/
|
||||
@Override // override for performance
|
||||
public int hashCode() {
|
||||
int yearValue = prolepticYear;
|
||||
int monthValue = monthOfYear;
|
||||
int dayValue = dayOfMonth;
|
||||
return getChronology().getId().hashCode() ^ (yearValue & 0xFFFFF800)
|
||||
^ ((yearValue << 11) + (monthValue << 6) + (dayValue));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the object using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(6); // identifies a HijrahDate
|
||||
* out.writeObject(chrono); // the HijrahChronology variant
|
||||
* out.writeInt(get(YEAR));
|
||||
* out.writeByte(get(MONTH_OF_YEAR));
|
||||
* out.writeByte(get(DAY_OF_MONTH));
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
private Object writeReplace() {
|
||||
return new Ser(Ser.HIJRAH_DATE_TYPE, this);
|
||||
}
|
||||
|
||||
void writeExternal(ObjectOutput out) throws IOException {
|
||||
// HijrahChronology is implicit in the Hijrah_DATE_TYPE
|
||||
out.writeObject(getChronology());
|
||||
out.writeInt(get(YEAR));
|
||||
out.writeByte(get(MONTH_OF_YEAR));
|
||||
out.writeByte(get(DAY_OF_MONTH));
|
||||
}
|
||||
|
||||
static HijrahDate readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
HijrahChronology chrono = (HijrahChronology) in.readObject();
|
||||
int year = in.readInt();
|
||||
int month = in.readByte();
|
||||
int dayOfMonth = in.readByte();
|
||||
return chrono.date(year, month, dayOfMonth);
|
||||
}
|
||||
|
||||
}
|
||||
158
jdkSrc/jdk8/java/time/chrono/HijrahEra.java
Normal file
158
jdkSrc/jdk8/java/time/chrono/HijrahEra.java
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.ERA;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
|
||||
/**
|
||||
* An era in the Hijrah calendar system.
|
||||
* <p>
|
||||
* The Hijrah calendar system has only one era covering the
|
||||
* proleptic years greater than zero.
|
||||
* <p>
|
||||
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code HijrahEra}.
|
||||
* Use {@code getValue()} instead.</b>
|
||||
*
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public enum HijrahEra implements Era {
|
||||
|
||||
/**
|
||||
* The singleton instance for the current era, 'Anno Hegirae',
|
||||
* which has the numeric value 1.
|
||||
*/
|
||||
AH;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code HijrahEra} from an {@code int} value.
|
||||
* <p>
|
||||
* The current era, which is the only accepted value, has the value 1
|
||||
*
|
||||
* @param hijrahEra the era to represent, only 1 supported
|
||||
* @return the HijrahEra.AH singleton, not null
|
||||
* @throws DateTimeException if the value is invalid
|
||||
*/
|
||||
public static HijrahEra of(int hijrahEra) {
|
||||
if (hijrahEra == 1 ) {
|
||||
return AH;
|
||||
} else {
|
||||
throw new DateTimeException("Invalid era: " + hijrahEra);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the numeric era {@code int} value.
|
||||
* <p>
|
||||
* The era AH has the value 1.
|
||||
*
|
||||
* @return the era value, 1 (AH)
|
||||
*/
|
||||
@Override
|
||||
public int getValue() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the range of valid values for the specified field.
|
||||
* <p>
|
||||
* The range object expresses the minimum and maximum valid values for a field.
|
||||
* This era is used to enhance the accuracy of the returned range.
|
||||
* If it is not possible to return the range, because the field is not supported
|
||||
* or for some other reason, an exception is thrown.
|
||||
* <p>
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@code ERA} field returns the range.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the range can be obtained is determined by the field.
|
||||
* <p>
|
||||
* The {@code ERA} field returns a range for the one valid Hijrah era.
|
||||
*
|
||||
* @param field the field to query the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
*/
|
||||
@Override // override as super would return range from 0 to 1
|
||||
public ValueRange range(TemporalField field) {
|
||||
if (field == ERA) {
|
||||
return ValueRange.of(1, 1);
|
||||
}
|
||||
return Era.super.range(field);
|
||||
}
|
||||
|
||||
}
|
||||
613
jdkSrc/jdk8/java/time/chrono/IsoChronology.java
Normal file
613
jdkSrc/jdk8/java/time/chrono/IsoChronology.java
Normal file
@@ -0,0 +1,613 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.ERA;
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.Clock;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.Month;
|
||||
import java.time.Period;
|
||||
import java.time.Year;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.ResolverStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The ISO calendar system.
|
||||
* <p>
|
||||
* This chronology defines the rules of the ISO calendar system.
|
||||
* This calendar system is based on the ISO-8601 standard, which is the
|
||||
* <i>de facto</i> world calendar.
|
||||
* <p>
|
||||
* The fields are defined as follows:
|
||||
* <ul>
|
||||
* <li>era - There are two eras, 'Current Era' (CE) and 'Before Current Era' (BCE).
|
||||
* <li>year-of-era - The year-of-era is the same as the proleptic-year for the current CE era.
|
||||
* For the BCE era before the ISO epoch the year increases from 1 upwards as time goes backwards.
|
||||
* <li>proleptic-year - The proleptic year is the same as the year-of-era for the
|
||||
* current era. For the previous era, years have zero, then negative values.
|
||||
* <li>month-of-year - There are 12 months in an ISO year, numbered from 1 to 12.
|
||||
* <li>day-of-month - There are between 28 and 31 days in each of the ISO month, numbered from 1 to 31.
|
||||
* Months 4, 6, 9 and 11 have 30 days, Months 1, 3, 5, 7, 8, 10 and 12 have 31 days.
|
||||
* Month 2 has 28 days, or 29 in a leap year.
|
||||
* <li>day-of-year - There are 365 days in a standard ISO year and 366 in a leap year.
|
||||
* The days are numbered from 1 to 365 or 1 to 366.
|
||||
* <li>leap-year - Leap years occur every 4 years, except where the year is divisble by 100 and not divisble by 400.
|
||||
* </ul>
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class IsoChronology extends AbstractChronology implements Serializable {
|
||||
|
||||
/**
|
||||
* Singleton instance of the ISO chronology.
|
||||
*/
|
||||
public static final IsoChronology INSTANCE = new IsoChronology();
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = -1440403870442975015L;
|
||||
|
||||
/**
|
||||
* Restricted constructor.
|
||||
*/
|
||||
private IsoChronology() {
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the ID of the chronology - 'ISO'.
|
||||
* <p>
|
||||
* The ID uniquely identifies the {@code Chronology}.
|
||||
* It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
|
||||
*
|
||||
* @return the chronology ID - 'ISO'
|
||||
* @see #getCalendarType()
|
||||
*/
|
||||
@Override
|
||||
public String getId() {
|
||||
return "ISO";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the calendar type of the underlying calendar system - 'iso8601'.
|
||||
* <p>
|
||||
* The calendar type is an identifier defined by the
|
||||
* <em>Unicode Locale Data Markup Language (LDML)</em> specification.
|
||||
* It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
|
||||
* It can also be used as part of a locale, accessible via
|
||||
* {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
|
||||
*
|
||||
* @return the calendar system type - 'iso8601'
|
||||
* @see #getId()
|
||||
*/
|
||||
@Override
|
||||
public String getCalendarType() {
|
||||
return "iso8601";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an ISO local date from the era, year-of-era, month-of-year
|
||||
* and day-of-month fields.
|
||||
*
|
||||
* @param era the ISO era, not null
|
||||
* @param yearOfEra the ISO year-of-era
|
||||
* @param month the ISO month-of-year
|
||||
* @param dayOfMonth the ISO day-of-month
|
||||
* @return the ISO local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
* @throws ClassCastException if the type of {@code era} is not {@code IsoEra}
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public LocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
|
||||
return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an ISO local date from the proleptic-year, month-of-year
|
||||
* and day-of-month fields.
|
||||
* <p>
|
||||
* This is equivalent to {@link LocalDate#of(int, int, int)}.
|
||||
*
|
||||
* @param prolepticYear the ISO proleptic-year
|
||||
* @param month the ISO month-of-year
|
||||
* @param dayOfMonth the ISO day-of-month
|
||||
* @return the ISO local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public LocalDate date(int prolepticYear, int month, int dayOfMonth) {
|
||||
return LocalDate.of(prolepticYear, month, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an ISO local date from the era, year-of-era and day-of-year fields.
|
||||
*
|
||||
* @param era the ISO era, not null
|
||||
* @param yearOfEra the ISO year-of-era
|
||||
* @param dayOfYear the ISO day-of-year
|
||||
* @return the ISO local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public LocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
|
||||
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an ISO local date from the proleptic-year and day-of-year fields.
|
||||
* <p>
|
||||
* This is equivalent to {@link LocalDate#ofYearDay(int, int)}.
|
||||
*
|
||||
* @param prolepticYear the ISO proleptic-year
|
||||
* @param dayOfYear the ISO day-of-year
|
||||
* @return the ISO local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public LocalDate dateYearDay(int prolepticYear, int dayOfYear) {
|
||||
return LocalDate.ofYearDay(prolepticYear, dayOfYear);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an ISO local date from the epoch-day.
|
||||
* <p>
|
||||
* This is equivalent to {@link LocalDate#ofEpochDay(long)}.
|
||||
*
|
||||
* @param epochDay the epoch day
|
||||
* @return the ISO local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public LocalDate dateEpochDay(long epochDay) {
|
||||
return LocalDate.ofEpochDay(epochDay);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an ISO local date from another date-time object.
|
||||
* <p>
|
||||
* This is equivalent to {@link LocalDate#from(TemporalAccessor)}.
|
||||
*
|
||||
* @param temporal the date-time object to convert, not null
|
||||
* @return the ISO local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public LocalDate date(TemporalAccessor temporal) {
|
||||
return LocalDate.from(temporal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an ISO local date-time from another date-time object.
|
||||
* <p>
|
||||
* This is equivalent to {@link LocalDateTime#from(TemporalAccessor)}.
|
||||
*
|
||||
* @param temporal the date-time object to convert, not null
|
||||
* @return the ISO local date-time, not null
|
||||
* @throws DateTimeException if unable to create the date-time
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public LocalDateTime localDateTime(TemporalAccessor temporal) {
|
||||
return LocalDateTime.from(temporal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an ISO zoned date-time from another date-time object.
|
||||
* <p>
|
||||
* This is equivalent to {@link ZonedDateTime#from(TemporalAccessor)}.
|
||||
*
|
||||
* @param temporal the date-time object to convert, not null
|
||||
* @return the ISO zoned date-time, not null
|
||||
* @throws DateTimeException if unable to create the date-time
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public ZonedDateTime zonedDateTime(TemporalAccessor temporal) {
|
||||
return ZonedDateTime.from(temporal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an ISO zoned date-time in this chronology from an {@code Instant}.
|
||||
* <p>
|
||||
* This is equivalent to {@link ZonedDateTime#ofInstant(Instant, ZoneId)}.
|
||||
*
|
||||
* @param instant the instant to create the date-time from, not null
|
||||
* @param zone the time-zone, not null
|
||||
* @return the zoned date-time, not null
|
||||
* @throws DateTimeException if the result exceeds the supported range
|
||||
*/
|
||||
@Override
|
||||
public ZonedDateTime zonedDateTime(Instant instant, ZoneId zone) {
|
||||
return ZonedDateTime.ofInstant(instant, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains the current ISO local date from the system clock in the default time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
|
||||
* time-zone to obtain the current date.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @return the current ISO local date using the system clock and default time-zone, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public LocalDate dateNow() {
|
||||
return dateNow(Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current ISO local date from the system clock in the specified time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
|
||||
* Specifying the time-zone avoids dependence on the default time-zone.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @return the current ISO local date using the system clock, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public LocalDate dateNow(ZoneId zone) {
|
||||
return dateNow(Clock.system(zone));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current ISO local date from the specified clock.
|
||||
* <p>
|
||||
* This will query the specified clock to obtain the current date - today.
|
||||
* Using this method allows the use of an alternate clock for testing.
|
||||
* The alternate clock may be introduced using {@link Clock dependency injection}.
|
||||
*
|
||||
* @param clock the clock to use, not null
|
||||
* @return the current ISO local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public LocalDate dateNow(Clock clock) {
|
||||
Objects.requireNonNull(clock, "clock");
|
||||
return date(LocalDate.now(clock));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if the year is a leap year, according to the ISO proleptic
|
||||
* calendar system rules.
|
||||
* <p>
|
||||
* This method applies the current rules for leap years across the whole time-line.
|
||||
* In general, a year is a leap year if it is divisible by four without
|
||||
* remainder. However, years divisible by 100, are not leap years, with
|
||||
* the exception of years divisible by 400 which are.
|
||||
* <p>
|
||||
* For example, 1904 is a leap year it is divisible by 4.
|
||||
* 1900 was not a leap year as it is divisible by 100, however 2000 was a
|
||||
* leap year as it is divisible by 400.
|
||||
* <p>
|
||||
* The calculation is proleptic - applying the same rules into the far future and far past.
|
||||
* This is historically inaccurate, but is correct for the ISO-8601 standard.
|
||||
*
|
||||
* @param prolepticYear the ISO proleptic year to check
|
||||
* @return true if the year is leap, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean isLeapYear(long prolepticYear) {
|
||||
return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int prolepticYear(Era era, int yearOfEra) {
|
||||
if (era instanceof IsoEra == false) {
|
||||
throw new ClassCastException("Era must be IsoEra");
|
||||
}
|
||||
return (era == IsoEra.CE ? yearOfEra : 1 - yearOfEra);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsoEra eraOf(int eraValue) {
|
||||
return IsoEra.of(eraValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Era> eras() {
|
||||
return Arrays.<Era>asList(IsoEra.values());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Resolves parsed {@code ChronoField} values into a date during parsing.
|
||||
* <p>
|
||||
* Most {@code TemporalField} implementations are resolved using the
|
||||
* resolve method on the field. By contrast, the {@code ChronoField} class
|
||||
* defines fields that only have meaning relative to the chronology.
|
||||
* As such, {@code ChronoField} date fields are resolved here in the
|
||||
* context of a specific chronology.
|
||||
* <p>
|
||||
* {@code ChronoField} instances on the ISO calendar system are resolved
|
||||
* as follows.
|
||||
* <ul>
|
||||
* <li>{@code EPOCH_DAY} - If present, this is converted to a {@code LocalDate}
|
||||
* and all other date fields are then cross-checked against the date.
|
||||
* <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the
|
||||
* {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart
|
||||
* then the field is validated.
|
||||
* <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they
|
||||
* are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA}
|
||||
* range is not validated, in smart and strict mode it is. The {@code ERA} is
|
||||
* validated for range in all three modes. If only the {@code YEAR_OF_ERA} is
|
||||
* present, and the mode is smart or lenient, then the current era (CE/AD)
|
||||
* is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is
|
||||
* left untouched. If only the {@code ERA} is present, then it is left untouched.
|
||||
* <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} -
|
||||
* If all three are present, then they are combined to form a {@code LocalDate}.
|
||||
* In all three modes, the {@code YEAR} is validated. If the mode is smart or strict,
|
||||
* then the month and day are validated, with the day validated from 1 to 31.
|
||||
* If the mode is lenient, then the date is combined in a manner equivalent to
|
||||
* creating a date on the first of January in the requested year, then adding
|
||||
* the difference in months, then the difference in days.
|
||||
* If the mode is smart, and the day-of-month is greater than the maximum for
|
||||
* the year-month, then the day-of-month is adjusted to the last day-of-month.
|
||||
* If the mode is strict, then the three fields must form a valid date.
|
||||
* <li>{@code YEAR} and {@code DAY_OF_YEAR} -
|
||||
* If both are present, then they are combined to form a {@code LocalDate}.
|
||||
* In all three modes, the {@code YEAR} is validated.
|
||||
* If the mode is lenient, then the date is combined in a manner equivalent to
|
||||
* creating a date on the first of January in the requested year, then adding
|
||||
* the difference in days.
|
||||
* If the mode is smart or strict, then the two fields must form a valid date.
|
||||
* <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
|
||||
* {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
|
||||
* If all four are present, then they are combined to form a {@code LocalDate}.
|
||||
* In all three modes, the {@code YEAR} is validated.
|
||||
* If the mode is lenient, then the date is combined in a manner equivalent to
|
||||
* creating a date on the first of January in the requested year, then adding
|
||||
* the difference in months, then the difference in weeks, then in days.
|
||||
* If the mode is smart or strict, then the all four fields are validated to
|
||||
* their outer ranges. The date is then combined in a manner equivalent to
|
||||
* creating a date on the first day of the requested year and month, then adding
|
||||
* the amount in weeks and days to reach their values. If the mode is strict,
|
||||
* the date is additionally validated to check that the day and week adjustment
|
||||
* did not change the month.
|
||||
* <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
|
||||
* {@code DAY_OF_WEEK} - If all four are present, then they are combined to
|
||||
* form a {@code LocalDate}. The approach is the same as described above for
|
||||
* years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}.
|
||||
* The day-of-week is adjusted as the next or same matching day-of-week once
|
||||
* the years, months and weeks have been handled.
|
||||
* <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
|
||||
* If all three are present, then they are combined to form a {@code LocalDate}.
|
||||
* In all three modes, the {@code YEAR} is validated.
|
||||
* If the mode is lenient, then the date is combined in a manner equivalent to
|
||||
* creating a date on the first of January in the requested year, then adding
|
||||
* the difference in weeks, then in days.
|
||||
* If the mode is smart or strict, then the all three fields are validated to
|
||||
* their outer ranges. The date is then combined in a manner equivalent to
|
||||
* creating a date on the first day of the requested year, then adding
|
||||
* the amount in weeks and days to reach their values. If the mode is strict,
|
||||
* the date is additionally validated to check that the day and week adjustment
|
||||
* did not change the year.
|
||||
* <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} -
|
||||
* If all three are present, then they are combined to form a {@code LocalDate}.
|
||||
* The approach is the same as described above for years and weeks in
|
||||
* {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the
|
||||
* next or same matching day-of-week once the years and weeks have been handled.
|
||||
* </ul>
|
||||
*
|
||||
* @param fieldValues the map of fields to values, which can be updated, not null
|
||||
* @param resolverStyle the requested type of resolve, not null
|
||||
* @return the resolved date, null if insufficient information to create a date
|
||||
* @throws DateTimeException if the date cannot be resolved, typically
|
||||
* because of a conflict in the input data
|
||||
*/
|
||||
@Override // override for performance
|
||||
public LocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
return (LocalDate) super.resolveDate(fieldValues, resolverStyle);
|
||||
}
|
||||
|
||||
@Override // override for better proleptic algorithm
|
||||
void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
Long pMonth = fieldValues.remove(PROLEPTIC_MONTH);
|
||||
if (pMonth != null) {
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
PROLEPTIC_MONTH.checkValidValue(pMonth);
|
||||
}
|
||||
addFieldValue(fieldValues, MONTH_OF_YEAR, Math.floorMod(pMonth, 12) + 1);
|
||||
addFieldValue(fieldValues, YEAR, Math.floorDiv(pMonth, 12));
|
||||
}
|
||||
}
|
||||
|
||||
@Override // override for enhanced behaviour
|
||||
LocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
Long yoeLong = fieldValues.remove(YEAR_OF_ERA);
|
||||
if (yoeLong != null) {
|
||||
if (resolverStyle != ResolverStyle.LENIENT) {
|
||||
YEAR_OF_ERA.checkValidValue(yoeLong);
|
||||
}
|
||||
Long era = fieldValues.remove(ERA);
|
||||
if (era == null) {
|
||||
Long year = fieldValues.get(YEAR);
|
||||
if (resolverStyle == ResolverStyle.STRICT) {
|
||||
// do not invent era if strict, but do cross-check with year
|
||||
if (year != null) {
|
||||
addFieldValue(fieldValues, YEAR, (year > 0 ? yoeLong: Math.subtractExact(1, yoeLong)));
|
||||
} else {
|
||||
// reinstate the field removed earlier, no cross-check issues
|
||||
fieldValues.put(YEAR_OF_ERA, yoeLong);
|
||||
}
|
||||
} else {
|
||||
// invent era
|
||||
addFieldValue(fieldValues, YEAR, (year == null || year > 0 ? yoeLong: Math.subtractExact(1, yoeLong)));
|
||||
}
|
||||
} else if (era.longValue() == 1L) {
|
||||
addFieldValue(fieldValues, YEAR, yoeLong);
|
||||
} else if (era.longValue() == 0L) {
|
||||
addFieldValue(fieldValues, YEAR, Math.subtractExact(1, yoeLong));
|
||||
} else {
|
||||
throw new DateTimeException("Invalid value for era: " + era);
|
||||
}
|
||||
} else if (fieldValues.containsKey(ERA)) {
|
||||
ERA.checkValidValue(fieldValues.get(ERA)); // always validated
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override // override for performance
|
||||
LocalDate resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
|
||||
long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
|
||||
return LocalDate.of(y, 1, 1).plusMonths(months).plusDays(days);
|
||||
}
|
||||
int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR));
|
||||
int dom = DAY_OF_MONTH.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH));
|
||||
if (resolverStyle == ResolverStyle.SMART) { // previous valid
|
||||
if (moy == 4 || moy == 6 || moy == 9 || moy == 11) {
|
||||
dom = Math.min(dom, 30);
|
||||
} else if (moy == 2) {
|
||||
dom = Math.min(dom, Month.FEBRUARY.length(Year.isLeap(y)));
|
||||
|
||||
}
|
||||
}
|
||||
return LocalDate.of(y, moy, dom);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ValueRange range(ChronoField field) {
|
||||
return field.range();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a period for this chronology based on years, months and days.
|
||||
* <p>
|
||||
* This returns a period tied to the ISO chronology using the specified
|
||||
* years, months and days. See {@link Period} for further details.
|
||||
*
|
||||
* @param years the number of years, may be negative
|
||||
* @param months the number of years, may be negative
|
||||
* @param days the number of years, may be negative
|
||||
* @return the period in terms of this chronology, not null
|
||||
* @return the ISO period, not null
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public Period period(int years, int months, int days) {
|
||||
return Period.of(years, months, days);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the Chronology using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(1); // identifies a Chronology
|
||||
* out.writeUTF(getId());
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
@Override
|
||||
Object writeReplace() {
|
||||
return super.writeReplace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
}
|
||||
153
jdkSrc/jdk8/java/time/chrono/IsoEra.java
Normal file
153
jdkSrc/jdk8/java/time/chrono/IsoEra.java
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
|
||||
/**
|
||||
* An era in the ISO calendar system.
|
||||
* <p>
|
||||
* The ISO-8601 standard does not define eras.
|
||||
* A definition has therefore been created with two eras - 'Current era' (CE) for
|
||||
* years on or after 0001-01-01 (ISO), and 'Before current era' (BCE) for years before that.
|
||||
*
|
||||
* <table summary="ISO years and eras" cellpadding="2" cellspacing="3" border="0" >
|
||||
* <thead>
|
||||
* <tr class="tableSubHeadingColor">
|
||||
* <th class="colFirst" align="left">year-of-era</th>
|
||||
* <th class="colFirst" align="left">era</th>
|
||||
* <th class="colLast" align="left">proleptic-year</th>
|
||||
* </tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr class="rowColor">
|
||||
* <td>2</td><td>CE</td><td>2</td>
|
||||
* </tr>
|
||||
* <tr class="altColor">
|
||||
* <td>1</td><td>CE</td><td>1</td>
|
||||
* </tr>
|
||||
* <tr class="rowColor">
|
||||
* <td>1</td><td>BCE</td><td>0</td>
|
||||
* </tr>
|
||||
* <tr class="altColor">
|
||||
* <td>2</td><td>BCE</td><td>-1</td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* <p>
|
||||
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code IsoEra}.
|
||||
* Use {@code getValue()} instead.</b>
|
||||
*
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public enum IsoEra implements Era {
|
||||
|
||||
/**
|
||||
* The singleton instance for the era before the current one, 'Before Current Era',
|
||||
* which has the numeric value 0.
|
||||
*/
|
||||
BCE,
|
||||
/**
|
||||
* The singleton instance for the current era, 'Current Era',
|
||||
* which has the numeric value 1.
|
||||
*/
|
||||
CE;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code IsoEra} from an {@code int} value.
|
||||
* <p>
|
||||
* {@code IsoEra} is an enum representing the ISO eras of BCE/CE.
|
||||
* This factory allows the enum to be obtained from the {@code int} value.
|
||||
*
|
||||
* @param isoEra the BCE/CE value to represent, from 0 (BCE) to 1 (CE)
|
||||
* @return the era singleton, not null
|
||||
* @throws DateTimeException if the value is invalid
|
||||
*/
|
||||
public static IsoEra of(int isoEra) {
|
||||
switch (isoEra) {
|
||||
case 0:
|
||||
return BCE;
|
||||
case 1:
|
||||
return CE;
|
||||
default:
|
||||
throw new DateTimeException("Invalid era: " + isoEra);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the numeric era {@code int} value.
|
||||
* <p>
|
||||
* The era BCE has the value 0, while the era CE has the value 1.
|
||||
*
|
||||
* @return the era value, from 0 (BCE) to 1 (CE)
|
||||
*/
|
||||
@Override
|
||||
public int getValue() {
|
||||
return ordinal();
|
||||
}
|
||||
|
||||
}
|
||||
534
jdkSrc/jdk8/java/time/chrono/JapaneseChronology.java
Normal file
534
jdkSrc/jdk8/java/time/chrono/JapaneseChronology.java
Normal file
@@ -0,0 +1,534 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.DAY_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.ERA;
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
|
||||
import static java.time.temporal.ChronoUnit.DAYS;
|
||||
import static java.time.temporal.ChronoUnit.MONTHS;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.Clock;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Year;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.ResolverStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import sun.util.calendar.CalendarSystem;
|
||||
import sun.util.calendar.LocalGregorianCalendar;
|
||||
|
||||
/**
|
||||
* The Japanese Imperial calendar system.
|
||||
* <p>
|
||||
* This chronology defines the rules of the Japanese Imperial calendar system.
|
||||
* This calendar system is primarily used in Japan.
|
||||
* The Japanese Imperial calendar system is the same as the ISO calendar system
|
||||
* apart from the era-based year numbering.
|
||||
* <p>
|
||||
* Japan introduced the Gregorian calendar starting with Meiji 6.
|
||||
* Only Meiji and later eras are supported;
|
||||
* dates before Meiji 6, January 1 are not supported.
|
||||
* <p>
|
||||
* The supported {@code ChronoField} instances are:
|
||||
* <ul>
|
||||
* <li>{@code DAY_OF_WEEK}
|
||||
* <li>{@code DAY_OF_MONTH}
|
||||
* <li>{@code DAY_OF_YEAR}
|
||||
* <li>{@code EPOCH_DAY}
|
||||
* <li>{@code MONTH_OF_YEAR}
|
||||
* <li>{@code PROLEPTIC_MONTH}
|
||||
* <li>{@code YEAR_OF_ERA}
|
||||
* <li>{@code YEAR}
|
||||
* <li>{@code ERA}
|
||||
* </ul>
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class JapaneseChronology extends AbstractChronology implements Serializable {
|
||||
|
||||
static final LocalGregorianCalendar JCAL =
|
||||
(LocalGregorianCalendar) CalendarSystem.forName("japanese");
|
||||
|
||||
// Locale for creating a JapaneseImpericalCalendar.
|
||||
static final Locale LOCALE = Locale.forLanguageTag("ja-JP-u-ca-japanese");
|
||||
|
||||
/**
|
||||
* Singleton instance for Japanese chronology.
|
||||
*/
|
||||
public static final JapaneseChronology INSTANCE = new JapaneseChronology();
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = 459996390165777884L;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Restricted constructor.
|
||||
*/
|
||||
private JapaneseChronology() {
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the ID of the chronology - 'Japanese'.
|
||||
* <p>
|
||||
* The ID uniquely identifies the {@code Chronology}.
|
||||
* It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
|
||||
*
|
||||
* @return the chronology ID - 'Japanese'
|
||||
* @see #getCalendarType()
|
||||
*/
|
||||
@Override
|
||||
public String getId() {
|
||||
return "Japanese";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the calendar type of the underlying calendar system - 'japanese'.
|
||||
* <p>
|
||||
* The calendar type is an identifier defined by the
|
||||
* <em>Unicode Locale Data Markup Language (LDML)</em> specification.
|
||||
* It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
|
||||
* It can also be used as part of a locale, accessible via
|
||||
* {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
|
||||
*
|
||||
* @return the calendar system type - 'japanese'
|
||||
* @see #getId()
|
||||
*/
|
||||
@Override
|
||||
public String getCalendarType() {
|
||||
return "japanese";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a local date in Japanese calendar system from the
|
||||
* era, year-of-era, month-of-year and day-of-month fields.
|
||||
* <p>
|
||||
* The Japanese month and day-of-month are the same as those in the
|
||||
* ISO calendar system. They are not reset when the era changes.
|
||||
* For example:
|
||||
* <pre>
|
||||
* 6th Jan Showa 64 = ISO 1989-01-06
|
||||
* 7th Jan Showa 64 = ISO 1989-01-07
|
||||
* 8th Jan Heisei 1 = ISO 1989-01-08
|
||||
* 9th Jan Heisei 1 = ISO 1989-01-09
|
||||
* </pre>
|
||||
*
|
||||
* @param era the Japanese era, not null
|
||||
* @param yearOfEra the year-of-era
|
||||
* @param month the month-of-year
|
||||
* @param dayOfMonth the day-of-month
|
||||
* @return the Japanese local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
* @throws ClassCastException if the {@code era} is not a {@code JapaneseEra}
|
||||
*/
|
||||
@Override
|
||||
public JapaneseDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
|
||||
if (era instanceof JapaneseEra == false) {
|
||||
throw new ClassCastException("Era must be JapaneseEra");
|
||||
}
|
||||
return JapaneseDate.of((JapaneseEra) era, yearOfEra, month, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in Japanese calendar system from the
|
||||
* proleptic-year, month-of-year and day-of-month fields.
|
||||
* <p>
|
||||
* The Japanese proleptic year, month and day-of-month are the same as those
|
||||
* in the ISO calendar system. They are not reset when the era changes.
|
||||
*
|
||||
* @param prolepticYear the proleptic-year
|
||||
* @param month the month-of-year
|
||||
* @param dayOfMonth the day-of-month
|
||||
* @return the Japanese local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override
|
||||
public JapaneseDate date(int prolepticYear, int month, int dayOfMonth) {
|
||||
return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in Japanese calendar system from the
|
||||
* era, year-of-era and day-of-year fields.
|
||||
* <p>
|
||||
* The day-of-year in this factory is expressed relative to the start of the year-of-era.
|
||||
* This definition changes the normal meaning of day-of-year only in those years
|
||||
* where the year-of-era is reset to one due to a change in the era.
|
||||
* For example:
|
||||
* <pre>
|
||||
* 6th Jan Showa 64 = day-of-year 6
|
||||
* 7th Jan Showa 64 = day-of-year 7
|
||||
* 8th Jan Heisei 1 = day-of-year 1
|
||||
* 9th Jan Heisei 1 = day-of-year 2
|
||||
* </pre>
|
||||
*
|
||||
* @param era the Japanese era, not null
|
||||
* @param yearOfEra the year-of-era
|
||||
* @param dayOfYear the day-of-year
|
||||
* @return the Japanese local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
* @throws ClassCastException if the {@code era} is not a {@code JapaneseEra}
|
||||
*/
|
||||
@Override
|
||||
public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
|
||||
return JapaneseDate.ofYearDay((JapaneseEra) era, yearOfEra, dayOfYear);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in Japanese calendar system from the
|
||||
* proleptic-year and day-of-year fields.
|
||||
* <p>
|
||||
* The day-of-year in this factory is expressed relative to the start of the proleptic year.
|
||||
* The Japanese proleptic year and day-of-year are the same as those in the ISO calendar system.
|
||||
* They are not reset when the era changes.
|
||||
*
|
||||
* @param prolepticYear the proleptic-year
|
||||
* @param dayOfYear the day-of-year
|
||||
* @return the Japanese local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override
|
||||
public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) {
|
||||
return new JapaneseDate(LocalDate.ofYearDay(prolepticYear, dayOfYear));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in the Japanese calendar system from the epoch-day.
|
||||
*
|
||||
* @param epochDay the epoch day
|
||||
* @return the Japanese local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public JapaneseDate dateEpochDay(long epochDay) {
|
||||
return new JapaneseDate(LocalDate.ofEpochDay(epochDay));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JapaneseDate dateNow() {
|
||||
return dateNow(Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JapaneseDate dateNow(ZoneId zone) {
|
||||
return dateNow(Clock.system(zone));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JapaneseDate dateNow(Clock clock) {
|
||||
return date(LocalDate.now(clock));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JapaneseDate date(TemporalAccessor temporal) {
|
||||
if (temporal instanceof JapaneseDate) {
|
||||
return (JapaneseDate) temporal;
|
||||
}
|
||||
return new JapaneseDate(LocalDate.from(temporal));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoLocalDateTime<JapaneseDate> localDateTime(TemporalAccessor temporal) {
|
||||
return (ChronoLocalDateTime<JapaneseDate>)super.localDateTime(temporal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoZonedDateTime<JapaneseDate> zonedDateTime(TemporalAccessor temporal) {
|
||||
return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(temporal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoZonedDateTime<JapaneseDate> zonedDateTime(Instant instant, ZoneId zone) {
|
||||
return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(instant, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if the specified year is a leap year.
|
||||
* <p>
|
||||
* Japanese calendar leap years occur exactly in line with ISO leap years.
|
||||
* This method does not validate the year passed in, and only has a
|
||||
* well-defined result for years in the supported range.
|
||||
*
|
||||
* @param prolepticYear the proleptic-year to check, not validated for range
|
||||
* @return true if the year is a leap year
|
||||
*/
|
||||
@Override
|
||||
public boolean isLeapYear(long prolepticYear) {
|
||||
return IsoChronology.INSTANCE.isLeapYear(prolepticYear);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int prolepticYear(Era era, int yearOfEra) {
|
||||
if (era instanceof JapaneseEra == false) {
|
||||
throw new ClassCastException("Era must be JapaneseEra");
|
||||
}
|
||||
|
||||
JapaneseEra jera = (JapaneseEra) era;
|
||||
int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
|
||||
if (yearOfEra == 1) {
|
||||
return gregorianYear;
|
||||
}
|
||||
if (gregorianYear >= Year.MIN_VALUE && gregorianYear <= Year.MAX_VALUE) {
|
||||
LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null);
|
||||
jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1);
|
||||
if (JapaneseChronology.JCAL.validate(jdate)) {
|
||||
return gregorianYear;
|
||||
}
|
||||
}
|
||||
throw new DateTimeException("Invalid yearOfEra value");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the calendar system era object from the given numeric value.
|
||||
*
|
||||
* See the description of each Era for the numeric values of:
|
||||
* {@link JapaneseEra#HEISEI}, {@link JapaneseEra#SHOWA},{@link JapaneseEra#TAISHO},
|
||||
* {@link JapaneseEra#MEIJI}), only Meiji and later eras are supported.
|
||||
*
|
||||
* @param eraValue the era value
|
||||
* @return the Japanese {@code Era} for the given numeric era value
|
||||
* @throws DateTimeException if {@code eraValue} is invalid
|
||||
*/
|
||||
@Override
|
||||
public JapaneseEra eraOf(int eraValue) {
|
||||
return JapaneseEra.of(eraValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Era> eras() {
|
||||
return Arrays.<Era>asList(JapaneseEra.values());
|
||||
}
|
||||
|
||||
JapaneseEra getCurrentEra() {
|
||||
// Assume that the last JapaneseEra is the current one.
|
||||
JapaneseEra[] eras = JapaneseEra.values();
|
||||
return eras[eras.length - 1];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ValueRange range(ChronoField field) {
|
||||
switch (field) {
|
||||
case ALIGNED_DAY_OF_WEEK_IN_MONTH:
|
||||
case ALIGNED_DAY_OF_WEEK_IN_YEAR:
|
||||
case ALIGNED_WEEK_OF_MONTH:
|
||||
case ALIGNED_WEEK_OF_YEAR:
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
case YEAR_OF_ERA: {
|
||||
Calendar jcal = Calendar.getInstance(LOCALE);
|
||||
int startYear = getCurrentEra().getPrivateEra().getSinceDate().getYear();
|
||||
return ValueRange.of(1, jcal.getGreatestMinimum(Calendar.YEAR),
|
||||
jcal.getLeastMaximum(Calendar.YEAR) + 1, // +1 due to the different definitions
|
||||
Year.MAX_VALUE - startYear);
|
||||
}
|
||||
case DAY_OF_YEAR: {
|
||||
Calendar jcal = Calendar.getInstance(LOCALE);
|
||||
int fieldIndex = Calendar.DAY_OF_YEAR;
|
||||
return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex),
|
||||
jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex));
|
||||
}
|
||||
case YEAR:
|
||||
return ValueRange.of(JapaneseDate.MEIJI_6_ISODATE.getYear(), Year.MAX_VALUE);
|
||||
case ERA:
|
||||
return ValueRange.of(JapaneseEra.MEIJI.getValue(), getCurrentEra().getValue());
|
||||
default:
|
||||
return field.range();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override // override for return type
|
||||
public JapaneseDate resolveDate(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
return (JapaneseDate) super.resolveDate(fieldValues, resolverStyle);
|
||||
}
|
||||
|
||||
@Override // override for special Japanese behavior
|
||||
ChronoLocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
// validate era and year-of-era
|
||||
Long eraLong = fieldValues.get(ERA);
|
||||
JapaneseEra era = null;
|
||||
if (eraLong != null) {
|
||||
era = eraOf(range(ERA).checkValidIntValue(eraLong, ERA)); // always validated
|
||||
}
|
||||
Long yoeLong = fieldValues.get(YEAR_OF_ERA);
|
||||
int yoe = 0;
|
||||
if (yoeLong != null) {
|
||||
yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); // always validated
|
||||
}
|
||||
// if only year-of-era and no year then invent era unless strict
|
||||
if (era == null && yoeLong != null && fieldValues.containsKey(YEAR) == false && resolverStyle != ResolverStyle.STRICT) {
|
||||
era = JapaneseEra.values()[JapaneseEra.values().length - 1];
|
||||
}
|
||||
// if both present, then try to create date
|
||||
if (yoeLong != null && era != null) {
|
||||
if (fieldValues.containsKey(MONTH_OF_YEAR)) {
|
||||
if (fieldValues.containsKey(DAY_OF_MONTH)) {
|
||||
return resolveYMD(era, yoe, fieldValues, resolverStyle);
|
||||
}
|
||||
}
|
||||
if (fieldValues.containsKey(DAY_OF_YEAR)) {
|
||||
return resolveYD(era, yoe, fieldValues, resolverStyle);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int prolepticYearLenient(JapaneseEra era, int yearOfEra) {
|
||||
return era.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
|
||||
}
|
||||
|
||||
private ChronoLocalDate resolveYMD(JapaneseEra era, int yoe, Map<TemporalField,Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
fieldValues.remove(ERA);
|
||||
fieldValues.remove(YEAR_OF_ERA);
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
int y = prolepticYearLenient(era, yoe);
|
||||
long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
|
||||
long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
|
||||
return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS);
|
||||
}
|
||||
int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
|
||||
int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH);
|
||||
if (resolverStyle == ResolverStyle.SMART) { // previous valid
|
||||
if (yoe < 1) {
|
||||
throw new DateTimeException("Invalid YearOfEra: " + yoe);
|
||||
}
|
||||
int y = prolepticYearLenient(era, yoe);
|
||||
JapaneseDate result;
|
||||
try {
|
||||
result = date(y, moy, dom);
|
||||
} catch (DateTimeException ex) {
|
||||
result = date(y, moy, 1).with(TemporalAdjusters.lastDayOfMonth());
|
||||
}
|
||||
// handle the era being changed
|
||||
// only allow if the new date is in the same Jan-Dec as the era change
|
||||
// determine by ensuring either original yoe or result yoe is 1
|
||||
if (result.getEra() != era && result.get(YEAR_OF_ERA) > 1 && yoe > 1) {
|
||||
throw new DateTimeException("Invalid YearOfEra for Era: " + era + " " + yoe);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return date(era, yoe, moy, dom);
|
||||
}
|
||||
|
||||
private ChronoLocalDate resolveYD(JapaneseEra era, int yoe, Map <TemporalField,Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
fieldValues.remove(ERA);
|
||||
fieldValues.remove(YEAR_OF_ERA);
|
||||
if (resolverStyle == ResolverStyle.LENIENT) {
|
||||
int y = prolepticYearLenient(era, yoe);
|
||||
long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1);
|
||||
return dateYearDay(y, 1).plus(days, DAYS);
|
||||
}
|
||||
int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR);
|
||||
return dateYearDay(era, yoe, doy); // smart is same as strict
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the Chronology using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(1); // identifies a Chronology
|
||||
* out.writeUTF(getId());
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
@Override
|
||||
Object writeReplace() {
|
||||
return super.writeReplace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
}
|
||||
757
jdkSrc/jdk8/java/time/chrono/JapaneseDate.java
Normal file
757
jdkSrc/jdk8/java/time/chrono/JapaneseDate.java
Normal file
@@ -0,0 +1,757 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
|
||||
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
|
||||
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.Clock;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Period;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Calendar;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.util.calendar.CalendarDate;
|
||||
import sun.util.calendar.LocalGregorianCalendar;
|
||||
|
||||
/**
|
||||
* A date in the Japanese Imperial calendar system.
|
||||
* <p>
|
||||
* This date operates using the {@linkplain JapaneseChronology Japanese Imperial calendar}.
|
||||
* This calendar system is primarily used in Japan.
|
||||
* <p>
|
||||
* The Japanese Imperial calendar system is the same as the ISO calendar system
|
||||
* apart from the era-based year numbering. The proleptic-year is defined to be
|
||||
* equal to the ISO proleptic-year.
|
||||
* <p>
|
||||
* Japan introduced the Gregorian calendar starting with Meiji 6.
|
||||
* Only Meiji and later eras are supported;
|
||||
* dates before Meiji 6, January 1 are not supported.
|
||||
* <p>
|
||||
* For example, the Japanese year "Heisei 24" corresponds to ISO year "2012".<br>
|
||||
* Calling {@code japaneseDate.get(YEAR_OF_ERA)} will return 24.<br>
|
||||
* Calling {@code japaneseDate.get(YEAR)} will return 2012.<br>
|
||||
* Calling {@code japaneseDate.get(ERA)} will return 2, corresponding to
|
||||
* {@code JapaneseChronology.ERA_HEISEI}.<br>
|
||||
*
|
||||
* <p>
|
||||
* This is a <a href="{@docRoot}/java/lang/doc-files/ValueBased.html">value-based</a>
|
||||
* class; use of identity-sensitive operations (including reference equality
|
||||
* ({@code ==}), identity hash code, or synchronization) on instances of
|
||||
* {@code JapaneseDate} may have unpredictable results and should be avoided.
|
||||
* The {@code equals} method should be used for comparisons.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class JapaneseDate
|
||||
extends ChronoLocalDateImpl<JapaneseDate>
|
||||
implements ChronoLocalDate, Serializable {
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = -305327627230580483L;
|
||||
|
||||
/**
|
||||
* The underlying ISO local date.
|
||||
*/
|
||||
private final transient LocalDate isoDate;
|
||||
/**
|
||||
* The JapaneseEra of this date.
|
||||
*/
|
||||
private transient JapaneseEra era;
|
||||
/**
|
||||
* The Japanese imperial calendar year of this date.
|
||||
*/
|
||||
private transient int yearOfEra;
|
||||
|
||||
/**
|
||||
* The first day supported by the JapaneseChronology is Meiji 6, January 1st.
|
||||
*/
|
||||
static final LocalDate MEIJI_6_ISODATE = LocalDate.of(1873, 1, 1);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains the current {@code JapaneseDate} from the system clock in the default time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
|
||||
* time-zone to obtain the current date.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @return the current date using the system clock and default time-zone, not null
|
||||
*/
|
||||
public static JapaneseDate now() {
|
||||
return now(Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current {@code JapaneseDate} from the system clock in the specified time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
|
||||
* Specifying the time-zone avoids dependence on the default time-zone.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @param zone the zone ID to use, not null
|
||||
* @return the current date using the system clock, not null
|
||||
*/
|
||||
public static JapaneseDate now(ZoneId zone) {
|
||||
return now(Clock.system(zone));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current {@code JapaneseDate} from the specified clock.
|
||||
* <p>
|
||||
* This will query the specified clock to obtain the current date - today.
|
||||
* Using this method allows the use of an alternate clock for testing.
|
||||
* The alternate clock may be introduced using {@linkplain Clock dependency injection}.
|
||||
*
|
||||
* @param clock the clock to use, not null
|
||||
* @return the current date, not null
|
||||
* @throws DateTimeException if the current date cannot be obtained
|
||||
*/
|
||||
public static JapaneseDate now(Clock clock) {
|
||||
return new JapaneseDate(LocalDate.now(clock));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
|
||||
* system from the era, year-of-era, month-of-year and day-of-month fields.
|
||||
* <p>
|
||||
* This returns a {@code JapaneseDate} with the specified fields.
|
||||
* The day must be valid for the year and month, otherwise an exception will be thrown.
|
||||
* <p>
|
||||
* The Japanese month and day-of-month are the same as those in the
|
||||
* ISO calendar system. They are not reset when the era changes.
|
||||
* For example:
|
||||
* <pre>
|
||||
* 6th Jan Showa 64 = ISO 1989-01-06
|
||||
* 7th Jan Showa 64 = ISO 1989-01-07
|
||||
* 8th Jan Heisei 1 = ISO 1989-01-08
|
||||
* 9th Jan Heisei 1 = ISO 1989-01-09
|
||||
* </pre>
|
||||
*
|
||||
* @param era the Japanese era, not null
|
||||
* @param yearOfEra the Japanese year-of-era
|
||||
* @param month the Japanese month-of-year, from 1 to 12
|
||||
* @param dayOfMonth the Japanese day-of-month, from 1 to 31
|
||||
* @return the date in Japanese calendar system, not null
|
||||
* @throws DateTimeException if the value of any field is out of range,
|
||||
* or if the day-of-month is invalid for the month-year,
|
||||
* or if the date is not a Japanese era
|
||||
*/
|
||||
public static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) {
|
||||
Objects.requireNonNull(era, "era");
|
||||
LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
|
||||
jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth);
|
||||
if (!JapaneseChronology.JCAL.validate(jdate)) {
|
||||
throw new DateTimeException("year, month, and day not valid for Era");
|
||||
}
|
||||
LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth);
|
||||
return new JapaneseDate(era, yearOfEra, date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
|
||||
* system from the proleptic-year, month-of-year and day-of-month fields.
|
||||
* <p>
|
||||
* This returns a {@code JapaneseDate} with the specified fields.
|
||||
* The day must be valid for the year and month, otherwise an exception will be thrown.
|
||||
* <p>
|
||||
* The Japanese proleptic year, month and day-of-month are the same as those
|
||||
* in the ISO calendar system. They are not reset when the era changes.
|
||||
*
|
||||
* @param prolepticYear the Japanese proleptic-year
|
||||
* @param month the Japanese month-of-year, from 1 to 12
|
||||
* @param dayOfMonth the Japanese day-of-month, from 1 to 31
|
||||
* @return the date in Japanese calendar system, not null
|
||||
* @throws DateTimeException if the value of any field is out of range,
|
||||
* or if the day-of-month is invalid for the month-year
|
||||
*/
|
||||
public static JapaneseDate of(int prolepticYear, int month, int dayOfMonth) {
|
||||
return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
|
||||
* system from the era, year-of-era and day-of-year fields.
|
||||
* <p>
|
||||
* This returns a {@code JapaneseDate} with the specified fields.
|
||||
* The day must be valid for the year, otherwise an exception will be thrown.
|
||||
* <p>
|
||||
* The day-of-year in this factory is expressed relative to the start of the year-of-era.
|
||||
* This definition changes the normal meaning of day-of-year only in those years
|
||||
* where the year-of-era is reset to one due to a change in the era.
|
||||
* For example:
|
||||
* <pre>
|
||||
* 6th Jan Showa 64 = day-of-year 6
|
||||
* 7th Jan Showa 64 = day-of-year 7
|
||||
* 8th Jan Heisei 1 = day-of-year 1
|
||||
* 9th Jan Heisei 1 = day-of-year 2
|
||||
* </pre>
|
||||
*
|
||||
* @param era the Japanese era, not null
|
||||
* @param yearOfEra the Japanese year-of-era
|
||||
* @param dayOfYear the chronology day-of-year, from 1 to 366
|
||||
* @return the date in Japanese calendar system, not null
|
||||
* @throws DateTimeException if the value of any field is out of range,
|
||||
* or if the day-of-year is invalid for the year
|
||||
*/
|
||||
static JapaneseDate ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear) {
|
||||
Objects.requireNonNull(era, "era");
|
||||
CalendarDate firstDay = era.getPrivateEra().getSinceDate();
|
||||
LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
|
||||
jdate.setEra(era.getPrivateEra());
|
||||
if (yearOfEra == 1) {
|
||||
jdate.setDate(yearOfEra, firstDay.getMonth(), firstDay.getDayOfMonth() + dayOfYear - 1);
|
||||
} else {
|
||||
jdate.setDate(yearOfEra, 1, dayOfYear);
|
||||
}
|
||||
JapaneseChronology.JCAL.normalize(jdate);
|
||||
if (era.getPrivateEra() != jdate.getEra() || yearOfEra != jdate.getYear()) {
|
||||
throw new DateTimeException("Invalid parameters");
|
||||
}
|
||||
LocalDate localdate = LocalDate.of(jdate.getNormalizedYear(),
|
||||
jdate.getMonth(), jdate.getDayOfMonth());
|
||||
return new JapaneseDate(era, yearOfEra, localdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code JapaneseDate} from a temporal object.
|
||||
* <p>
|
||||
* This obtains a date in the Japanese calendar system based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code JapaneseDate}.
|
||||
* <p>
|
||||
* The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
|
||||
* field, which is standardized across calendar systems.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code JapaneseDate::from}.
|
||||
*
|
||||
* @param temporal the temporal object to convert, not null
|
||||
* @return the date in Japanese calendar system, not null
|
||||
* @throws DateTimeException if unable to convert to a {@code JapaneseDate}
|
||||
*/
|
||||
public static JapaneseDate from(TemporalAccessor temporal) {
|
||||
return JapaneseChronology.INSTANCE.date(temporal);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Creates an instance from an ISO date.
|
||||
*
|
||||
* @param isoDate the standard local date, validated not null
|
||||
*/
|
||||
JapaneseDate(LocalDate isoDate) {
|
||||
if (isoDate.isBefore(MEIJI_6_ISODATE)) {
|
||||
throw new DateTimeException("JapaneseDate before Meiji 6 is not supported");
|
||||
}
|
||||
LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate);
|
||||
this.era = JapaneseEra.toJapaneseEra(jdate.getEra());
|
||||
this.yearOfEra = jdate.getYear();
|
||||
this.isoDate = isoDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code JapaneseDate}. This constructor does NOT validate the given parameters,
|
||||
* and {@code era} and {@code year} must agree with {@code isoDate}.
|
||||
*
|
||||
* @param era the era, validated not null
|
||||
* @param year the year-of-era, validated
|
||||
* @param isoDate the standard local date, validated not null
|
||||
*/
|
||||
JapaneseDate(JapaneseEra era, int year, LocalDate isoDate) {
|
||||
if (isoDate.isBefore(MEIJI_6_ISODATE)) {
|
||||
throw new DateTimeException("JapaneseDate before Meiji 6 is not supported");
|
||||
}
|
||||
this.era = era;
|
||||
this.yearOfEra = year;
|
||||
this.isoDate = isoDate;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the chronology of this date, which is the Japanese calendar system.
|
||||
* <p>
|
||||
* The {@code Chronology} represents the calendar system in use.
|
||||
* The era and other fields in {@link ChronoField} are defined by the chronology.
|
||||
*
|
||||
* @return the Japanese chronology, not null
|
||||
*/
|
||||
@Override
|
||||
public JapaneseChronology getChronology() {
|
||||
return JapaneseChronology.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the era applicable at this date.
|
||||
* <p>
|
||||
* The Japanese calendar system has multiple eras defined by {@link JapaneseEra}.
|
||||
*
|
||||
* @return the era applicable at this date, not null
|
||||
*/
|
||||
@Override
|
||||
public JapaneseEra getEra() {
|
||||
return era;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the month represented by this date.
|
||||
* <p>
|
||||
* This returns the length of the month in days.
|
||||
* Month lengths match those of the ISO calendar system.
|
||||
*
|
||||
* @return the length of the month in days
|
||||
*/
|
||||
@Override
|
||||
public int lengthOfMonth() {
|
||||
return isoDate.lengthOfMonth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lengthOfYear() {
|
||||
Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
|
||||
jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
|
||||
jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
|
||||
return jcal.getActualMaximum(Calendar.DAY_OF_YEAR);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if the specified field is supported.
|
||||
* <p>
|
||||
* This checks if this date can be queried for the specified field.
|
||||
* If false, then calling the {@link #range(TemporalField) range} and
|
||||
* {@link #get(TemporalField) get} methods will throw an exception.
|
||||
* <p>
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The supported fields are:
|
||||
* <ul>
|
||||
* <li>{@code DAY_OF_WEEK}
|
||||
* <li>{@code DAY_OF_MONTH}
|
||||
* <li>{@code DAY_OF_YEAR}
|
||||
* <li>{@code EPOCH_DAY}
|
||||
* <li>{@code MONTH_OF_YEAR}
|
||||
* <li>{@code PROLEPTIC_MONTH}
|
||||
* <li>{@code YEAR_OF_ERA}
|
||||
* <li>{@code YEAR}
|
||||
* <li>{@code ERA}
|
||||
* </ul>
|
||||
* All other {@code ChronoField} instances will return false.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the field is supported is determined by the field.
|
||||
*
|
||||
* @param field the field to check, null returns false
|
||||
* @return true if the field is supported on this date, false if not
|
||||
*/
|
||||
@Override
|
||||
public boolean isSupported(TemporalField field) {
|
||||
if (field == ALIGNED_DAY_OF_WEEK_IN_MONTH || field == ALIGNED_DAY_OF_WEEK_IN_YEAR ||
|
||||
field == ALIGNED_WEEK_OF_MONTH || field == ALIGNED_WEEK_OF_YEAR) {
|
||||
return false;
|
||||
}
|
||||
return ChronoLocalDate.super.isSupported(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueRange range(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
if (isSupported(field)) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
switch (f) {
|
||||
case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
|
||||
case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
|
||||
case YEAR_OF_ERA: {
|
||||
Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
|
||||
jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
|
||||
jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
|
||||
return ValueRange.of(1, jcal.getActualMaximum(Calendar.YEAR));
|
||||
}
|
||||
}
|
||||
return getChronology().range(f);
|
||||
}
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
}
|
||||
return field.rangeRefinedBy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
// same as ISO:
|
||||
// DAY_OF_WEEK, DAY_OF_MONTH, EPOCH_DAY, MONTH_OF_YEAR, PROLEPTIC_MONTH, YEAR
|
||||
//
|
||||
// calendar specific fields
|
||||
// DAY_OF_YEAR, YEAR_OF_ERA, ERA
|
||||
switch ((ChronoField) field) {
|
||||
case ALIGNED_DAY_OF_WEEK_IN_MONTH:
|
||||
case ALIGNED_DAY_OF_WEEK_IN_YEAR:
|
||||
case ALIGNED_WEEK_OF_MONTH:
|
||||
case ALIGNED_WEEK_OF_YEAR:
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
case YEAR_OF_ERA:
|
||||
return yearOfEra;
|
||||
case ERA:
|
||||
return era.getValue();
|
||||
case DAY_OF_YEAR:
|
||||
Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
|
||||
jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
|
||||
jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
|
||||
return jcal.get(Calendar.DAY_OF_YEAR);
|
||||
}
|
||||
return isoDate.getLong(field);
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code LocalGregorianCalendar.Date} converted from the given {@code isoDate}.
|
||||
*
|
||||
* @param isoDate the local date, not null
|
||||
* @return a {@code LocalGregorianCalendar.Date}, not null
|
||||
*/
|
||||
private static LocalGregorianCalendar.Date toPrivateJapaneseDate(LocalDate isoDate) {
|
||||
LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
|
||||
sun.util.calendar.Era sunEra = JapaneseEra.privateEraFrom(isoDate);
|
||||
int year = isoDate.getYear();
|
||||
if (sunEra != null) {
|
||||
year -= sunEra.getSinceDate().getYear() - 1;
|
||||
}
|
||||
jdate.setEra(sunEra).setYear(year).setMonth(isoDate.getMonthValue()).setDayOfMonth(isoDate.getDayOfMonth());
|
||||
JapaneseChronology.JCAL.normalize(jdate);
|
||||
return jdate;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public JapaneseDate with(TemporalField field, long newValue) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
if (getLong(f) == newValue) { // getLong() validates for supported fields
|
||||
return this;
|
||||
}
|
||||
switch (f) {
|
||||
case YEAR_OF_ERA:
|
||||
case YEAR:
|
||||
case ERA: {
|
||||
int nvalue = getChronology().range(f).checkValidIntValue(newValue, f);
|
||||
switch (f) {
|
||||
case YEAR_OF_ERA:
|
||||
return this.withYear(nvalue);
|
||||
case YEAR:
|
||||
return with(isoDate.withYear(nvalue));
|
||||
case ERA: {
|
||||
return this.withYear(JapaneseEra.of(nvalue), yearOfEra);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// YEAR, PROLEPTIC_MONTH and others are same as ISO
|
||||
return with(isoDate.with(field, newValue));
|
||||
}
|
||||
return super.with(field, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public JapaneseDate with(TemporalAdjuster adjuster) {
|
||||
return super.with(adjuster);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public JapaneseDate plus(TemporalAmount amount) {
|
||||
return super.plus(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public JapaneseDate minus(TemporalAmount amount) {
|
||||
return super.minus(amount);
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a copy of this date with the year altered.
|
||||
* <p>
|
||||
* This method changes the year of the date.
|
||||
* If the month-day is invalid for the year, then the previous valid day
|
||||
* will be selected instead.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param era the era to set in the result, not null
|
||||
* @param yearOfEra the year-of-era to set in the returned date
|
||||
* @return a {@code JapaneseDate} based on this date with the requested year, never null
|
||||
* @throws DateTimeException if {@code year} is invalid
|
||||
*/
|
||||
private JapaneseDate withYear(JapaneseEra era, int yearOfEra) {
|
||||
int year = JapaneseChronology.INSTANCE.prolepticYear(era, yearOfEra);
|
||||
return with(isoDate.withYear(year));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this date with the year-of-era altered.
|
||||
* <p>
|
||||
* This method changes the year-of-era of the date.
|
||||
* If the month-day is invalid for the year, then the previous valid day
|
||||
* will be selected instead.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param year the year to set in the returned date
|
||||
* @return a {@code JapaneseDate} based on this date with the requested year-of-era, never null
|
||||
* @throws DateTimeException if {@code year} is invalid
|
||||
*/
|
||||
private JapaneseDate withYear(int year) {
|
||||
return withYear(getEra(), year);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
JapaneseDate plusYears(long years) {
|
||||
return with(isoDate.plusYears(years));
|
||||
}
|
||||
|
||||
@Override
|
||||
JapaneseDate plusMonths(long months) {
|
||||
return with(isoDate.plusMonths(months));
|
||||
}
|
||||
|
||||
@Override
|
||||
JapaneseDate plusWeeks(long weeksToAdd) {
|
||||
return with(isoDate.plusWeeks(weeksToAdd));
|
||||
}
|
||||
|
||||
@Override
|
||||
JapaneseDate plusDays(long days) {
|
||||
return with(isoDate.plusDays(days));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JapaneseDate plus(long amountToAdd, TemporalUnit unit) {
|
||||
return super.plus(amountToAdd, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JapaneseDate minus(long amountToAdd, TemporalUnit unit) {
|
||||
return super.minus(amountToAdd, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
JapaneseDate minusYears(long yearsToSubtract) {
|
||||
return super.minusYears(yearsToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
JapaneseDate minusMonths(long monthsToSubtract) {
|
||||
return super.minusMonths(monthsToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
JapaneseDate minusWeeks(long weeksToSubtract) {
|
||||
return super.minusWeeks(weeksToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
JapaneseDate minusDays(long daysToSubtract) {
|
||||
return super.minusDays(daysToSubtract);
|
||||
}
|
||||
|
||||
private JapaneseDate with(LocalDate newDate) {
|
||||
return (newDate.equals(isoDate) ? this : new JapaneseDate(newDate));
|
||||
}
|
||||
|
||||
@Override // for javadoc and covariant return type
|
||||
@SuppressWarnings("unchecked")
|
||||
public final ChronoLocalDateTime<JapaneseDate> atTime(LocalTime localTime) {
|
||||
return (ChronoLocalDateTime<JapaneseDate>)super.atTime(localTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronoPeriod until(ChronoLocalDate endDate) {
|
||||
Period period = isoDate.until(endDate);
|
||||
return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
|
||||
}
|
||||
|
||||
@Override // override for performance
|
||||
public long toEpochDay() {
|
||||
return isoDate.toEpochDay();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this date to another date, including the chronology.
|
||||
* <p>
|
||||
* Compares this {@code JapaneseDate} with another ensuring that the date is the same.
|
||||
* <p>
|
||||
* Only objects of type {@code JapaneseDate} are compared, other types return false.
|
||||
* To compare the dates of two {@code TemporalAccessor} instances, including dates
|
||||
* in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other date
|
||||
*/
|
||||
@Override // override for performance
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof JapaneseDate) {
|
||||
JapaneseDate otherDate = (JapaneseDate) obj;
|
||||
return this.isoDate.equals(otherDate.isoDate);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for this date.
|
||||
*
|
||||
* @return a suitable hash code based only on the Chronology and the date
|
||||
*/
|
||||
@Override // override for performance
|
||||
public int hashCode() {
|
||||
return getChronology().getId().hashCode() ^ isoDate.hashCode();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the object using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(4); // identifies a JapaneseDate
|
||||
* out.writeInt(get(YEAR));
|
||||
* out.writeByte(get(MONTH_OF_YEAR));
|
||||
* out.writeByte(get(DAY_OF_MONTH));
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
private Object writeReplace() {
|
||||
return new Ser(Ser.JAPANESE_DATE_TYPE, this);
|
||||
}
|
||||
|
||||
void writeExternal(DataOutput out) throws IOException {
|
||||
// JapaneseChronology is implicit in the JAPANESE_DATE_TYPE
|
||||
out.writeInt(get(YEAR));
|
||||
out.writeByte(get(MONTH_OF_YEAR));
|
||||
out.writeByte(get(DAY_OF_MONTH));
|
||||
}
|
||||
|
||||
static JapaneseDate readExternal(DataInput in) throws IOException {
|
||||
int year = in.readInt();
|
||||
int month = in.readByte();
|
||||
int dayOfMonth = in.readByte();
|
||||
return JapaneseChronology.INSTANCE.date(year, month, dayOfMonth);
|
||||
}
|
||||
|
||||
}
|
||||
450
jdkSrc/jdk8/java/time/chrono/JapaneseEra.java
Normal file
450
jdkSrc/jdk8/java/time/chrono/JapaneseEra.java
Normal file
@@ -0,0 +1,450 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.chrono.JapaneseDate.MEIJI_6_ISODATE;
|
||||
import static java.time.temporal.ChronoField.ERA;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.TextStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.util.calendar.CalendarDate;
|
||||
|
||||
/**
|
||||
* An era in the Japanese Imperial calendar system.
|
||||
* <p>
|
||||
* The Japanese government defines the official name and start date of
|
||||
* each era. Eras are consecutive and their date ranges do not overlap,
|
||||
* so the end date of one era is always the day before the start date
|
||||
* of the next era.
|
||||
* <p>
|
||||
* The Java SE Platform supports all eras defined by the Japanese government,
|
||||
* beginning with the Meiji era. Each era is identified in the Platform by an
|
||||
* integer value and a name. The {@link #of(int)} and {@link #valueOf(String)}
|
||||
* methods may be used to obtain a singleton instance of JapaneseEra for each
|
||||
* era. The {@link #values()} method returns the singleton instances of all
|
||||
* supported eras.
|
||||
* <p>
|
||||
* For convenience, this class declares a number of public static final fields
|
||||
* that refer to singleton instances returned by the values() method.
|
||||
*
|
||||
* @apiNote
|
||||
* The fields declared in this class may evolve over time, in line with the
|
||||
* results of the {@link #values()} method. However, there is not necessarily
|
||||
* a 1:1 correspondence between the fields and the singleton instances.
|
||||
*
|
||||
* @apiNote
|
||||
* The Japanese government may announce a new era and define its start
|
||||
* date but not its official name. In this scenario, the singleton instance
|
||||
* that represents the new era may return a name that is not stable until
|
||||
* the official name is defined. Developers should exercise caution when
|
||||
* relying on the name returned by any singleton instance that does not
|
||||
* correspond to a public static final field.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class JapaneseEra
|
||||
implements Era, Serializable {
|
||||
|
||||
// The offset value to 0-based index from the era value.
|
||||
// i.e., getValue() + ERA_OFFSET == 0-based index
|
||||
static final int ERA_OFFSET = 2;
|
||||
|
||||
static final sun.util.calendar.Era[] ERA_CONFIG;
|
||||
|
||||
/**
|
||||
* The singleton instance for the 'Meiji' era (1868-01-01 - 1912-07-29)
|
||||
* which has the value -1.
|
||||
*/
|
||||
public static final JapaneseEra MEIJI = new JapaneseEra(-1, LocalDate.of(1868, 1, 1));
|
||||
/**
|
||||
* The singleton instance for the 'Taisho' era (1912-07-30 - 1926-12-24)
|
||||
* which has the value 0.
|
||||
*/
|
||||
public static final JapaneseEra TAISHO = new JapaneseEra(0, LocalDate.of(1912, 7, 30));
|
||||
/**
|
||||
* The singleton instance for the 'Showa' era (1926-12-25 - 1989-01-07)
|
||||
* which has the value 1.
|
||||
*/
|
||||
public static final JapaneseEra SHOWA = new JapaneseEra(1, LocalDate.of(1926, 12, 25));
|
||||
/**
|
||||
* The singleton instance for the 'Heisei' era (1989-01-08 - 2019-04-30)
|
||||
* which has the value 2.
|
||||
*/
|
||||
public static final JapaneseEra HEISEI = new JapaneseEra(2, LocalDate.of(1989, 1, 8));
|
||||
/**
|
||||
* The singleton instance for the 'Reiwa' era (2019-05-01 - )
|
||||
* which has the value 3.
|
||||
*/
|
||||
private static final JapaneseEra REIWA = new JapaneseEra(3, LocalDate.of(2019, 5, 1));
|
||||
|
||||
// The number of predefined JapaneseEra constants.
|
||||
// There may be a supplemental era defined by the property.
|
||||
private static final int N_ERA_CONSTANTS = REIWA.getValue() + ERA_OFFSET;
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = 1466499369062886794L;
|
||||
|
||||
// array for the singleton JapaneseEra instances
|
||||
private static final JapaneseEra[] KNOWN_ERAS;
|
||||
|
||||
static {
|
||||
ERA_CONFIG = JapaneseChronology.JCAL.getEras();
|
||||
|
||||
KNOWN_ERAS = new JapaneseEra[ERA_CONFIG.length];
|
||||
KNOWN_ERAS[0] = MEIJI;
|
||||
KNOWN_ERAS[1] = TAISHO;
|
||||
KNOWN_ERAS[2] = SHOWA;
|
||||
KNOWN_ERAS[3] = HEISEI;
|
||||
KNOWN_ERAS[4] = REIWA;
|
||||
for (int i = N_ERA_CONSTANTS; i < ERA_CONFIG.length; i++) {
|
||||
CalendarDate date = ERA_CONFIG[i].getSinceDate();
|
||||
LocalDate isoDate = LocalDate.of(date.getYear(), date.getMonth(), date.getDayOfMonth());
|
||||
KNOWN_ERAS[i] = new JapaneseEra(i - ERA_OFFSET + 1, isoDate);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The era value.
|
||||
* @serial
|
||||
*/
|
||||
private final transient int eraValue;
|
||||
|
||||
// the first day of the era
|
||||
private final transient LocalDate since;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param eraValue the era value, validated
|
||||
* @param since the date representing the first date of the era, validated not null
|
||||
*/
|
||||
private JapaneseEra(int eraValue, LocalDate since) {
|
||||
this.eraValue = eraValue;
|
||||
this.since = since;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns the Sun private Era instance corresponding to this {@code JapaneseEra}.
|
||||
*
|
||||
* @return the Sun private Era instance for this {@code JapaneseEra}.
|
||||
*/
|
||||
sun.util.calendar.Era getPrivateEra() {
|
||||
return ERA_CONFIG[ordinal(eraValue)];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code JapaneseEra} from an {@code int} value.
|
||||
* <ul>
|
||||
* <li>The value {@code 1} is associated with the 'Showa' era, because
|
||||
* it contains 1970-01-01 (ISO calendar system).</li>
|
||||
* <li>The values {@code -1} and {@code 0} are associated with two earlier
|
||||
* eras, Meiji and Taisho, respectively.</li>
|
||||
* <li>A value greater than {@code 1} is associated with a later era,
|
||||
* beginning with Heisei ({@code 2}).</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Every instance of {@code JapaneseEra} that is returned from the {@link values()}
|
||||
* method has an int value (available via {@link Era#getValue()} which is
|
||||
* accepted by this method.
|
||||
*
|
||||
* @param japaneseEra the era to represent
|
||||
* @return the {@code JapaneseEra} singleton, not null
|
||||
* @throws DateTimeException if the value is invalid
|
||||
*/
|
||||
public static JapaneseEra of(int japaneseEra) {
|
||||
if (japaneseEra < MEIJI.eraValue || japaneseEra + ERA_OFFSET > KNOWN_ERAS.length) {
|
||||
throw new DateTimeException("Invalid era: " + japaneseEra);
|
||||
}
|
||||
return KNOWN_ERAS[ordinal(japaneseEra)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code JapaneseEra} with the name.
|
||||
* <p>
|
||||
* The string must match exactly the name of the era.
|
||||
* (Extraneous whitespace characters are not permitted.)
|
||||
*
|
||||
* @param japaneseEra the japaneseEra name; non-null
|
||||
* @return the {@code JapaneseEra} singleton, never null
|
||||
* @throws IllegalArgumentException if there is not JapaneseEra with the specified name
|
||||
*/
|
||||
public static JapaneseEra valueOf(String japaneseEra) {
|
||||
Objects.requireNonNull(japaneseEra, "japaneseEra");
|
||||
for (JapaneseEra era : KNOWN_ERAS) {
|
||||
if (era.getName().equals(japaneseEra)) {
|
||||
return era;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("japaneseEra is invalid");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of JapaneseEras.
|
||||
* <p>
|
||||
* This method may be used to iterate over the JapaneseEras as follows:
|
||||
* <pre>
|
||||
* for (JapaneseEra c : JapaneseEra.values())
|
||||
* System.out.println(c);
|
||||
* </pre>
|
||||
*
|
||||
* @return an array of JapaneseEras
|
||||
*/
|
||||
public static JapaneseEra[] values() {
|
||||
return Arrays.copyOf(KNOWN_ERAS, KNOWN_ERAS.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param style {@inheritDoc}
|
||||
* @param locale {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getDisplayName(TextStyle style, Locale locale) {
|
||||
// If this JapaneseEra is a supplemental one, obtain the name from
|
||||
// the era definition.
|
||||
if (getValue() > N_ERA_CONSTANTS - ERA_OFFSET) {
|
||||
Objects.requireNonNull(locale, "locale");
|
||||
return style.asNormal() == TextStyle.NARROW ? getAbbreviation() : getName();
|
||||
}
|
||||
|
||||
return new DateTimeFormatterBuilder()
|
||||
.appendText(ERA, style)
|
||||
.toFormatter(locale)
|
||||
.withChronology(JapaneseChronology.INSTANCE)
|
||||
.format(this == MEIJI ? MEIJI_6_ISODATE : since);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code JapaneseEra} from a date.
|
||||
*
|
||||
* @param date the date, not null
|
||||
* @return the Era singleton, never null
|
||||
*/
|
||||
static JapaneseEra from(LocalDate date) {
|
||||
if (date.isBefore(MEIJI_6_ISODATE)) {
|
||||
throw new DateTimeException("JapaneseDate before Meiji 6 are not supported");
|
||||
}
|
||||
for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
|
||||
JapaneseEra era = KNOWN_ERAS[i];
|
||||
if (date.compareTo(era.since) >= 0) {
|
||||
return era;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static JapaneseEra toJapaneseEra(sun.util.calendar.Era privateEra) {
|
||||
for (int i = ERA_CONFIG.length - 1; i >= 0; i--) {
|
||||
if (ERA_CONFIG[i].equals(privateEra)) {
|
||||
return KNOWN_ERAS[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static sun.util.calendar.Era privateEraFrom(LocalDate isoDate) {
|
||||
for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
|
||||
JapaneseEra era = KNOWN_ERAS[i];
|
||||
if (isoDate.compareTo(era.since) >= 0) {
|
||||
return ERA_CONFIG[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index into the arrays from the Era value.
|
||||
* the eraValue is a valid Era number, -1..2.
|
||||
*
|
||||
* @param eraValue the era value to convert to the index
|
||||
* @return the index of the current Era
|
||||
*/
|
||||
private static int ordinal(int eraValue) {
|
||||
return eraValue + ERA_OFFSET - 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the numeric era {@code int} value.
|
||||
* <p>
|
||||
* The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1.
|
||||
* Later eras are numbered from 2 ({@link #HEISEI}).
|
||||
* Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI})).
|
||||
*
|
||||
* @return the era value
|
||||
*/
|
||||
@Override
|
||||
public int getValue() {
|
||||
return eraValue;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the range of valid values for the specified field.
|
||||
* <p>
|
||||
* The range object expresses the minimum and maximum valid values for a field.
|
||||
* This era is used to enhance the accuracy of the returned range.
|
||||
* If it is not possible to return the range, because the field is not supported
|
||||
* or for some other reason, an exception is thrown.
|
||||
* <p>
|
||||
* If the field is a {@link ChronoField} then the query is implemented here.
|
||||
* The {@code ERA} field returns the range.
|
||||
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
|
||||
* <p>
|
||||
* If the field is not a {@code ChronoField}, then the result of this method
|
||||
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
|
||||
* passing {@code this} as the argument.
|
||||
* Whether the range can be obtained is determined by the field.
|
||||
* <p>
|
||||
* The range of valid Japanese eras can change over time due to the nature
|
||||
* of the Japanese calendar system.
|
||||
*
|
||||
* @param field the field to query the range for, not null
|
||||
* @return the range of valid values for the field, not null
|
||||
* @throws DateTimeException if the range for the field cannot be obtained
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
*/
|
||||
@Override // override as super would return range from 0 to 1
|
||||
public ValueRange range(TemporalField field) {
|
||||
if (field == ERA) {
|
||||
return JapaneseChronology.INSTANCE.range(ERA);
|
||||
}
|
||||
return Era.super.range(field);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
String getAbbreviation() {
|
||||
return ERA_CONFIG[ordinal(getValue())].getAbbreviation();
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return ERA_CONFIG[ordinal(getValue())].getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the object using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(5); // identifies a JapaneseEra
|
||||
* out.writeInt(getValue());
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
private Object writeReplace() {
|
||||
return new Ser(Ser.JAPANESE_ERA_TYPE, this);
|
||||
}
|
||||
|
||||
void writeExternal(DataOutput out) throws IOException {
|
||||
out.writeByte(this.getValue());
|
||||
}
|
||||
|
||||
static JapaneseEra readExternal(DataInput in) throws IOException {
|
||||
byte eraValue = in.readByte();
|
||||
return JapaneseEra.of(eraValue);
|
||||
}
|
||||
|
||||
}
|
||||
364
jdkSrc/jdk8/java/time/chrono/MinguoChronology.java
Normal file
364
jdkSrc/jdk8/java/time/chrono/MinguoChronology.java
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.Clock;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.ResolverStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Minguo calendar system.
|
||||
* <p>
|
||||
* This chronology defines the rules of the Minguo calendar system.
|
||||
* This calendar system is primarily used in the Republic of China, often known as Taiwan.
|
||||
* Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}.
|
||||
* <p>
|
||||
* The fields are defined as follows:
|
||||
* <ul>
|
||||
* <li>era - There are two eras, the current 'Republic' (ERA_ROC) and the previous era (ERA_BEFORE_ROC).
|
||||
* <li>year-of-era - The year-of-era for the current era increases uniformly from the epoch at year one.
|
||||
* For the previous era the year increases from one as time goes backwards.
|
||||
* The value for the current era is equal to the ISO proleptic-year minus 1911.
|
||||
* <li>proleptic-year - The proleptic year is the same as the year-of-era for the
|
||||
* current era. For the previous era, years have zero, then negative values.
|
||||
* The value is equal to the ISO proleptic-year minus 1911.
|
||||
* <li>month-of-year - The Minguo month-of-year exactly matches ISO.
|
||||
* <li>day-of-month - The Minguo day-of-month exactly matches ISO.
|
||||
* <li>day-of-year - The Minguo day-of-year exactly matches ISO.
|
||||
* <li>leap-year - The Minguo leap-year pattern exactly matches ISO, such that the two calendars
|
||||
* are never out of step.
|
||||
* </ul>
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class MinguoChronology extends AbstractChronology implements Serializable {
|
||||
|
||||
/**
|
||||
* Singleton instance for the Minguo chronology.
|
||||
*/
|
||||
public static final MinguoChronology INSTANCE = new MinguoChronology();
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = 1039765215346859963L;
|
||||
/**
|
||||
* The difference in years between ISO and Minguo.
|
||||
*/
|
||||
static final int YEARS_DIFFERENCE = 1911;
|
||||
|
||||
/**
|
||||
* Restricted constructor.
|
||||
*/
|
||||
private MinguoChronology() {
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the ID of the chronology - 'Minguo'.
|
||||
* <p>
|
||||
* The ID uniquely identifies the {@code Chronology}.
|
||||
* It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
|
||||
*
|
||||
* @return the chronology ID - 'Minguo'
|
||||
* @see #getCalendarType()
|
||||
*/
|
||||
@Override
|
||||
public String getId() {
|
||||
return "Minguo";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the calendar type of the underlying calendar system - 'roc'.
|
||||
* <p>
|
||||
* The calendar type is an identifier defined by the
|
||||
* <em>Unicode Locale Data Markup Language (LDML)</em> specification.
|
||||
* It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
|
||||
* It can also be used as part of a locale, accessible via
|
||||
* {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
|
||||
*
|
||||
* @return the calendar system type - 'roc'
|
||||
* @see #getId()
|
||||
*/
|
||||
@Override
|
||||
public String getCalendarType() {
|
||||
return "roc";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a local date in Minguo calendar system from the
|
||||
* era, year-of-era, month-of-year and day-of-month fields.
|
||||
*
|
||||
* @param era the Minguo era, not null
|
||||
* @param yearOfEra the year-of-era
|
||||
* @param month the month-of-year
|
||||
* @param dayOfMonth the day-of-month
|
||||
* @return the Minguo local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
* @throws ClassCastException if the {@code era} is not a {@code MinguoEra}
|
||||
*/
|
||||
@Override
|
||||
public MinguoDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
|
||||
return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in Minguo calendar system from the
|
||||
* proleptic-year, month-of-year and day-of-month fields.
|
||||
*
|
||||
* @param prolepticYear the proleptic-year
|
||||
* @param month the month-of-year
|
||||
* @param dayOfMonth the day-of-month
|
||||
* @return the Minguo local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override
|
||||
public MinguoDate date(int prolepticYear, int month, int dayOfMonth) {
|
||||
return new MinguoDate(LocalDate.of(prolepticYear + YEARS_DIFFERENCE, month, dayOfMonth));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in Minguo calendar system from the
|
||||
* era, year-of-era and day-of-year fields.
|
||||
*
|
||||
* @param era the Minguo era, not null
|
||||
* @param yearOfEra the year-of-era
|
||||
* @param dayOfYear the day-of-year
|
||||
* @return the Minguo local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
* @throws ClassCastException if the {@code era} is not a {@code MinguoEra}
|
||||
*/
|
||||
@Override
|
||||
public MinguoDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
|
||||
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in Minguo calendar system from the
|
||||
* proleptic-year and day-of-year fields.
|
||||
*
|
||||
* @param prolepticYear the proleptic-year
|
||||
* @param dayOfYear the day-of-year
|
||||
* @return the Minguo local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override
|
||||
public MinguoDate dateYearDay(int prolepticYear, int dayOfYear) {
|
||||
return new MinguoDate(LocalDate.ofYearDay(prolepticYear + YEARS_DIFFERENCE, dayOfYear));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in the Minguo calendar system from the epoch-day.
|
||||
*
|
||||
* @param epochDay the epoch day
|
||||
* @return the Minguo local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public MinguoDate dateEpochDay(long epochDay) {
|
||||
return new MinguoDate(LocalDate.ofEpochDay(epochDay));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinguoDate dateNow() {
|
||||
return dateNow(Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinguoDate dateNow(ZoneId zone) {
|
||||
return dateNow(Clock.system(zone));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinguoDate dateNow(Clock clock) {
|
||||
return date(LocalDate.now(clock));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinguoDate date(TemporalAccessor temporal) {
|
||||
if (temporal instanceof MinguoDate) {
|
||||
return (MinguoDate) temporal;
|
||||
}
|
||||
return new MinguoDate(LocalDate.from(temporal));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoLocalDateTime<MinguoDate> localDateTime(TemporalAccessor temporal) {
|
||||
return (ChronoLocalDateTime<MinguoDate>)super.localDateTime(temporal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoZonedDateTime<MinguoDate> zonedDateTime(TemporalAccessor temporal) {
|
||||
return (ChronoZonedDateTime<MinguoDate>)super.zonedDateTime(temporal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoZonedDateTime<MinguoDate> zonedDateTime(Instant instant, ZoneId zone) {
|
||||
return (ChronoZonedDateTime<MinguoDate>)super.zonedDateTime(instant, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if the specified year is a leap year.
|
||||
* <p>
|
||||
* Minguo leap years occur exactly in line with ISO leap years.
|
||||
* This method does not validate the year passed in, and only has a
|
||||
* well-defined result for years in the supported range.
|
||||
*
|
||||
* @param prolepticYear the proleptic-year to check, not validated for range
|
||||
* @return true if the year is a leap year
|
||||
*/
|
||||
@Override
|
||||
public boolean isLeapYear(long prolepticYear) {
|
||||
return IsoChronology.INSTANCE.isLeapYear(prolepticYear + YEARS_DIFFERENCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int prolepticYear(Era era, int yearOfEra) {
|
||||
if (era instanceof MinguoEra == false) {
|
||||
throw new ClassCastException("Era must be MinguoEra");
|
||||
}
|
||||
return (era == MinguoEra.ROC ? yearOfEra : 1 - yearOfEra);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinguoEra eraOf(int eraValue) {
|
||||
return MinguoEra.of(eraValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Era> eras() {
|
||||
return Arrays.<Era>asList(MinguoEra.values());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ValueRange range(ChronoField field) {
|
||||
switch (field) {
|
||||
case PROLEPTIC_MONTH: {
|
||||
ValueRange range = PROLEPTIC_MONTH.range();
|
||||
return ValueRange.of(range.getMinimum() - YEARS_DIFFERENCE * 12L, range.getMaximum() - YEARS_DIFFERENCE * 12L);
|
||||
}
|
||||
case YEAR_OF_ERA: {
|
||||
ValueRange range = YEAR.range();
|
||||
return ValueRange.of(1, range.getMaximum() - YEARS_DIFFERENCE, -range.getMinimum() + 1 + YEARS_DIFFERENCE);
|
||||
}
|
||||
case YEAR: {
|
||||
ValueRange range = YEAR.range();
|
||||
return ValueRange.of(range.getMinimum() - YEARS_DIFFERENCE, range.getMaximum() - YEARS_DIFFERENCE);
|
||||
}
|
||||
}
|
||||
return field.range();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override // override for return type
|
||||
public MinguoDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
return (MinguoDate) super.resolveDate(fieldValues, resolverStyle);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the Chronology using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(1); // identifies a Chronology
|
||||
* out.writeUTF(getId());
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
@Override
|
||||
Object writeReplace() {
|
||||
return super.writeReplace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
}
|
||||
519
jdkSrc/jdk8/java/time/chrono/MinguoDate.java
Normal file
519
jdkSrc/jdk8/java/time/chrono/MinguoDate.java
Normal file
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.chrono.MinguoChronology.YEARS_DIFFERENCE;
|
||||
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.Clock;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Period;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date in the Minguo calendar system.
|
||||
* <p>
|
||||
* This date operates using the {@linkplain MinguoChronology Minguo calendar}.
|
||||
* This calendar system is primarily used in the Republic of China, often known as Taiwan.
|
||||
* Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}.
|
||||
*
|
||||
* <p>
|
||||
* This is a <a href="{@docRoot}/java/lang/doc-files/ValueBased.html">value-based</a>
|
||||
* class; use of identity-sensitive operations (including reference equality
|
||||
* ({@code ==}), identity hash code, or synchronization) on instances of
|
||||
* {@code MinguoDate} may have unpredictable results and should be avoided.
|
||||
* The {@code equals} method should be used for comparisons.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class MinguoDate
|
||||
extends ChronoLocalDateImpl<MinguoDate>
|
||||
implements ChronoLocalDate, Serializable {
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = 1300372329181994526L;
|
||||
|
||||
/**
|
||||
* The underlying date.
|
||||
*/
|
||||
private final transient LocalDate isoDate;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains the current {@code MinguoDate} from the system clock in the default time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
|
||||
* time-zone to obtain the current date.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @return the current date using the system clock and default time-zone, not null
|
||||
*/
|
||||
public static MinguoDate now() {
|
||||
return now(Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current {@code MinguoDate} from the system clock in the specified time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
|
||||
* Specifying the time-zone avoids dependence on the default time-zone.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @param zone the zone ID to use, not null
|
||||
* @return the current date using the system clock, not null
|
||||
*/
|
||||
public static MinguoDate now(ZoneId zone) {
|
||||
return now(Clock.system(zone));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current {@code MinguoDate} from the specified clock.
|
||||
* <p>
|
||||
* This will query the specified clock to obtain the current date - today.
|
||||
* Using this method allows the use of an alternate clock for testing.
|
||||
* The alternate clock may be introduced using {@linkplain Clock dependency injection}.
|
||||
*
|
||||
* @param clock the clock to use, not null
|
||||
* @return the current date, not null
|
||||
* @throws DateTimeException if the current date cannot be obtained
|
||||
*/
|
||||
public static MinguoDate now(Clock clock) {
|
||||
return new MinguoDate(LocalDate.now(clock));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code MinguoDate} representing a date in the Minguo calendar
|
||||
* system from the proleptic-year, month-of-year and day-of-month fields.
|
||||
* <p>
|
||||
* This returns a {@code MinguoDate} with the specified fields.
|
||||
* The day must be valid for the year and month, otherwise an exception will be thrown.
|
||||
*
|
||||
* @param prolepticYear the Minguo proleptic-year
|
||||
* @param month the Minguo month-of-year, from 1 to 12
|
||||
* @param dayOfMonth the Minguo day-of-month, from 1 to 31
|
||||
* @return the date in Minguo calendar system, not null
|
||||
* @throws DateTimeException if the value of any field is out of range,
|
||||
* or if the day-of-month is invalid for the month-year
|
||||
*/
|
||||
public static MinguoDate of(int prolepticYear, int month, int dayOfMonth) {
|
||||
return new MinguoDate(LocalDate.of(prolepticYear + YEARS_DIFFERENCE, month, dayOfMonth));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code MinguoDate} from a temporal object.
|
||||
* <p>
|
||||
* This obtains a date in the Minguo calendar system based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code MinguoDate}.
|
||||
* <p>
|
||||
* The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
|
||||
* field, which is standardized across calendar systems.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code MinguoDate::from}.
|
||||
*
|
||||
* @param temporal the temporal object to convert, not null
|
||||
* @return the date in Minguo calendar system, not null
|
||||
* @throws DateTimeException if unable to convert to a {@code MinguoDate}
|
||||
*/
|
||||
public static MinguoDate from(TemporalAccessor temporal) {
|
||||
return MinguoChronology.INSTANCE.date(temporal);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Creates an instance from an ISO date.
|
||||
*
|
||||
* @param isoDate the standard local date, validated not null
|
||||
*/
|
||||
MinguoDate(LocalDate isoDate) {
|
||||
Objects.requireNonNull(isoDate, "isoDate");
|
||||
this.isoDate = isoDate;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the chronology of this date, which is the Minguo calendar system.
|
||||
* <p>
|
||||
* The {@code Chronology} represents the calendar system in use.
|
||||
* The era and other fields in {@link ChronoField} are defined by the chronology.
|
||||
*
|
||||
* @return the Minguo chronology, not null
|
||||
*/
|
||||
@Override
|
||||
public MinguoChronology getChronology() {
|
||||
return MinguoChronology.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the era applicable at this date.
|
||||
* <p>
|
||||
* The Minguo calendar system has two eras, 'ROC' and 'BEFORE_ROC',
|
||||
* defined by {@link MinguoEra}.
|
||||
*
|
||||
* @return the era applicable at this date, not null
|
||||
*/
|
||||
@Override
|
||||
public MinguoEra getEra() {
|
||||
return (getProlepticYear() >= 1 ? MinguoEra.ROC : MinguoEra.BEFORE_ROC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the month represented by this date.
|
||||
* <p>
|
||||
* This returns the length of the month in days.
|
||||
* Month lengths match those of the ISO calendar system.
|
||||
*
|
||||
* @return the length of the month in days
|
||||
*/
|
||||
@Override
|
||||
public int lengthOfMonth() {
|
||||
return isoDate.lengthOfMonth();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ValueRange range(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
if (isSupported(field)) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
switch (f) {
|
||||
case DAY_OF_MONTH:
|
||||
case DAY_OF_YEAR:
|
||||
case ALIGNED_WEEK_OF_MONTH:
|
||||
return isoDate.range(field);
|
||||
case YEAR_OF_ERA: {
|
||||
ValueRange range = YEAR.range();
|
||||
long max = (getProlepticYear() <= 0 ? -range.getMinimum() + 1 + YEARS_DIFFERENCE : range.getMaximum() - YEARS_DIFFERENCE);
|
||||
return ValueRange.of(1, max);
|
||||
}
|
||||
}
|
||||
return getChronology().range(f);
|
||||
}
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
}
|
||||
return field.rangeRefinedBy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
switch ((ChronoField) field) {
|
||||
case PROLEPTIC_MONTH:
|
||||
return getProlepticMonth();
|
||||
case YEAR_OF_ERA: {
|
||||
int prolepticYear = getProlepticYear();
|
||||
return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear);
|
||||
}
|
||||
case YEAR:
|
||||
return getProlepticYear();
|
||||
case ERA:
|
||||
return (getProlepticYear() >= 1 ? 1 : 0);
|
||||
}
|
||||
return isoDate.getLong(field);
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
|
||||
private long getProlepticMonth() {
|
||||
return getProlepticYear() * 12L + isoDate.getMonthValue() - 1;
|
||||
}
|
||||
|
||||
private int getProlepticYear() {
|
||||
return isoDate.getYear() - YEARS_DIFFERENCE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public MinguoDate with(TemporalField field, long newValue) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
if (getLong(f) == newValue) {
|
||||
return this;
|
||||
}
|
||||
switch (f) {
|
||||
case PROLEPTIC_MONTH:
|
||||
getChronology().range(f).checkValidValue(newValue, f);
|
||||
return plusMonths(newValue - getProlepticMonth());
|
||||
case YEAR_OF_ERA:
|
||||
case YEAR:
|
||||
case ERA: {
|
||||
int nvalue = getChronology().range(f).checkValidIntValue(newValue, f);
|
||||
switch (f) {
|
||||
case YEAR_OF_ERA:
|
||||
return with(isoDate.withYear(getProlepticYear() >= 1 ? nvalue + YEARS_DIFFERENCE : (1 - nvalue) + YEARS_DIFFERENCE));
|
||||
case YEAR:
|
||||
return with(isoDate.withYear(nvalue + YEARS_DIFFERENCE));
|
||||
case ERA:
|
||||
return with(isoDate.withYear((1 - getProlepticYear()) + YEARS_DIFFERENCE));
|
||||
}
|
||||
}
|
||||
}
|
||||
return with(isoDate.with(field, newValue));
|
||||
}
|
||||
return super.with(field, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public MinguoDate with(TemporalAdjuster adjuster) {
|
||||
return super.with(adjuster);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public MinguoDate plus(TemporalAmount amount) {
|
||||
return super.plus(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public MinguoDate minus(TemporalAmount amount) {
|
||||
return super.minus(amount);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
MinguoDate plusYears(long years) {
|
||||
return with(isoDate.plusYears(years));
|
||||
}
|
||||
|
||||
@Override
|
||||
MinguoDate plusMonths(long months) {
|
||||
return with(isoDate.plusMonths(months));
|
||||
}
|
||||
|
||||
@Override
|
||||
MinguoDate plusWeeks(long weeksToAdd) {
|
||||
return super.plusWeeks(weeksToAdd);
|
||||
}
|
||||
|
||||
@Override
|
||||
MinguoDate plusDays(long days) {
|
||||
return with(isoDate.plusDays(days));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinguoDate plus(long amountToAdd, TemporalUnit unit) {
|
||||
return super.plus(amountToAdd, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinguoDate minus(long amountToAdd, TemporalUnit unit) {
|
||||
return super.minus(amountToAdd, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
MinguoDate minusYears(long yearsToSubtract) {
|
||||
return super.minusYears(yearsToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
MinguoDate minusMonths(long monthsToSubtract) {
|
||||
return super.minusMonths(monthsToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
MinguoDate minusWeeks(long weeksToSubtract) {
|
||||
return super.minusWeeks(weeksToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
MinguoDate minusDays(long daysToSubtract) {
|
||||
return super.minusDays(daysToSubtract);
|
||||
}
|
||||
|
||||
private MinguoDate with(LocalDate newDate) {
|
||||
return (newDate.equals(isoDate) ? this : new MinguoDate(newDate));
|
||||
}
|
||||
|
||||
@Override // for javadoc and covariant return type
|
||||
@SuppressWarnings("unchecked")
|
||||
public final ChronoLocalDateTime<MinguoDate> atTime(LocalTime localTime) {
|
||||
return (ChronoLocalDateTime<MinguoDate>)super.atTime(localTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronoPeriod until(ChronoLocalDate endDate) {
|
||||
Period period = isoDate.until(endDate);
|
||||
return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
|
||||
}
|
||||
|
||||
@Override // override for performance
|
||||
public long toEpochDay() {
|
||||
return isoDate.toEpochDay();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this date to another date, including the chronology.
|
||||
* <p>
|
||||
* Compares this {@code MinguoDate} with another ensuring that the date is the same.
|
||||
* <p>
|
||||
* Only objects of type {@code MinguoDate} are compared, other types return false.
|
||||
* To compare the dates of two {@code TemporalAccessor} instances, including dates
|
||||
* in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other date
|
||||
*/
|
||||
@Override // override for performance
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof MinguoDate) {
|
||||
MinguoDate otherDate = (MinguoDate) obj;
|
||||
return this.isoDate.equals(otherDate.isoDate);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for this date.
|
||||
*
|
||||
* @return a suitable hash code based only on the Chronology and the date
|
||||
*/
|
||||
@Override // override for performance
|
||||
public int hashCode() {
|
||||
return getChronology().getId().hashCode() ^ isoDate.hashCode();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the object using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(8); // identifies a MinguoDate
|
||||
* out.writeInt(get(YEAR));
|
||||
* out.writeByte(get(MONTH_OF_YEAR));
|
||||
* out.writeByte(get(DAY_OF_MONTH));
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
private Object writeReplace() {
|
||||
return new Ser(Ser.MINGUO_DATE_TYPE, this);
|
||||
}
|
||||
|
||||
void writeExternal(DataOutput out) throws IOException {
|
||||
// MinguoChronology is implicit in the MINGUO_DATE_TYPE
|
||||
out.writeInt(get(YEAR));
|
||||
out.writeByte(get(MONTH_OF_YEAR));
|
||||
out.writeByte(get(DAY_OF_MONTH));
|
||||
}
|
||||
|
||||
static MinguoDate readExternal(DataInput in) throws IOException {
|
||||
int year = in.readInt();
|
||||
int month = in.readByte();
|
||||
int dayOfMonth = in.readByte();
|
||||
return MinguoChronology.INSTANCE.date(year, month, dayOfMonth);
|
||||
}
|
||||
|
||||
}
|
||||
155
jdkSrc/jdk8/java/time/chrono/MinguoEra.java
Normal file
155
jdkSrc/jdk8/java/time/chrono/MinguoEra.java
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
|
||||
/**
|
||||
* An era in the Minguo calendar system.
|
||||
* <p>
|
||||
* The Minguo calendar system has two eras.
|
||||
* The current era, for years from 1 onwards, is known as the 'Republic of China' era.
|
||||
* All previous years, zero or earlier in the proleptic count or one and greater
|
||||
* in the year-of-era count, are part of the 'Before Republic of China' era.
|
||||
*
|
||||
* <table summary="Minguo years and eras" cellpadding="2" cellspacing="3" border="0" >
|
||||
* <thead>
|
||||
* <tr class="tableSubHeadingColor">
|
||||
* <th class="colFirst" align="left">year-of-era</th>
|
||||
* <th class="colFirst" align="left">era</th>
|
||||
* <th class="colFirst" align="left">proleptic-year</th>
|
||||
* <th class="colLast" align="left">ISO proleptic-year</th>
|
||||
* </tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr class="rowColor">
|
||||
* <td>2</td><td>ROC</td><td>2</td><td>1913</td>
|
||||
* </tr>
|
||||
* <tr class="altColor">
|
||||
* <td>1</td><td>ROC</td><td>1</td><td>1912</td>
|
||||
* </tr>
|
||||
* <tr class="rowColor">
|
||||
* <td>1</td><td>BEFORE_ROC</td><td>0</td><td>1911</td>
|
||||
* </tr>
|
||||
* <tr class="altColor">
|
||||
* <td>2</td><td>BEFORE_ROC</td><td>-1</td><td>1910</td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* <p>
|
||||
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code MinguoEra}.
|
||||
* Use {@code getValue()} instead.</b>
|
||||
*
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public enum MinguoEra implements Era {
|
||||
|
||||
/**
|
||||
* The singleton instance for the era before the current one, 'Before Republic of China Era',
|
||||
* which has the numeric value 0.
|
||||
*/
|
||||
BEFORE_ROC,
|
||||
/**
|
||||
* The singleton instance for the current era, 'Republic of China Era',
|
||||
* which has the numeric value 1.
|
||||
*/
|
||||
ROC;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code MinguoEra} from an {@code int} value.
|
||||
* <p>
|
||||
* {@code MinguoEra} is an enum representing the Minguo eras of BEFORE_ROC/ROC.
|
||||
* This factory allows the enum to be obtained from the {@code int} value.
|
||||
*
|
||||
* @param minguoEra the BEFORE_ROC/ROC value to represent, from 0 (BEFORE_ROC) to 1 (ROC)
|
||||
* @return the era singleton, not null
|
||||
* @throws DateTimeException if the value is invalid
|
||||
*/
|
||||
public static MinguoEra of(int minguoEra) {
|
||||
switch (minguoEra) {
|
||||
case 0:
|
||||
return BEFORE_ROC;
|
||||
case 1:
|
||||
return ROC;
|
||||
default:
|
||||
throw new DateTimeException("Invalid era: " + minguoEra);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the numeric era {@code int} value.
|
||||
* <p>
|
||||
* The era BEFORE_ROC has the value 0, while the era ROC has the value 1.
|
||||
*
|
||||
* @return the era value, from 0 (BEFORE_ROC) to 1 (ROC)
|
||||
*/
|
||||
@Override
|
||||
public int getValue() {
|
||||
return ordinal();
|
||||
}
|
||||
|
||||
}
|
||||
256
jdkSrc/jdk8/java/time/chrono/Ser.java
Normal file
256
jdkSrc/jdk8/java/time/chrono/Ser.java
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidClassException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.StreamCorruptedException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* The shared serialization delegate for this package.
|
||||
*
|
||||
* @implNote
|
||||
* This class wraps the object being serialized, and takes a byte representing the type of the class to
|
||||
* be serialized. This byte can also be used for versioning the serialization format. In this case another
|
||||
* byte flag would be used in order to specify an alternative version of the type format.
|
||||
* For example {@code CHRONO_TYPE_VERSION_2 = 21}
|
||||
* <p>
|
||||
* In order to serialize the object it writes its byte and then calls back to the appropriate class where
|
||||
* the serialization is performed. In order to deserialize the object it read in the type byte, switching
|
||||
* in order to select which class to call back into.
|
||||
* <p>
|
||||
* The serialization format is determined on a per class basis. In the case of field based classes each
|
||||
* of the fields is written out with an appropriate size format in descending order of the field's size. For
|
||||
* example in the case of {@link LocalDate} year is written before month. Composite classes, such as
|
||||
* {@link LocalDateTime} are serialized as one object. Enum classes are serialized using the index of their
|
||||
* element.
|
||||
* <p>
|
||||
* This class is mutable and should be created once per serialization.
|
||||
*
|
||||
* @serial include
|
||||
* @since 1.8
|
||||
*/
|
||||
final class Ser implements Externalizable {
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = -6103370247208168577L;
|
||||
|
||||
static final byte CHRONO_TYPE = 1;
|
||||
static final byte CHRONO_LOCAL_DATE_TIME_TYPE = 2;
|
||||
static final byte CHRONO_ZONE_DATE_TIME_TYPE = 3;
|
||||
static final byte JAPANESE_DATE_TYPE = 4;
|
||||
static final byte JAPANESE_ERA_TYPE = 5;
|
||||
static final byte HIJRAH_DATE_TYPE = 6;
|
||||
static final byte MINGUO_DATE_TYPE = 7;
|
||||
static final byte THAIBUDDHIST_DATE_TYPE = 8;
|
||||
static final byte CHRONO_PERIOD_TYPE = 9;
|
||||
|
||||
/** The type being serialized. */
|
||||
private byte type;
|
||||
/** The object being serialized. */
|
||||
private Object object;
|
||||
|
||||
/**
|
||||
* Constructor for deserialization.
|
||||
*/
|
||||
public Ser() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance for serialization.
|
||||
*
|
||||
* @param type the type
|
||||
* @param object the object
|
||||
*/
|
||||
Ser(byte type, Object object) {
|
||||
this.type = type;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Implements the {@code Externalizable} interface to write the object.
|
||||
* @serialData
|
||||
* Each serializable class is mapped to a type that is the first byte
|
||||
* in the stream. Refer to each class {@code writeReplace}
|
||||
* serialized form for the value of the type and sequence of values for the type.
|
||||
* <ul>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.HijrahChronology">HijrahChronology.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.IsoChronology">IsoChronology.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseChronology">JapaneseChronology.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.MinguoChronology">MinguoChronology.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistChronology">ThaiBuddhistChronology.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.ChronoLocalDateTimeImpl">ChronoLocalDateTime.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.ChronoZonedDateTimeImpl">ChronoZonedDateTime.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseDate">JapaneseDate.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseEra">JapaneseEra.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.HijrahDate">HijrahDate.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.MinguoDate">MinguoDate.writeReplace</a>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistDate">ThaiBuddhistDate.writeReplace</a>
|
||||
* </ul>
|
||||
*
|
||||
* @param out the data stream to write to, not null
|
||||
*/
|
||||
@Override
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
writeInternal(type, object, out);
|
||||
}
|
||||
|
||||
private static void writeInternal(byte type, Object object, ObjectOutput out) throws IOException {
|
||||
out.writeByte(type);
|
||||
switch (type) {
|
||||
case CHRONO_TYPE:
|
||||
((AbstractChronology) object).writeExternal(out);
|
||||
break;
|
||||
case CHRONO_LOCAL_DATE_TIME_TYPE:
|
||||
((ChronoLocalDateTimeImpl<?>) object).writeExternal(out);
|
||||
break;
|
||||
case CHRONO_ZONE_DATE_TIME_TYPE:
|
||||
((ChronoZonedDateTimeImpl<?>) object).writeExternal(out);
|
||||
break;
|
||||
case JAPANESE_DATE_TYPE:
|
||||
((JapaneseDate) object).writeExternal(out);
|
||||
break;
|
||||
case JAPANESE_ERA_TYPE:
|
||||
((JapaneseEra) object).writeExternal(out);
|
||||
break;
|
||||
case HIJRAH_DATE_TYPE:
|
||||
((HijrahDate) object).writeExternal(out);
|
||||
break;
|
||||
case MINGUO_DATE_TYPE:
|
||||
((MinguoDate) object).writeExternal(out);
|
||||
break;
|
||||
case THAIBUDDHIST_DATE_TYPE:
|
||||
((ThaiBuddhistDate) object).writeExternal(out);
|
||||
break;
|
||||
case CHRONO_PERIOD_TYPE:
|
||||
((ChronoPeriodImpl) object).writeExternal(out);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidClassException("Unknown serialized type");
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Implements the {@code Externalizable} interface to read the object.
|
||||
* @serialData
|
||||
* The streamed type and parameters defined by the type's {@code writeReplace}
|
||||
* method are read and passed to the corresponding static factory for the type
|
||||
* to create a new instance. That instance is returned as the de-serialized
|
||||
* {@code Ser} object.
|
||||
*
|
||||
* <ul>
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.HijrahChronology">HijrahChronology</a> - Chronology.of(id)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.IsoChronology">IsoChronology</a> - Chronology.of(id)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseChronology">JapaneseChronology</a> - Chronology.of(id)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.MinguoChronology">MinguoChronology</a> - Chronology.of(id)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistChronology">ThaiBuddhistChronology</a> - Chronology.of(id)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.ChronoLocalDateTimeImpl">ChronoLocalDateTime</a> - date.atTime(time)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.ChronoZonedDateTimeImpl">ChronoZonedDateTime</a> - dateTime.atZone(offset).withZoneSameLocal(zone)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseDate">JapaneseDate</a> - JapaneseChronology.INSTANCE.date(year, month, dayOfMonth)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseEra">JapaneseEra</a> - JapaneseEra.of(eraValue)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.HijrahDate">HijrahDate</a> - HijrahChronology chrono.date(year, month, dayOfMonth)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.MinguoDate">MinguoDate</a> - MinguoChronology.INSTANCE.date(year, month, dayOfMonth)
|
||||
* <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistDate">ThaiBuddhistDate</a> - ThaiBuddhistChronology.INSTANCE.date(year, month, dayOfMonth)
|
||||
* </ul>
|
||||
*
|
||||
* @param in the data stream to read from, not null
|
||||
*/
|
||||
@Override
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
type = in.readByte();
|
||||
object = readInternal(type, in);
|
||||
}
|
||||
|
||||
static Object read(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
byte type = in.readByte();
|
||||
return readInternal(type, in);
|
||||
}
|
||||
|
||||
private static Object readInternal(byte type, ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
switch (type) {
|
||||
case CHRONO_TYPE: return AbstractChronology.readExternal(in);
|
||||
case CHRONO_LOCAL_DATE_TIME_TYPE: return ChronoLocalDateTimeImpl.readExternal(in);
|
||||
case CHRONO_ZONE_DATE_TIME_TYPE: return ChronoZonedDateTimeImpl.readExternal(in);
|
||||
case JAPANESE_DATE_TYPE: return JapaneseDate.readExternal(in);
|
||||
case JAPANESE_ERA_TYPE: return JapaneseEra.readExternal(in);
|
||||
case HIJRAH_DATE_TYPE: return HijrahDate.readExternal(in);
|
||||
case MINGUO_DATE_TYPE: return MinguoDate.readExternal(in);
|
||||
case THAIBUDDHIST_DATE_TYPE: return ThaiBuddhistDate.readExternal(in);
|
||||
case CHRONO_PERIOD_TYPE: return ChronoPeriodImpl.readExternal(in);
|
||||
default: throw new StreamCorruptedException("Unknown serialized type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object that will replace this one.
|
||||
*
|
||||
* @return the read object, should never be null
|
||||
*/
|
||||
private Object readResolve() {
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
||||
400
jdkSrc/jdk8/java/time/chrono/ThaiBuddhistChronology.java
Normal file
400
jdkSrc/jdk8/java/time/chrono/ThaiBuddhistChronology.java
Normal file
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.Clock;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.ResolverStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Thai Buddhist calendar system.
|
||||
* <p>
|
||||
* This chronology defines the rules of the Thai Buddhist calendar system.
|
||||
* This calendar system is primarily used in Thailand.
|
||||
* Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}.
|
||||
* <p>
|
||||
* The fields are defined as follows:
|
||||
* <ul>
|
||||
* <li>era - There are two eras, the current 'Buddhist' (ERA_BE) and the previous era (ERA_BEFORE_BE).
|
||||
* <li>year-of-era - The year-of-era for the current era increases uniformly from the epoch at year one.
|
||||
* For the previous era the year increases from one as time goes backwards.
|
||||
* The value for the current era is equal to the ISO proleptic-year plus 543.
|
||||
* <li>proleptic-year - The proleptic year is the same as the year-of-era for the
|
||||
* current era. For the previous era, years have zero, then negative values.
|
||||
* The value is equal to the ISO proleptic-year plus 543.
|
||||
* <li>month-of-year - The ThaiBuddhist month-of-year exactly matches ISO.
|
||||
* <li>day-of-month - The ThaiBuddhist day-of-month exactly matches ISO.
|
||||
* <li>day-of-year - The ThaiBuddhist day-of-year exactly matches ISO.
|
||||
* <li>leap-year - The ThaiBuddhist leap-year pattern exactly matches ISO, such that the two calendars
|
||||
* are never out of step.
|
||||
* </ul>
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class ThaiBuddhistChronology extends AbstractChronology implements Serializable {
|
||||
|
||||
/**
|
||||
* Singleton instance of the Buddhist chronology.
|
||||
*/
|
||||
public static final ThaiBuddhistChronology INSTANCE = new ThaiBuddhistChronology();
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = 2775954514031616474L;
|
||||
/**
|
||||
* Containing the offset to add to the ISO year.
|
||||
*/
|
||||
static final int YEARS_DIFFERENCE = 543;
|
||||
/**
|
||||
* Narrow names for eras.
|
||||
*/
|
||||
private static final HashMap<String, String[]> ERA_NARROW_NAMES = new HashMap<>();
|
||||
/**
|
||||
* Short names for eras.
|
||||
*/
|
||||
private static final HashMap<String, String[]> ERA_SHORT_NAMES = new HashMap<>();
|
||||
/**
|
||||
* Full names for eras.
|
||||
*/
|
||||
private static final HashMap<String, String[]> ERA_FULL_NAMES = new HashMap<>();
|
||||
/**
|
||||
* Fallback language for the era names.
|
||||
*/
|
||||
private static final String FALLBACK_LANGUAGE = "en";
|
||||
/**
|
||||
* Language that has the era names.
|
||||
*/
|
||||
private static final String TARGET_LANGUAGE = "th";
|
||||
/**
|
||||
* Name data.
|
||||
*/
|
||||
static {
|
||||
ERA_NARROW_NAMES.put(FALLBACK_LANGUAGE, new String[]{"BB", "BE"});
|
||||
ERA_NARROW_NAMES.put(TARGET_LANGUAGE, new String[]{"BB", "BE"});
|
||||
ERA_SHORT_NAMES.put(FALLBACK_LANGUAGE, new String[]{"B.B.", "B.E."});
|
||||
ERA_SHORT_NAMES.put(TARGET_LANGUAGE,
|
||||
new String[]{"\u0e1e.\u0e28.",
|
||||
"\u0e1b\u0e35\u0e01\u0e48\u0e2d\u0e19\u0e04\u0e23\u0e34\u0e2a\u0e15\u0e4c\u0e01\u0e32\u0e25\u0e17\u0e35\u0e48"});
|
||||
ERA_FULL_NAMES.put(FALLBACK_LANGUAGE, new String[]{"Before Buddhist", "Budhhist Era"});
|
||||
ERA_FULL_NAMES.put(TARGET_LANGUAGE,
|
||||
new String[]{"\u0e1e\u0e38\u0e17\u0e18\u0e28\u0e31\u0e01\u0e23\u0e32\u0e0a",
|
||||
"\u0e1b\u0e35\u0e01\u0e48\u0e2d\u0e19\u0e04\u0e23\u0e34\u0e2a\u0e15\u0e4c\u0e01\u0e32\u0e25\u0e17\u0e35\u0e48"});
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricted constructor.
|
||||
*/
|
||||
private ThaiBuddhistChronology() {
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the ID of the chronology - 'ThaiBuddhist'.
|
||||
* <p>
|
||||
* The ID uniquely identifies the {@code Chronology}.
|
||||
* It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
|
||||
*
|
||||
* @return the chronology ID - 'ThaiBuddhist'
|
||||
* @see #getCalendarType()
|
||||
*/
|
||||
@Override
|
||||
public String getId() {
|
||||
return "ThaiBuddhist";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the calendar type of the underlying calendar system - 'buddhist'.
|
||||
* <p>
|
||||
* The calendar type is an identifier defined by the
|
||||
* <em>Unicode Locale Data Markup Language (LDML)</em> specification.
|
||||
* It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
|
||||
* It can also be used as part of a locale, accessible via
|
||||
* {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
|
||||
*
|
||||
* @return the calendar system type - 'buddhist'
|
||||
* @see #getId()
|
||||
*/
|
||||
@Override
|
||||
public String getCalendarType() {
|
||||
return "buddhist";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a local date in Thai Buddhist calendar system from the
|
||||
* era, year-of-era, month-of-year and day-of-month fields.
|
||||
*
|
||||
* @param era the Thai Buddhist era, not null
|
||||
* @param yearOfEra the year-of-era
|
||||
* @param month the month-of-year
|
||||
* @param dayOfMonth the day-of-month
|
||||
* @return the Thai Buddhist local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
* @throws ClassCastException if the {@code era} is not a {@code ThaiBuddhistEra}
|
||||
*/
|
||||
@Override
|
||||
public ThaiBuddhistDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
|
||||
return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in Thai Buddhist calendar system from the
|
||||
* proleptic-year, month-of-year and day-of-month fields.
|
||||
*
|
||||
* @param prolepticYear the proleptic-year
|
||||
* @param month the month-of-year
|
||||
* @param dayOfMonth the day-of-month
|
||||
* @return the Thai Buddhist local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override
|
||||
public ThaiBuddhistDate date(int prolepticYear, int month, int dayOfMonth) {
|
||||
return new ThaiBuddhistDate(LocalDate.of(prolepticYear - YEARS_DIFFERENCE, month, dayOfMonth));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in Thai Buddhist calendar system from the
|
||||
* era, year-of-era and day-of-year fields.
|
||||
*
|
||||
* @param era the Thai Buddhist era, not null
|
||||
* @param yearOfEra the year-of-era
|
||||
* @param dayOfYear the day-of-year
|
||||
* @return the Thai Buddhist local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
* @throws ClassCastException if the {@code era} is not a {@code ThaiBuddhistEra}
|
||||
*/
|
||||
@Override
|
||||
public ThaiBuddhistDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
|
||||
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in Thai Buddhist calendar system from the
|
||||
* proleptic-year and day-of-year fields.
|
||||
*
|
||||
* @param prolepticYear the proleptic-year
|
||||
* @param dayOfYear the day-of-year
|
||||
* @return the Thai Buddhist local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override
|
||||
public ThaiBuddhistDate dateYearDay(int prolepticYear, int dayOfYear) {
|
||||
return new ThaiBuddhistDate(LocalDate.ofYearDay(prolepticYear - YEARS_DIFFERENCE, dayOfYear));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a local date in the Thai Buddhist calendar system from the epoch-day.
|
||||
*
|
||||
* @param epochDay the epoch day
|
||||
* @return the Thai Buddhist local date, not null
|
||||
* @throws DateTimeException if unable to create the date
|
||||
*/
|
||||
@Override // override with covariant return type
|
||||
public ThaiBuddhistDate dateEpochDay(long epochDay) {
|
||||
return new ThaiBuddhistDate(LocalDate.ofEpochDay(epochDay));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThaiBuddhistDate dateNow() {
|
||||
return dateNow(Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThaiBuddhistDate dateNow(ZoneId zone) {
|
||||
return dateNow(Clock.system(zone));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThaiBuddhistDate dateNow(Clock clock) {
|
||||
return date(LocalDate.now(clock));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThaiBuddhistDate date(TemporalAccessor temporal) {
|
||||
if (temporal instanceof ThaiBuddhistDate) {
|
||||
return (ThaiBuddhistDate) temporal;
|
||||
}
|
||||
return new ThaiBuddhistDate(LocalDate.from(temporal));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoLocalDateTime<ThaiBuddhistDate> localDateTime(TemporalAccessor temporal) {
|
||||
return (ChronoLocalDateTime<ThaiBuddhistDate>)super.localDateTime(temporal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoZonedDateTime<ThaiBuddhistDate> zonedDateTime(TemporalAccessor temporal) {
|
||||
return (ChronoZonedDateTime<ThaiBuddhistDate>)super.zonedDateTime(temporal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChronoZonedDateTime<ThaiBuddhistDate> zonedDateTime(Instant instant, ZoneId zone) {
|
||||
return (ChronoZonedDateTime<ThaiBuddhistDate>)super.zonedDateTime(instant, zone);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if the specified year is a leap year.
|
||||
* <p>
|
||||
* Thai Buddhist leap years occur exactly in line with ISO leap years.
|
||||
* This method does not validate the year passed in, and only has a
|
||||
* well-defined result for years in the supported range.
|
||||
*
|
||||
* @param prolepticYear the proleptic-year to check, not validated for range
|
||||
* @return true if the year is a leap year
|
||||
*/
|
||||
@Override
|
||||
public boolean isLeapYear(long prolepticYear) {
|
||||
return IsoChronology.INSTANCE.isLeapYear(prolepticYear - YEARS_DIFFERENCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int prolepticYear(Era era, int yearOfEra) {
|
||||
if (era instanceof ThaiBuddhistEra == false) {
|
||||
throw new ClassCastException("Era must be BuddhistEra");
|
||||
}
|
||||
return (era == ThaiBuddhistEra.BE ? yearOfEra : 1 - yearOfEra);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThaiBuddhistEra eraOf(int eraValue) {
|
||||
return ThaiBuddhistEra.of(eraValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Era> eras() {
|
||||
return Arrays.<Era>asList(ThaiBuddhistEra.values());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ValueRange range(ChronoField field) {
|
||||
switch (field) {
|
||||
case PROLEPTIC_MONTH: {
|
||||
ValueRange range = PROLEPTIC_MONTH.range();
|
||||
return ValueRange.of(range.getMinimum() + YEARS_DIFFERENCE * 12L, range.getMaximum() + YEARS_DIFFERENCE * 12L);
|
||||
}
|
||||
case YEAR_OF_ERA: {
|
||||
ValueRange range = YEAR.range();
|
||||
return ValueRange.of(1, -(range.getMinimum() + YEARS_DIFFERENCE) + 1, range.getMaximum() + YEARS_DIFFERENCE);
|
||||
}
|
||||
case YEAR: {
|
||||
ValueRange range = YEAR.range();
|
||||
return ValueRange.of(range.getMinimum() + YEARS_DIFFERENCE, range.getMaximum() + YEARS_DIFFERENCE);
|
||||
}
|
||||
}
|
||||
return field.range();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override // override for return type
|
||||
public ThaiBuddhistDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
|
||||
return (ThaiBuddhistDate) super.resolveDate(fieldValues, resolverStyle);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Writes the Chronology using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(1); // identifies a Chronology
|
||||
* out.writeUTF(getId());
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
@Override
|
||||
Object writeReplace() {
|
||||
return super.writeReplace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
}
|
||||
519
jdkSrc/jdk8/java/time/chrono/ThaiBuddhistDate.java
Normal file
519
jdkSrc/jdk8/java/time/chrono/ThaiBuddhistDate.java
Normal file
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import static java.time.chrono.ThaiBuddhistChronology.YEARS_DIFFERENCE;
|
||||
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.YEAR;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.Clock;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Period;
|
||||
import java.time.ZoneId;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalAdjuster;
|
||||
import java.time.temporal.TemporalAmount;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.TemporalQuery;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.time.temporal.UnsupportedTemporalTypeException;
|
||||
import java.time.temporal.ValueRange;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A date in the Thai Buddhist calendar system.
|
||||
* <p>
|
||||
* This date operates using the {@linkplain ThaiBuddhistChronology Thai Buddhist calendar}.
|
||||
* This calendar system is primarily used in Thailand.
|
||||
* Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}.
|
||||
*
|
||||
* <p>
|
||||
* This is a <a href="{@docRoot}/java/lang/doc-files/ValueBased.html">value-based</a>
|
||||
* class; use of identity-sensitive operations (including reference equality
|
||||
* ({@code ==}), identity hash code, or synchronization) on instances of
|
||||
* {@code ThaiBuddhistDate} may have unpredictable results and should be avoided.
|
||||
* The {@code equals} method should be used for comparisons.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class ThaiBuddhistDate
|
||||
extends ChronoLocalDateImpl<ThaiBuddhistDate>
|
||||
implements ChronoLocalDate, Serializable {
|
||||
|
||||
/**
|
||||
* Serialization version.
|
||||
*/
|
||||
private static final long serialVersionUID = -8722293800195731463L;
|
||||
|
||||
/**
|
||||
* The underlying date.
|
||||
*/
|
||||
private final transient LocalDate isoDate;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains the current {@code ThaiBuddhistDate} from the system clock in the default time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
|
||||
* time-zone to obtain the current date.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @return the current date using the system clock and default time-zone, not null
|
||||
*/
|
||||
public static ThaiBuddhistDate now() {
|
||||
return now(Clock.systemDefaultZone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current {@code ThaiBuddhistDate} from the system clock in the specified time-zone.
|
||||
* <p>
|
||||
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
|
||||
* Specifying the time-zone avoids dependence on the default time-zone.
|
||||
* <p>
|
||||
* Using this method will prevent the ability to use an alternate clock for testing
|
||||
* because the clock is hard-coded.
|
||||
*
|
||||
* @param zone the zone ID to use, not null
|
||||
* @return the current date using the system clock, not null
|
||||
*/
|
||||
public static ThaiBuddhistDate now(ZoneId zone) {
|
||||
return now(Clock.system(zone));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the current {@code ThaiBuddhistDate} from the specified clock.
|
||||
* <p>
|
||||
* This will query the specified clock to obtain the current date - today.
|
||||
* Using this method allows the use of an alternate clock for testing.
|
||||
* The alternate clock may be introduced using {@linkplain Clock dependency injection}.
|
||||
*
|
||||
* @param clock the clock to use, not null
|
||||
* @return the current date, not null
|
||||
* @throws DateTimeException if the current date cannot be obtained
|
||||
*/
|
||||
public static ThaiBuddhistDate now(Clock clock) {
|
||||
return new ThaiBuddhistDate(LocalDate.now(clock));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code ThaiBuddhistDate} representing a date in the Thai Buddhist calendar
|
||||
* system from the proleptic-year, month-of-year and day-of-month fields.
|
||||
* <p>
|
||||
* This returns a {@code ThaiBuddhistDate} with the specified fields.
|
||||
* The day must be valid for the year and month, otherwise an exception will be thrown.
|
||||
*
|
||||
* @param prolepticYear the Thai Buddhist proleptic-year
|
||||
* @param month the Thai Buddhist month-of-year, from 1 to 12
|
||||
* @param dayOfMonth the Thai Buddhist day-of-month, from 1 to 31
|
||||
* @return the date in Thai Buddhist calendar system, not null
|
||||
* @throws DateTimeException if the value of any field is out of range,
|
||||
* or if the day-of-month is invalid for the month-year
|
||||
*/
|
||||
public static ThaiBuddhistDate of(int prolepticYear, int month, int dayOfMonth) {
|
||||
return new ThaiBuddhistDate(LocalDate.of(prolepticYear - YEARS_DIFFERENCE, month, dayOfMonth));
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a {@code ThaiBuddhistDate} from a temporal object.
|
||||
* <p>
|
||||
* This obtains a date in the Thai Buddhist calendar system based on the specified temporal.
|
||||
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
|
||||
* which this factory converts to an instance of {@code ThaiBuddhistDate}.
|
||||
* <p>
|
||||
* The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
|
||||
* field, which is standardized across calendar systems.
|
||||
* <p>
|
||||
* This method matches the signature of the functional interface {@link TemporalQuery}
|
||||
* allowing it to be used as a query via method reference, {@code ThaiBuddhistDate::from}.
|
||||
*
|
||||
* @param temporal the temporal object to convert, not null
|
||||
* @return the date in Thai Buddhist calendar system, not null
|
||||
* @throws DateTimeException if unable to convert to a {@code ThaiBuddhistDate}
|
||||
*/
|
||||
public static ThaiBuddhistDate from(TemporalAccessor temporal) {
|
||||
return ThaiBuddhistChronology.INSTANCE.date(temporal);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Creates an instance from an ISO date.
|
||||
*
|
||||
* @param isoDate the standard local date, validated not null
|
||||
*/
|
||||
ThaiBuddhistDate(LocalDate isoDate) {
|
||||
Objects.requireNonNull(isoDate, "isoDate");
|
||||
this.isoDate = isoDate;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the chronology of this date, which is the Thai Buddhist calendar system.
|
||||
* <p>
|
||||
* The {@code Chronology} represents the calendar system in use.
|
||||
* The era and other fields in {@link ChronoField} are defined by the chronology.
|
||||
*
|
||||
* @return the Thai Buddhist chronology, not null
|
||||
*/
|
||||
@Override
|
||||
public ThaiBuddhistChronology getChronology() {
|
||||
return ThaiBuddhistChronology.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the era applicable at this date.
|
||||
* <p>
|
||||
* The Thai Buddhist calendar system has two eras, 'BE' and 'BEFORE_BE',
|
||||
* defined by {@link ThaiBuddhistEra}.
|
||||
*
|
||||
* @return the era applicable at this date, not null
|
||||
*/
|
||||
@Override
|
||||
public ThaiBuddhistEra getEra() {
|
||||
return (getProlepticYear() >= 1 ? ThaiBuddhistEra.BE : ThaiBuddhistEra.BEFORE_BE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the month represented by this date.
|
||||
* <p>
|
||||
* This returns the length of the month in days.
|
||||
* Month lengths match those of the ISO calendar system.
|
||||
*
|
||||
* @return the length of the month in days
|
||||
*/
|
||||
@Override
|
||||
public int lengthOfMonth() {
|
||||
return isoDate.lengthOfMonth();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ValueRange range(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
if (isSupported(field)) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
switch (f) {
|
||||
case DAY_OF_MONTH:
|
||||
case DAY_OF_YEAR:
|
||||
case ALIGNED_WEEK_OF_MONTH:
|
||||
return isoDate.range(field);
|
||||
case YEAR_OF_ERA: {
|
||||
ValueRange range = YEAR.range();
|
||||
long max = (getProlepticYear() <= 0 ? -(range.getMinimum() + YEARS_DIFFERENCE) + 1 : range.getMaximum() + YEARS_DIFFERENCE);
|
||||
return ValueRange.of(1, max);
|
||||
}
|
||||
}
|
||||
return getChronology().range(f);
|
||||
}
|
||||
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
|
||||
}
|
||||
return field.rangeRefinedBy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(TemporalField field) {
|
||||
if (field instanceof ChronoField) {
|
||||
switch ((ChronoField) field) {
|
||||
case PROLEPTIC_MONTH:
|
||||
return getProlepticMonth();
|
||||
case YEAR_OF_ERA: {
|
||||
int prolepticYear = getProlepticYear();
|
||||
return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear);
|
||||
}
|
||||
case YEAR:
|
||||
return getProlepticYear();
|
||||
case ERA:
|
||||
return (getProlepticYear() >= 1 ? 1 : 0);
|
||||
}
|
||||
return isoDate.getLong(field);
|
||||
}
|
||||
return field.getFrom(this);
|
||||
}
|
||||
|
||||
private long getProlepticMonth() {
|
||||
return getProlepticYear() * 12L + isoDate.getMonthValue() - 1;
|
||||
}
|
||||
|
||||
private int getProlepticYear() {
|
||||
return isoDate.getYear() + YEARS_DIFFERENCE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
public ThaiBuddhistDate with(TemporalField field, long newValue) {
|
||||
if (field instanceof ChronoField) {
|
||||
ChronoField f = (ChronoField) field;
|
||||
if (getLong(f) == newValue) {
|
||||
return this;
|
||||
}
|
||||
switch (f) {
|
||||
case PROLEPTIC_MONTH:
|
||||
getChronology().range(f).checkValidValue(newValue, f);
|
||||
return plusMonths(newValue - getProlepticMonth());
|
||||
case YEAR_OF_ERA:
|
||||
case YEAR:
|
||||
case ERA: {
|
||||
int nvalue = getChronology().range(f).checkValidIntValue(newValue, f);
|
||||
switch (f) {
|
||||
case YEAR_OF_ERA:
|
||||
return with(isoDate.withYear((getProlepticYear() >= 1 ? nvalue : 1 - nvalue) - YEARS_DIFFERENCE));
|
||||
case YEAR:
|
||||
return with(isoDate.withYear(nvalue - YEARS_DIFFERENCE));
|
||||
case ERA:
|
||||
return with(isoDate.withYear((1 - getProlepticYear()) - YEARS_DIFFERENCE));
|
||||
}
|
||||
}
|
||||
}
|
||||
return with(isoDate.with(field, newValue));
|
||||
}
|
||||
return super.with(field, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ThaiBuddhistDate with(TemporalAdjuster adjuster) {
|
||||
return super.with(adjuster);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ThaiBuddhistDate plus(TemporalAmount amount) {
|
||||
return super.plus(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws DateTimeException {@inheritDoc}
|
||||
* @throws ArithmeticException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ThaiBuddhistDate minus(TemporalAmount amount) {
|
||||
return super.minus(amount);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override
|
||||
ThaiBuddhistDate plusYears(long years) {
|
||||
return with(isoDate.plusYears(years));
|
||||
}
|
||||
|
||||
@Override
|
||||
ThaiBuddhistDate plusMonths(long months) {
|
||||
return with(isoDate.plusMonths(months));
|
||||
}
|
||||
|
||||
@Override
|
||||
ThaiBuddhistDate plusWeeks(long weeksToAdd) {
|
||||
return super.plusWeeks(weeksToAdd);
|
||||
}
|
||||
|
||||
@Override
|
||||
ThaiBuddhistDate plusDays(long days) {
|
||||
return with(isoDate.plusDays(days));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThaiBuddhistDate plus(long amountToAdd, TemporalUnit unit) {
|
||||
return super.plus(amountToAdd, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThaiBuddhistDate minus(long amountToAdd, TemporalUnit unit) {
|
||||
return super.minus(amountToAdd, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
ThaiBuddhistDate minusYears(long yearsToSubtract) {
|
||||
return super.minusYears(yearsToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
ThaiBuddhistDate minusMonths(long monthsToSubtract) {
|
||||
return super.minusMonths(monthsToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
ThaiBuddhistDate minusWeeks(long weeksToSubtract) {
|
||||
return super.minusWeeks(weeksToSubtract);
|
||||
}
|
||||
|
||||
@Override
|
||||
ThaiBuddhistDate minusDays(long daysToSubtract) {
|
||||
return super.minusDays(daysToSubtract);
|
||||
}
|
||||
|
||||
private ThaiBuddhistDate with(LocalDate newDate) {
|
||||
return (newDate.equals(isoDate) ? this : new ThaiBuddhistDate(newDate));
|
||||
}
|
||||
|
||||
@Override // for javadoc and covariant return type
|
||||
@SuppressWarnings("unchecked")
|
||||
public final ChronoLocalDateTime<ThaiBuddhistDate> atTime(LocalTime localTime) {
|
||||
return (ChronoLocalDateTime<ThaiBuddhistDate>) super.atTime(localTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChronoPeriod until(ChronoLocalDate endDate) {
|
||||
Period period = isoDate.until(endDate);
|
||||
return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
|
||||
}
|
||||
|
||||
@Override // override for performance
|
||||
public long toEpochDay() {
|
||||
return isoDate.toEpochDay();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this date to another date, including the chronology.
|
||||
* <p>
|
||||
* Compares this {@code ThaiBuddhistDate} with another ensuring that the date is the same.
|
||||
* <p>
|
||||
* Only objects of type {@code ThaiBuddhistDate} are compared, other types return false.
|
||||
* To compare the dates of two {@code TemporalAccessor} instances, including dates
|
||||
* in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
|
||||
*
|
||||
* @param obj the object to check, null returns false
|
||||
* @return true if this is equal to the other date
|
||||
*/
|
||||
@Override // override for performance
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof ThaiBuddhistDate) {
|
||||
ThaiBuddhistDate otherDate = (ThaiBuddhistDate) obj;
|
||||
return this.isoDate.equals(otherDate.isoDate);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash code for this date.
|
||||
*
|
||||
* @return a suitable hash code based only on the Chronology and the date
|
||||
*/
|
||||
@Override // override for performance
|
||||
public int hashCode() {
|
||||
return getChronology().getId().hashCode() ^ isoDate.hashCode();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Defend against malicious streams.
|
||||
*
|
||||
* @param s the stream to read
|
||||
* @throws InvalidObjectException always
|
||||
*/
|
||||
private void readObject(ObjectInputStream s) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Deserialization via serialization delegate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the object using a
|
||||
* <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
|
||||
* @serialData
|
||||
* <pre>
|
||||
* out.writeByte(10); // identifies a ThaiBuddhistDate
|
||||
* out.writeInt(get(YEAR));
|
||||
* out.writeByte(get(MONTH_OF_YEAR));
|
||||
* out.writeByte(get(DAY_OF_MONTH));
|
||||
* </pre>
|
||||
*
|
||||
* @return the instance of {@code Ser}, not null
|
||||
*/
|
||||
private Object writeReplace() {
|
||||
return new Ser(Ser.THAIBUDDHIST_DATE_TYPE, this);
|
||||
}
|
||||
|
||||
void writeExternal(DataOutput out) throws IOException {
|
||||
// ThaiBuddhistChronology is implicit in the THAIBUDDHIST_DATE_TYPE
|
||||
out.writeInt(this.get(YEAR));
|
||||
out.writeByte(this.get(MONTH_OF_YEAR));
|
||||
out.writeByte(this.get(DAY_OF_MONTH));
|
||||
}
|
||||
|
||||
static ThaiBuddhistDate readExternal(DataInput in) throws IOException {
|
||||
int year = in.readInt();
|
||||
int month = in.readByte();
|
||||
int dayOfMonth = in.readByte();
|
||||
return ThaiBuddhistChronology.INSTANCE.date(year, month, dayOfMonth);
|
||||
}
|
||||
|
||||
}
|
||||
155
jdkSrc/jdk8/java/time/chrono/ThaiBuddhistEra.java
Normal file
155
jdkSrc/jdk8/java/time/chrono/ThaiBuddhistEra.java
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package java.time.chrono;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
|
||||
/**
|
||||
* An era in the Thai Buddhist calendar system.
|
||||
* <p>
|
||||
* The Thai Buddhist calendar system has two eras.
|
||||
* The current era, for years from 1 onwards, is known as the 'Buddhist' era.
|
||||
* All previous years, zero or earlier in the proleptic count or one and greater
|
||||
* in the year-of-era count, are part of the 'Before Buddhist' era.
|
||||
*
|
||||
* <table summary="Buddhist years and eras" cellpadding="2" cellspacing="3" border="0" >
|
||||
* <thead>
|
||||
* <tr class="tableSubHeadingColor">
|
||||
* <th class="colFirst" align="left">year-of-era</th>
|
||||
* <th class="colFirst" align="left">era</th>
|
||||
* <th class="colFirst" align="left">proleptic-year</th>
|
||||
* <th class="colLast" align="left">ISO proleptic-year</th>
|
||||
* </tr>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <tr class="rowColor">
|
||||
* <td>2</td><td>BE</td><td>2</td><td>-542</td>
|
||||
* </tr>
|
||||
* <tr class="altColor">
|
||||
* <td>1</td><td>BE</td><td>1</td><td>-543</td>
|
||||
* </tr>
|
||||
* <tr class="rowColor">
|
||||
* <td>1</td><td>BEFORE_BE</td><td>0</td><td>-544</td>
|
||||
* </tr>
|
||||
* <tr class="altColor">
|
||||
* <td>2</td><td>BEFORE_BE</td><td>-1</td><td>-545</td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* <p>
|
||||
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code ThaiBuddhistEra}.
|
||||
* Use {@code getValue()} instead.</b>
|
||||
*
|
||||
* @implSpec
|
||||
* This is an immutable and thread-safe enum.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public enum ThaiBuddhistEra implements Era {
|
||||
|
||||
/**
|
||||
* The singleton instance for the era before the current one, 'Before Buddhist Era',
|
||||
* which has the numeric value 0.
|
||||
*/
|
||||
BEFORE_BE,
|
||||
/**
|
||||
* The singleton instance for the current era, 'Buddhist Era',
|
||||
* which has the numeric value 1.
|
||||
*/
|
||||
BE;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code ThaiBuddhistEra} from an {@code int} value.
|
||||
* <p>
|
||||
* {@code ThaiBuddhistEra} is an enum representing the Thai Buddhist eras of BEFORE_BE/BE.
|
||||
* This factory allows the enum to be obtained from the {@code int} value.
|
||||
*
|
||||
* @param thaiBuddhistEra the era to represent, from 0 to 1
|
||||
* @return the BuddhistEra singleton, never null
|
||||
* @throws DateTimeException if the era is invalid
|
||||
*/
|
||||
public static ThaiBuddhistEra of(int thaiBuddhistEra) {
|
||||
switch (thaiBuddhistEra) {
|
||||
case 0:
|
||||
return BEFORE_BE;
|
||||
case 1:
|
||||
return BE;
|
||||
default:
|
||||
throw new DateTimeException("Invalid era: " + thaiBuddhistEra);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Gets the numeric era {@code int} value.
|
||||
* <p>
|
||||
* The era BEFORE_BE has the value 0, while the era BE has the value 1.
|
||||
*
|
||||
* @return the era value, from 0 (BEFORE_BE) to 1 (BE)
|
||||
*/
|
||||
@Override
|
||||
public int getValue() {
|
||||
return ordinal();
|
||||
}
|
||||
|
||||
}
|
||||
171
jdkSrc/jdk8/java/time/chrono/package-info.java
Normal file
171
jdkSrc/jdk8/java/time/chrono/package-info.java
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of JSR-310 nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Generic API for calendar systems other than the default ISO.
|
||||
* </p>
|
||||
* <p>
|
||||
* The main API is based around the calendar system defined in ISO-8601.
|
||||
* However, there are other calendar systems, and this package provides basic support for them.
|
||||
* The alternate calendars are provided in the {@link java.time.chrono} package.
|
||||
* </p>
|
||||
* <p>
|
||||
* A calendar system is defined by the {@link java.time.chrono.Chronology} interface,
|
||||
* while a date in a calendar system is defined by the {@link java.time.chrono.ChronoLocalDate} interface.
|
||||
* </p>
|
||||
* <p>
|
||||
* It is intended that applications use the main API whenever possible, including code to read and write
|
||||
* from a persistent data store, such as a database, and to send dates and times across a network.
|
||||
* The "chrono" classes are then used at the user interface level to deal with localized input/output.
|
||||
* See {@link java.time.chrono.ChronoLocalDate ChronoLocalDate}
|
||||
* for a full discussion of the issues.
|
||||
* </p>
|
||||
* <p>
|
||||
* Using non-ISO calendar systems in an application introduces significant extra complexity.
|
||||
* Ensure that the warnings and recommendations in {@code ChronoLocalDate} have been read before
|
||||
* working with the "chrono" interfaces.
|
||||
* </p>
|
||||
* <p>
|
||||
* The supported calendar systems includes:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@link java.time.chrono.HijrahChronology Hijrah calendar}</li>
|
||||
* <li>{@link java.time.chrono.JapaneseChronology Japanese calendar}</li>
|
||||
* <li>{@link java.time.chrono.MinguoChronology Minguo calendar}</li>
|
||||
* <li>{@link java.time.chrono.ThaiBuddhistChronology Thai Buddhist calendar}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h3>Example</h3>
|
||||
* <p>
|
||||
* This example lists todays date for all of the available calendars.
|
||||
* </p>
|
||||
* <pre>
|
||||
* // Enumerate the list of available calendars and print todays date for each.
|
||||
* Set<Chronology> chronos = Chronology.getAvailableChronologies();
|
||||
* for (Chronology chrono : chronos) {
|
||||
* ChronoLocalDate date = chrono.dateNow();
|
||||
* System.out.printf(" %20s: %s%n", chrono.getId(), date.toString());
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* This example creates and uses a date in a named non-ISO calendar system.
|
||||
* </p>
|
||||
* <pre>
|
||||
* // Print the Thai Buddhist date
|
||||
* ChronoLocalDate now1 = Chronology.of("ThaiBuddhist").dateNow();
|
||||
* int day = now1.get(ChronoField.DAY_OF_MONTH);
|
||||
* int dow = now1.get(ChronoField.DAY_OF_WEEK);
|
||||
* int month = now1.get(ChronoField.MONTH_OF_YEAR);
|
||||
* int year = now1.get(ChronoField.YEAR);
|
||||
* System.out.printf(" Today is %s %s %d-%s-%d%n", now1.getChronology().getId(),
|
||||
* dow, day, month, year);
|
||||
* // Print today's date and the last day of the year for the Thai Buddhist Calendar.
|
||||
* ChronoLocalDate first = now1
|
||||
* .with(ChronoField.DAY_OF_MONTH, 1)
|
||||
* .with(ChronoField.MONTH_OF_YEAR, 1);
|
||||
* ChronoLocalDate last = first
|
||||
* .plus(1, ChronoUnit.YEARS)
|
||||
* .minus(1, ChronoUnit.DAYS);
|
||||
* System.out.printf(" %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(),
|
||||
* first, last);
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* This example creates and uses a date in a specific ThaiBuddhist calendar system.
|
||||
* </p>
|
||||
* <pre>
|
||||
* // Print the Thai Buddhist date
|
||||
* ThaiBuddhistDate now1 = ThaiBuddhistDate.now();
|
||||
* int day = now1.get(ChronoField.DAY_OF_MONTH);
|
||||
* int dow = now1.get(ChronoField.DAY_OF_WEEK);
|
||||
* int month = now1.get(ChronoField.MONTH_OF_YEAR);
|
||||
* int year = now1.get(ChronoField.YEAR);
|
||||
* System.out.printf(" Today is %s %s %d-%s-%d%n", now1.getChronology().getId(),
|
||||
* dow, day, month, year);
|
||||
*
|
||||
* // Print today's date and the last day of the year for the Thai Buddhist Calendar.
|
||||
* ThaiBuddhistDate first = now1
|
||||
* .with(ChronoField.DAY_OF_MONTH, 1)
|
||||
* .with(ChronoField.MONTH_OF_YEAR, 1);
|
||||
* ThaiBuddhistDate last = first
|
||||
* .plus(1, ChronoUnit.YEARS)
|
||||
* .minus(1, ChronoUnit.DAYS);
|
||||
* System.out.printf(" %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(),
|
||||
* first, last);
|
||||
* </pre>
|
||||
*
|
||||
* <h3>Package specification</h3>
|
||||
* <p>
|
||||
* Unless otherwise noted, passing a null argument to a constructor or method in any class or interface
|
||||
* in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown.
|
||||
* The Javadoc "@param" definition is used to summarise the null-behavior.
|
||||
* The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method.
|
||||
* </p>
|
||||
* <p>
|
||||
* All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
|
||||
* or a {@link java.time.DateTimeException}.
|
||||
* </p>
|
||||
* @since JDK1.8
|
||||
*/
|
||||
package java.time.chrono;
|
||||
Reference in New Issue
Block a user