/* * 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.calendrical; import static java.time.calendrical.ChronoField.OFFSET_SECONDS; import java.time.DateTimeException; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.chrono.Chrono; /** * General low-level access to a date and/or time object. * <p> * This interface is implemented by all date-time classes. It provides access to the state using the * {@link #get(DateTimeField)} and {@link #getLong(DateTimeField)} methods that takes a {@link DateTimeField}. * Access is also provided to any additional state using a query interface through {@link #query(Query)}. This * provides access to the time-zone, precision and calendar system. * <p> * A sub-interface, {@link DateTime}, extends this definition to one that also supports adjustment and * manipulation on more complete date-time objects. * * <h4>Implementation notes</h4> * This interface places no restrictions on implementations and makes no guarantees about their thread-safety. * See {@code DateTime} for a full description of whether to implement this interface. */ public interface DateTimeAccessor { /** * Checks if the specified date-time field is supported. * <p> * This checks if the date-time can be queried for the specified field. If false, then calling the * {@link #range(DateTimeField) range} and {@link #get(DateTimeField) get} methods will throw an exception. * * <h5>Implementation notes</h5> * Implementations must check and handle any fields defined in {@link ChronoField} before delegating on to * the {@link DateTimeField#doRange(DateTimeAccessor) doRange method} on the specified field. * * @param field the field to check, null returns false * @return true if this date-time can be queried for the field, false if not */ boolean isSupported(DateTimeField field); /** * Gets the range of valid values for the specified date-time 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. If the date-time cannot return the range, because the field is unsupported or * for some other reason, an exception will be thrown. * <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. * * <h5>Implementation notes</h5> * Implementations must check and handle any fields defined in {@link ChronoField} before delegating on to * the {@link DateTimeField#doRange(DateTimeAccessor) doRange method} on the specified field. * * @param field the field to get, not null * @return the range of valid values for the field, not null * @throws DateTimeException if the range for the field cannot be obtained */ DateTimeValueRange range(DateTimeField field); /** * Gets the value of the specified date-time field as an {@code int}. * <p> * This queries the date-time for the value for the specified field. The returned value will always be * within the valid range of values for the field. If the date-time cannot return the value, because the * field is unsupported or for some other reason, an exception will be thrown. * * <h5>Implementation notes</h5> * Implementations must check and handle any fields defined in {@link ChronoField} before delegating on to * the {@link DateTimeField#doGet(DateTimeAccessor) doGet method} on the specified 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 DateTimeException if the range of valid values for the field exceeds an {@code int} * @throws DateTimeException if the value is outside the range of valid values for the field * @throws ArithmeticException if numeric overflow occurs */ int get(DateTimeField field); /** * Gets the value of the specified date-time field as a {@code Long}. * <p> * This queries the date-time for the value for the specified field. The returned value may be outside the * valid range of values for the field. If the date-time cannot return the value, because the field is * unsupported or for some other reason, an exception will be thrown. * * <h5>Implementation notes</h5> * Implementations must check and handle any fields defined in {@link ChronoField} before delegating on to * the {@link DateTimeField#doGet(DateTimeAccessor) doGet method} on the specified 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 ArithmeticException if numeric overflow occurs */ long getLong(DateTimeField field); /** * Queries this date-time. * <p> * This queries this date-time using the specified query strategy object. The Query interface has three * special predefined constants - {@code Query.ZONE_ID}, {@code Query.CHRONO} and * {@code Query.TIME_PRECISION}. Other queries may be defined by applications. * * <h5>Implementation notes</h5> * Queries are used for two purposes - general application specific logic, and providing a way to query * those parts of a {@code DateTimeAccessor} that cannot be returned as a {@code long} using a field. * <p> * In use, there is no difference between the two purposes. However, there is a difference in * implementation. It is the responsibility of implementations of this method to return a value for the * three special constants if applicable. Future JDKs are permitted to add further special constants. * <p> * The standard implementation of this method will be similar to the following: * * <pre> * public <R> R query(Query<R> type) { * // only include an if statement if the implementation can return it * if (query == Query.ZONE_ID) return // the ZoneId * if (query == Query.CHRONO) return // the Chrono * if (query == Query.PRECISION) return // the precision * // call default method * return super.query(query); * } * </pre> * If the implementation class has no zone, chronology or precision, then the class can rely totally on the * default implementation. * * @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) */ <R> R query(Query<R> query); // ----------------------------------------------------------------------- /** * Strategy for querying a date-time object. * <p> * This interface allows different kinds of query to be modeled. Examples might be a query that checks if * the date is the day before February 29th in a leap year, or calculates the number of days to your next * birthday. * <p> * Implementations should not normally be used directly. Instead, the {@link DateTimeAccessor#query(Query)} * method must be used: * * <pre> * dateTime = dateTime.query(query); * </pre> * <p> * See {@link DateTimeAdjusters} for a standard set of adjusters, including finding the last day of the * month. * * <h4>Implementation notes</h4> * 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. */ public interface Query<R> { // special constants should be used to extract information from a DateTimeAccessor // that cannot be derived in other ways /** * The special constant for the query for {@code ZoneId}. * <p> * If the target {@code DateTimeAccessor} has a zone ID, then querying it with this constant must return * the chronology. */ Query<ZoneId> ZONE_ID = new Query<ZoneId>() { @Override public ZoneId doQuery(DateTimeAccessor dateTime) { return null; } }; /** * The special constant for the query for {@code Chrono}. * <p> * If the target {@code DateTimeAccessor} has a chronology, then querying it with this constant must * return the chronology. Note that {@code LocalTime} returns null as it is valid for all chronologies. */ Query<Chrono<?>> CHRONO = new Query<Chrono<?>>() { @Override public Chrono<?> doQuery(DateTimeAccessor dateTime) { return null; } }; /** * The special constant for the query for the minimum supported time unit. * <p> * If the target {@code DateTimeAccessor} represents a consistent or complete date-time, date or time then * this must return the smallest precision actually supported. Note that fields such as * {@code NANO_OF_DAY} and {@code NANO_OF_SECOND} are defined to always return ignoring the precision, * thus this is the only way to find the accurate minimum supported unit. * <p> * For example, {@code GregorianCalendar} has a precision of {@code MILLIS}, whereas {@code LocalDate} and * {@code ZoneOffset} have no time precision and thus returns null. */ Query<ChronoUnit> TIME_PRECISION = new Query<ChronoUnit>() { @Override public ChronoUnit doQuery(DateTimeAccessor dateTime) { return null; } }; /** * A query for the {@code ZoneOffset}. * <p> * This query examines the {@link ChronoField#OFFSET_SECONDS offset-seconds} field and uses it to create a * {@code ZoneOffset}. Implementations of {@code DateTimeAccessor} may choose to check for this constant * and return a stored offset directly. */ Query<ZoneOffset> OFFSET = new Query<ZoneOffset>() { @Override public ZoneOffset doQuery(DateTimeAccessor dateTime) { if (dateTime.isSupported(OFFSET_SECONDS)) { return ZoneOffset.ofTotalSeconds(dateTime.get(OFFSET_SECONDS)); } return null; } }; /** * Implementation of the strategy to query the specified date-time object. * <p> * This method is not intended to be called by application code directly. Instead, the * {@link DateTimeAccessor#query(Query)} method must be used: * * <pre> * dateTime = dateTime.query(query); * </pre> * * <h5>Implementation notes</h5> * The implementation queries the input date-time object to return the result. For example, an * implementation might query the date and time, returning the astronomical Julian day as a * {@code BigDecimal}. * <p> * This interface can be used by calendar systems other than ISO. Implementations may choose to document * compatibility with other calendar systems, or validate for it by querying the chronology from the input * object. * * @param dateTime the date-time object to query, not null * @return the queried value, avoid returning null * @throws DateTimeException if unable to query * @throws ArithmeticException if numeric overflow occurs */ R doQuery(DateTimeAccessor dateTime); } }