1 /* 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * This file is available under and governed by the GNU General Public 28 * License version 2 only, as published by the Free Software Foundation. 29 * However, the following notice accompanied the original version of this 30 * file: 31 * 32 * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos 33 * 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions are met: 38 * 39 * * Redistributions of source code must retain the above copyright notice, 40 * this list of conditions and the following disclaimer. 41 * 42 * * Redistributions in binary form must reproduce the above copyright notice, 43 * this list of conditions and the following disclaimer in the documentation 44 * and/or other materials provided with the distribution. 45 * 46 * * Neither the name of JSR-310 nor the names of its contributors 47 * may be used to endorse or promote products derived from this software 48 * without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 54 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 55 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 56 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 57 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 58 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 59 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 */ 62 package java.time.temporal; 63 64 import java.time.DateTimeException; 65 import java.time.ZoneId; 66 import java.util.Objects; 67 68 /** 69 * Framework-level interface defining read-only access to a temporal object, 70 * such as a date, time, offset or some combination of these. 71 * <p> 72 * This is the base interface type for date, time and offset objects. 73 * It is implemented by those classes that can provide information 74 * as {@linkplain TemporalField fields} or {@linkplain TemporalQuery queries}. 75 * <p> 76 * Most date and time information can be represented as a number. 77 * These are modeled using {@code TemporalField} with the number held using 78 * a {@code long} to handle large values. Year, month and day-of-month are 79 * simple examples of fields, but they also include instant and offsets. 80 * See {@link ChronoField} for the standard set of fields. 81 * <p> 82 * Two pieces of date/time information cannot be represented by numbers, 83 * the {@linkplain java.time.chrono.Chronology chronology} and the {@linkplain ZoneId time-zone}. 84 * These can be accessed via {@linkplain #query(TemporalQuery) queries} using 85 * the static methods defined on {@link TemporalQuery}. 86 * <p> 87 * A sub-interface, {@link Temporal}, extends this definition to one that also 88 * supports adjustment and manipulation on more complete temporal objects. 89 * <p> 90 * This interface is a framework-level interface that should not be widely 91 * used in application code. Instead, applications should create and pass 92 * around instances of concrete types, such as {@code LocalDate}. 93 * There are many reasons for this, part of which is that implementations 94 * of this interface may be in calendar systems other than ISO. 95 * See {@link java.time.chrono.ChronoLocalDate} for a fuller discussion of the issues. 96 * 97 * <h3>Specification for implementors</h3> 98 * This interface places no restrictions on the mutability of implementations, 99 * however immutability is strongly recommended. 100 * 101 * @since 1.8 102 */ 103 public interface TemporalAccessor { 104 105 /** 106 * Checks if the specified field is supported. 107 * <p> 108 * This checks if the date-time can be queried for the specified field. 109 * If false, then calling the {@link #range(TemporalField) range} and {@link #get(TemporalField) get} 110 * methods will throw an exception. 111 * 112 * <h3>Specification for implementors</h3> 113 * Implementations must check and handle all fields defined in {@link ChronoField}. 114 * If the field is supported, then true is returned, otherwise false 115 * <p> 116 * If the field is not a {@code ChronoField}, then the result of this method 117 * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} 118 * passing {@code this} as the argument. 119 * <p> 120 * Implementations must not alter either this object. 121 * 122 * @param field the field to check, null returns false 123 * @return true if this date-time can be queried for the field, false if not 124 */ 125 boolean isSupported(TemporalField field); 126 127 /** 128 * Gets the range of valid values for the specified field. 129 * <p> 130 * All fields can be expressed as a {@code long} integer. 131 * This method returns an object that describes the valid range for that value. 132 * The value of this temporal object is used to enhance the accuracy of the returned range. 133 * If the date-time cannot return the range, because the field is unsupported or for 134 * some other reason, an exception will be thrown. 135 * <p> 136 * Note that the result only describes the minimum and maximum valid values 137 * and it is important not to read too much into them. For example, there 138 * could be values within the range that are invalid for the field. 139 * 140 * <h3>Specification for implementors</h3> 141 * Implementations must check and handle all fields defined in {@link ChronoField}. 142 * If the field is supported, then the range of the field must be returned. 143 * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown. 144 * <p> 145 * If the field is not a {@code ChronoField}, then the result of this method 146 * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessorl)} 147 * passing {@code this} as the argument. 148 * <p> 149 * Implementations must not alter either this object. 150 * <p> 151 * The default implementation must behave equivalent to this code: 152 * <pre> 153 * if (field instanceof ChronoField) { 154 * if (isSupported(field)) { 155 * return field.range(); 156 * } 157 * throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); 158 * } 159 * return field.rangeRefinedBy(this); 160 * </pre> 161 * 162 * @param field the field to query the range for, not null 163 * @return the range of valid values for the field, not null 164 * @throws DateTimeException if the range for the field cannot be obtained 165 * @throws UnsupportedTemporalTypeException if the field is not supported 166 */ 167 default ValueRange range(TemporalField field) { 168 if (field instanceof ChronoField) { 169 if (isSupported(field)) { 170 return field.range(); 171 } 172 throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); 173 } 174 Objects.requireNonNull(field, "field"); 175 return field.rangeRefinedBy(this); 176 } 177 178 /** 179 * Gets the value of the specified field as an {@code int}. 180 * <p> 181 * This queries the date-time for the value for the specified field. 182 * The returned value will always be within the valid range of values for the field. 183 * If the date-time cannot return the value, because the field is unsupported or for 184 * some other reason, an exception will be thrown. 185 * 186 * <h3>Specification for implementors</h3> 187 * Implementations must check and handle all fields defined in {@link ChronoField}. 188 * If the field is supported and has an {@code int} range, then the value of 189 * the field must be returned. 190 * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown. 191 * <p> 192 * If the field is not a {@code ChronoField}, then the result of this method 193 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 194 * passing {@code this} as the argument. 195 * <p> 196 * Implementations must not alter this object. 197 * <p> 198 * The default implementation must behave equivalent to this code: 199 * <pre> 200 * if (range(field).isIntValue()) { 201 * return range(field).checkValidIntValue(getLong(field), field); 202 * } 203 * throw new UnsupportedTemporalTypeException("Invalid field " + field + " + for get() method, use getLong() instead"); 204 * </pre> 205 * 206 * @param field the field to get, not null 207 * @return the value for the field, within the valid range of values 208 * @throws DateTimeException if a value for the field cannot be obtained or 209 * the value is outside the range of valid values for the field 210 * @throws UnsupportedTemporalTypeException if the field is not supported or 211 * the range of values exceeds an {@code int} 212 * @throws ArithmeticException if numeric overflow occurs 213 */ 214 default int get(TemporalField field) { 215 ValueRange range = range(field); 216 if (range.isIntValue() == false) { 217 throw new UnsupportedTemporalTypeException("Invalid field " + field + " + for get() method, use getLong() instead"); 218 } 219 long value = getLong(field); 220 if (range.isValidValue(value) == false) { 221 throw new DateTimeException("Invalid value for " + field + " (valid values " + range + "): " + value); 222 } 223 return (int) value; 224 } 225 226 /** 227 * Gets the value of the specified field as a {@code long}. 228 * <p> 229 * This queries the date-time for the value for the specified field. 230 * The returned value may be outside the valid range of values for the field. 231 * If the date-time cannot return the value, because the field is unsupported or for 232 * some other reason, an exception will be thrown. 233 * 234 * <h3>Specification for implementors</h3> 235 * Implementations must check and handle all fields defined in {@link ChronoField}. 236 * If the field is supported, then the value of the field must be returned. 237 * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown. 238 * <p> 239 * If the field is not a {@code ChronoField}, then the result of this method 240 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 241 * passing {@code this} as the argument. 242 * <p> 243 * Implementations must not alter either this object. 244 * 245 * @param field the field to get, not null 246 * @return the value for the field 247 * @throws DateTimeException if a value for the field cannot be obtained 248 * @throws UnsupportedTemporalTypeException if the field is not supported 249 * @throws ArithmeticException if numeric overflow occurs 250 */ 251 long getLong(TemporalField field); 252 253 /** 254 * Queries this date-time. 255 * <p> 256 * This queries this date-time using the specified query strategy object. 257 * <p> 258 * Queries are a key tool for extracting information from date-times. 259 * They exists to externalize the process of querying, permitting different 260 * approaches, as per the strategy design pattern. 261 * Examples might be a query that checks if the date is the day before February 29th 262 * in a leap year, or calculates the number of days to your next birthday. 263 * <p> 264 * The most common query implementations are method references, such as 265 * {@code LocalDate::from} and {@code ZoneId::from}. 266 * Additional implementations are provided as static methods on {@link TemporalQuery}. 267 * 268 * <h3>Specification for implementors</h3> 269 * The default implementation must behave equivalent to this code: 270 * <pre> 271 * if (query == TemporalQuery.zoneId() || 272 * query == TemporalQuery.chronology() || query == TemporalQuery.precision()) { 273 * return null; 274 * } 275 * return query.queryFrom(this); 276 * </pre> 277 * Future versions are permitted to add further queries to the if statement. 278 * <p> 279 * All classes implementing this interface and overriding this method must call 280 * {@code TemporalAccessor.super.query(query)}. JDK classes may avoid calling 281 * super if they provide behavior equivalent to the default behaviour, however 282 * non-JDK classes may not utilize this optimization and must call {@code super}. 283 * <p> 284 * If the implementation can supply a value for one of the queries listed in the 285 * if statement of the default implementation, then it must do so. 286 * For example, an application-defined {@code HourMin} class storing the hour 287 * and minute must override this method as follows: 288 * <pre> 289 * if (query == TemporalQuery.precision()) { 290 * return MINUTES; 291 * } 292 * return TemporalAccessor.super.query(query); 293 * </pre> 294 * 295 * @param <R> the type of the result 296 * @param query the query to invoke, not null 297 * @return the query result, null may be returned (defined by the query) 298 * @throws DateTimeException if unable to query 299 * @throws ArithmeticException if numeric overflow occurs 300 */ 301 default <R> R query(TemporalQuery<R> query) { 302 if (query == TemporalQuery.zoneId() || query == TemporalQuery.chronology() || query == TemporalQuery.precision()) { 303 return null; 304 } 305 return query.queryFrom(this); 306 } 307 308 }