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) 2007-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 static java.time.temporal.ChronoField.EPOCH_DAY; 65 import static java.time.temporal.ChronoField.NANO_OF_DAY; 66 import static java.time.temporal.ChronoField.OFFSET_SECONDS; 67 68 import java.time.LocalDate; 69 import java.time.LocalTime; 70 import java.time.ZoneId; 71 import java.time.ZoneOffset; 72 import java.time.chrono.Chronology; 73 74 /** 75 * Common implementations of {@code TemporalQuery}. 76 * <p> 77 * This class provides common implementations of {@link TemporalQuery}. 78 * These are defined here as they must be constants, and the definition 79 * of lambdas does not guarantee that. By assigning them once here, 80 * they become 'normal' Java constants. 81 * <p> 82 * Queries are a key tool for extracting information from temporal objects. 83 * They exist to externalize the process of querying, permitting different 84 * approaches, as per the strategy design pattern. 85 * Examples might be a query that checks if the date is the day before February 29th 86 * in a leap year, or calculates the number of days to your next birthday. 87 * <p> 88 * The {@link TemporalField} interface provides another mechanism for querying 89 * temporal objects. That interface is limited to returning a {@code long}. 90 * By contrast, queries can return any type. 91 * <p> 92 * There are two equivalent ways of using a {@code TemporalQuery}. 93 * The first is to invoke the method on this interface directly. 94 * The second is to use {@link TemporalAccessor#query(TemporalQuery)}: 95 * <pre> 96 * // these two lines are equivalent, but the second approach is recommended 97 * temporal = thisQuery.queryFrom(temporal); 98 * temporal = temporal.query(thisQuery); 99 * </pre> 100 * It is recommended to use the second approach, {@code query(TemporalQuery)}, 101 * as it is a lot clearer to read in code. 102 * <p> 103 * The most common implementations are method references, such as 104 * {@code LocalDate::from} and {@code ZoneId::from}. 105 * Additional common queries are provided to return: 106 * <ul> 107 * <li> a Chronology, 108 * <li> a LocalDate, 109 * <li> a LocalTime, 110 * <li> a ZoneOffset, 111 * <li> a precision, 112 * <li> a zone, or 113 * <li> a zoneId. 114 * </ul> 115 * 116 * @since 1.8 117 */ 118 public final class TemporalQueries { 119 // note that it is vital that each method supplies a constant, not a 120 // calculated value, as they will be checked for using == 121 // it is also vital that each constant is different (due to the == checking) 122 // as such, alterations to this code must be done with care 123 124 /** 125 * Private constructor since this is a utility class. 126 */ TemporalQueries()127 private TemporalQueries() { 128 } 129 130 //----------------------------------------------------------------------- 131 // special constants should be used to extract information from a TemporalAccessor 132 // that cannot be derived in other ways 133 // Javadoc added here, so as to pretend they are more normal than they really are 134 135 /** 136 * A strict query for the {@code ZoneId}. 137 * <p> 138 * This queries a {@code TemporalAccessor} for the zone. 139 * The zone is only returned if the date-time conceptually contains a {@code ZoneId}. 140 * It will not be returned if the date-time only conceptually has an {@code ZoneOffset}. 141 * Thus a {@link java.time.ZonedDateTime} will return the result of {@code getZone()}, 142 * but an {@link java.time.OffsetDateTime} will return null. 143 * <p> 144 * In most cases, applications should use {@link #zone()} as this query is too strict. 145 * <p> 146 * The result from JDK classes implementing {@code TemporalAccessor} is as follows:<br> 147 * {@code LocalDate} returns null<br> 148 * {@code LocalTime} returns null<br> 149 * {@code LocalDateTime} returns null<br> 150 * {@code ZonedDateTime} returns the associated zone<br> 151 * {@code OffsetTime} returns null<br> 152 * {@code OffsetDateTime} returns null<br> 153 * {@code ChronoLocalDate} returns null<br> 154 * {@code ChronoLocalDateTime} returns null<br> 155 * {@code ChronoZonedDateTime} returns the associated zone<br> 156 * {@code Era} returns null<br> 157 * {@code DayOfWeek} returns null<br> 158 * {@code Month} returns null<br> 159 * {@code Year} returns null<br> 160 * {@code YearMonth} returns null<br> 161 * {@code MonthDay} returns null<br> 162 * {@code ZoneOffset} returns null<br> 163 * {@code Instant} returns null<br> 164 * 165 * @return a query that can obtain the zone ID of a temporal, not null 166 */ zoneId()167 public static TemporalQuery<ZoneId> zoneId() { 168 return TemporalQueries.ZONE_ID; 169 } 170 171 /** 172 * A query for the {@code Chronology}. 173 * <p> 174 * This queries a {@code TemporalAccessor} for the chronology. 175 * If the target {@code TemporalAccessor} represents a date, or part of a date, 176 * then it should return the chronology that the date is expressed in. 177 * As a result of this definition, objects only representing time, such as 178 * {@code LocalTime}, will return null. 179 * <p> 180 * The result from JDK classes implementing {@code TemporalAccessor} is as follows:<br> 181 * {@code LocalDate} returns {@code IsoChronology.INSTANCE}<br> 182 * {@code LocalTime} returns null (does not represent a date)<br> 183 * {@code LocalDateTime} returns {@code IsoChronology.INSTANCE}<br> 184 * {@code ZonedDateTime} returns {@code IsoChronology.INSTANCE}<br> 185 * {@code OffsetTime} returns null (does not represent a date)<br> 186 * {@code OffsetDateTime} returns {@code IsoChronology.INSTANCE}<br> 187 * {@code ChronoLocalDate} returns the associated chronology<br> 188 * {@code ChronoLocalDateTime} returns the associated chronology<br> 189 * {@code ChronoZonedDateTime} returns the associated chronology<br> 190 * {@code Era} returns the associated chronology<br> 191 * {@code DayOfWeek} returns null (shared across chronologies)<br> 192 * {@code Month} returns {@code IsoChronology.INSTANCE}<br> 193 * {@code Year} returns {@code IsoChronology.INSTANCE}<br> 194 * {@code YearMonth} returns {@code IsoChronology.INSTANCE}<br> 195 * {@code MonthDay} returns null {@code IsoChronology.INSTANCE}<br> 196 * {@code ZoneOffset} returns null (does not represent a date)<br> 197 * {@code Instant} returns null (does not represent a date)<br> 198 * <p> 199 * The method {@link java.time.chrono.Chronology#from(TemporalAccessor)} can be used as a 200 * {@code TemporalQuery} via a method reference, {@code Chronology::from}. 201 * That method is equivalent to this query, except that it throws an 202 * exception if a chronology cannot be obtained. 203 * 204 * @return a query that can obtain the chronology of a temporal, not null 205 */ chronology()206 public static TemporalQuery<Chronology> chronology() { 207 return TemporalQueries.CHRONO; 208 } 209 210 /** 211 * A query for the smallest supported unit. 212 * <p> 213 * This queries a {@code TemporalAccessor} for the time precision. 214 * If the target {@code TemporalAccessor} represents a consistent or complete date-time, 215 * date or time then this must return the smallest precision actually supported. 216 * Note that fields such as {@code NANO_OF_DAY} and {@code NANO_OF_SECOND} 217 * are defined to always return ignoring the precision, thus this is the only 218 * way to find the actual smallest supported unit. 219 * For example, were {@code GregorianCalendar} to implement {@code TemporalAccessor} 220 * it would return a precision of {@code MILLIS}. 221 * <p> 222 * The result from JDK classes implementing {@code TemporalAccessor} is as follows:<br> 223 * {@code LocalDate} returns {@code DAYS}<br> 224 * {@code LocalTime} returns {@code NANOS}<br> 225 * {@code LocalDateTime} returns {@code NANOS}<br> 226 * {@code ZonedDateTime} returns {@code NANOS}<br> 227 * {@code OffsetTime} returns {@code NANOS}<br> 228 * {@code OffsetDateTime} returns {@code NANOS}<br> 229 * {@code ChronoLocalDate} returns {@code DAYS}<br> 230 * {@code ChronoLocalDateTime} returns {@code NANOS}<br> 231 * {@code ChronoZonedDateTime} returns {@code NANOS}<br> 232 * {@code Era} returns {@code ERAS}<br> 233 * {@code DayOfWeek} returns {@code DAYS}<br> 234 * {@code Month} returns {@code MONTHS}<br> 235 * {@code Year} returns {@code YEARS}<br> 236 * {@code YearMonth} returns {@code MONTHS}<br> 237 * {@code MonthDay} returns null (does not represent a complete date or time)<br> 238 * {@code ZoneOffset} returns null (does not represent a date or time)<br> 239 * {@code Instant} returns {@code NANOS}<br> 240 * 241 * @return a query that can obtain the precision of a temporal, not null 242 */ precision()243 public static TemporalQuery<TemporalUnit> precision() { 244 return TemporalQueries.PRECISION; 245 } 246 247 //----------------------------------------------------------------------- 248 // non-special constants are standard queries that derive information from other information 249 /** 250 * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}. 251 * <p> 252 * This queries a {@code TemporalAccessor} for the zone. 253 * It first tries to obtain the zone, using {@link #zoneId()}. 254 * If that is not found it tries to obtain the {@link #offset()}. 255 * Thus a {@link java.time.ZonedDateTime} will return the result of {@code getZone()}, 256 * while an {@link java.time.OffsetDateTime} will return the result of {@code getOffset()}. 257 * <p> 258 * In most cases, applications should use this query rather than {@code #zoneId()}. 259 * <p> 260 * The method {@link ZoneId#from(TemporalAccessor)} can be used as a 261 * {@code TemporalQuery} via a method reference, {@code ZoneId::from}. 262 * That method is equivalent to this query, except that it throws an 263 * exception if a zone cannot be obtained. 264 * 265 * @return a query that can obtain the zone ID or offset of a temporal, not null 266 */ zone()267 public static TemporalQuery<ZoneId> zone() { 268 return TemporalQueries.ZONE; 269 } 270 271 /** 272 * A query for {@code ZoneOffset} returning null if not found. 273 * <p> 274 * This returns a {@code TemporalQuery} that can be used to query a temporal 275 * object for the offset. The query will return null if the temporal 276 * object cannot supply an offset. 277 * <p> 278 * The query implementation examines the {@link ChronoField#OFFSET_SECONDS OFFSET_SECONDS} 279 * field and uses it to create a {@code ZoneOffset}. 280 * <p> 281 * The method {@link java.time.ZoneOffset#from(TemporalAccessor)} can be used as a 282 * {@code TemporalQuery} via a method reference, {@code ZoneOffset::from}. 283 * This query and {@code ZoneOffset::from} will return the same result if the 284 * temporal object contains an offset. If the temporal object does not contain 285 * an offset, then the method reference will throw an exception, whereas this 286 * query will return null. 287 * 288 * @return a query that can obtain the offset of a temporal, not null 289 */ offset()290 public static TemporalQuery<ZoneOffset> offset() { 291 return TemporalQueries.OFFSET; 292 } 293 294 /** 295 * A query for {@code LocalDate} returning null if not found. 296 * <p> 297 * This returns a {@code TemporalQuery} that can be used to query a temporal 298 * object for the local date. The query will return null if the temporal 299 * object cannot supply a local date. 300 * <p> 301 * The query implementation examines the {@link ChronoField#EPOCH_DAY EPOCH_DAY} 302 * field and uses it to create a {@code LocalDate}. 303 * <p> 304 * The method {@link ZoneOffset#from(TemporalAccessor)} can be used as a 305 * {@code TemporalQuery} via a method reference, {@code LocalDate::from}. 306 * This query and {@code LocalDate::from} will return the same result if the 307 * temporal object contains a date. If the temporal object does not contain 308 * a date, then the method reference will throw an exception, whereas this 309 * query will return null. 310 * 311 * @return a query that can obtain the date of a temporal, not null 312 */ localDate()313 public static TemporalQuery<LocalDate> localDate() { 314 return TemporalQueries.LOCAL_DATE; 315 } 316 317 /** 318 * A query for {@code LocalTime} returning null if not found. 319 * <p> 320 * This returns a {@code TemporalQuery} that can be used to query a temporal 321 * object for the local time. The query will return null if the temporal 322 * object cannot supply a local time. 323 * <p> 324 * The query implementation examines the {@link ChronoField#NANO_OF_DAY NANO_OF_DAY} 325 * field and uses it to create a {@code LocalTime}. 326 * <p> 327 * The method {@link ZoneOffset#from(TemporalAccessor)} can be used as a 328 * {@code TemporalQuery} via a method reference, {@code LocalTime::from}. 329 * This query and {@code LocalTime::from} will return the same result if the 330 * temporal object contains a time. If the temporal object does not contain 331 * a time, then the method reference will throw an exception, whereas this 332 * query will return null. 333 * 334 * @return a query that can obtain the time of a temporal, not null 335 */ localTime()336 public static TemporalQuery<LocalTime> localTime() { 337 return TemporalQueries.LOCAL_TIME; 338 } 339 340 //----------------------------------------------------------------------- 341 /** 342 * A strict query for the {@code ZoneId}. 343 */ 344 static final TemporalQuery<ZoneId> ZONE_ID = new TemporalQuery<>() { 345 @Override 346 public ZoneId queryFrom(TemporalAccessor temporal) { 347 return temporal.query(TemporalQueries.ZONE_ID); 348 } 349 350 @Override 351 public String toString() { 352 return "ZoneId"; 353 } 354 }; 355 356 /** 357 * A query for the {@code Chronology}. 358 */ 359 static final TemporalQuery<Chronology> CHRONO = new TemporalQuery<>() { 360 @Override 361 public Chronology queryFrom(TemporalAccessor temporal) { 362 return temporal.query(TemporalQueries.CHRONO); 363 } 364 365 @Override 366 public String toString() { 367 return "Chronology"; 368 } 369 }; 370 371 372 /** 373 * A query for the smallest supported unit. 374 */ 375 static final TemporalQuery<TemporalUnit> PRECISION = new TemporalQuery<>() { 376 @Override 377 public TemporalUnit queryFrom(TemporalAccessor temporal) { 378 return temporal.query(TemporalQueries.PRECISION); 379 } 380 381 @Override 382 public String toString() { 383 return "Precision"; 384 } 385 }; 386 387 //----------------------------------------------------------------------- 388 /** 389 * A query for {@code ZoneOffset} returning null if not found. 390 */ 391 static final TemporalQuery<ZoneOffset> OFFSET = new TemporalQuery<>() { 392 @Override 393 public ZoneOffset queryFrom(TemporalAccessor temporal) { 394 if (temporal.isSupported(OFFSET_SECONDS)) { 395 return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS)); 396 } 397 return null; 398 } 399 400 @Override 401 public String toString() { 402 return "ZoneOffset"; 403 } 404 }; 405 406 /** 407 * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}. 408 */ 409 static final TemporalQuery<ZoneId> ZONE = new TemporalQuery<>() { 410 @Override 411 public ZoneId queryFrom(TemporalAccessor temporal) { 412 ZoneId zone = temporal.query(ZONE_ID); 413 return (zone != null ? zone : temporal.query(OFFSET)); 414 } 415 416 @Override 417 public String toString() { 418 return "Zone"; 419 } 420 }; 421 422 /** 423 * A query for {@code LocalDate} returning null if not found. 424 */ 425 static final TemporalQuery<LocalDate> LOCAL_DATE = new TemporalQuery<>() { 426 @Override 427 public LocalDate queryFrom(TemporalAccessor temporal) { 428 if (temporal.isSupported(EPOCH_DAY)) { 429 return LocalDate.ofEpochDay(temporal.getLong(EPOCH_DAY)); 430 } 431 return null; 432 } 433 434 @Override 435 public String toString() { 436 return "LocalDate"; 437 } 438 }; 439 440 /** 441 * A query for {@code LocalTime} returning null if not found. 442 */ 443 static final TemporalQuery<LocalTime> LOCAL_TIME = new TemporalQuery<>() { 444 @Override 445 public LocalTime queryFrom(TemporalAccessor temporal) { 446 if (temporal.isSupported(NANO_OF_DAY)) { 447 return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY)); 448 } 449 return null; 450 } 451 452 @Override 453 public String toString() { 454 return "LocalTime"; 455 } 456 }; 457 458 } 459