1 /* 2 * Copyright (c) 2012, 2019, 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.chrono; 63 64 import static java.time.temporal.ChronoField.DAY_OF_MONTH; 65 import static java.time.temporal.ChronoField.ERA; 66 import static java.time.temporal.ChronoField.HOUR_OF_DAY; 67 import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; 68 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 69 import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; 70 import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; 71 import static java.time.temporal.ChronoField.YEAR; 72 import static java.time.temporal.ChronoField.YEAR_OF_ERA; 73 74 import java.io.InvalidObjectException; 75 import java.io.ObjectInputStream; 76 import java.io.Serializable; 77 import java.time.Clock; 78 import java.time.DateTimeException; 79 import java.time.Instant; 80 import java.time.LocalDate; 81 import java.time.LocalDateTime; 82 import java.time.Month; 83 import java.time.Period; 84 import java.time.Year; 85 import java.time.ZonedDateTime; 86 import java.time.ZoneId; 87 import java.time.ZoneOffset; 88 import java.time.format.ResolverStyle; 89 import java.time.temporal.ChronoField; 90 import java.time.temporal.TemporalAccessor; 91 import java.time.temporal.TemporalField; 92 import java.time.temporal.ValueRange; 93 import java.util.List; 94 import java.util.Locale; 95 import java.util.Map; 96 import java.util.Objects; 97 98 /** 99 * The ISO calendar system. 100 * <p> 101 * This chronology defines the rules of the ISO calendar system. 102 * This calendar system is based on the ISO-8601 standard, which is the 103 * <i>de facto</i> world calendar. 104 * <p> 105 * The fields are defined as follows: 106 * <ul> 107 * <li>era - There are two eras, 'Current Era' (CE) and 'Before Current Era' (BCE). 108 * <li>year-of-era - The year-of-era is the same as the proleptic-year for the current CE era. 109 * For the BCE era before the ISO epoch the year increases from 1 upwards as time goes backwards. 110 * <li>proleptic-year - The proleptic year is the same as the year-of-era for the 111 * current era. For the previous era, years have zero, then negative values. 112 * <li>month-of-year - There are 12 months in an ISO year, numbered from 1 to 12. 113 * <li>day-of-month - There are between 28 and 31 days in each of the ISO month, numbered from 1 to 31. 114 * Months 4, 6, 9 and 11 have 30 days, Months 1, 3, 5, 7, 8, 10 and 12 have 31 days. 115 * Month 2 has 28 days, or 29 in a leap year. 116 * <li>day-of-year - There are 365 days in a standard ISO year and 366 in a leap year. 117 * The days are numbered from 1 to 365 or 1 to 366. 118 * <li>leap-year - Leap years occur every 4 years, except where the year is divisble by 100 and not divisble by 400. 119 * </ul> 120 * 121 * @implSpec 122 * This class is immutable and thread-safe. 123 * 124 * @since 1.8 125 */ 126 public final class IsoChronology extends AbstractChronology implements Serializable { 127 128 /** 129 * Singleton instance of the ISO chronology. 130 */ 131 public static final IsoChronology INSTANCE = new IsoChronology(); 132 133 /** 134 * Serialization version. 135 */ 136 @java.io.Serial 137 private static final long serialVersionUID = -1440403870442975015L; 138 139 private static final long DAYS_0000_TO_1970 = (146097 * 5L) - (30L * 365L + 7L); // taken from LocalDate 140 141 /** 142 * Restricted constructor. 143 */ IsoChronology()144 private IsoChronology() { 145 } 146 147 //----------------------------------------------------------------------- 148 /** 149 * Gets the ID of the chronology - 'ISO'. 150 * <p> 151 * The ID uniquely identifies the {@code Chronology}. 152 * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. 153 * 154 * @return the chronology ID - 'ISO' 155 * @see #getCalendarType() 156 */ 157 @Override getId()158 public String getId() { 159 return "ISO"; 160 } 161 162 /** 163 * Gets the calendar type of the underlying calendar system - 'iso8601'. 164 * <p> 165 * The calendar type is an identifier defined by the 166 * <em>Unicode Locale Data Markup Language (LDML)</em> specification. 167 * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. 168 * It can also be used as part of a locale, accessible via 169 * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. 170 * 171 * @return the calendar system type - 'iso8601' 172 * @see #getId() 173 */ 174 @Override getCalendarType()175 public String getCalendarType() { 176 return "iso8601"; 177 } 178 179 //----------------------------------------------------------------------- 180 /** 181 * Obtains an ISO local date from the era, year-of-era, month-of-year 182 * and day-of-month fields. 183 * 184 * @param era the ISO era, not null 185 * @param yearOfEra the ISO year-of-era 186 * @param month the ISO month-of-year 187 * @param dayOfMonth the ISO day-of-month 188 * @return the ISO local date, not null 189 * @throws DateTimeException if unable to create the date 190 * @throws ClassCastException if the type of {@code era} is not {@code IsoEra} 191 */ 192 @Override // override with covariant return type date(Era era, int yearOfEra, int month, int dayOfMonth)193 public LocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) { 194 return date(prolepticYear(era, yearOfEra), month, dayOfMonth); 195 } 196 197 /** 198 * Obtains an ISO local date from the proleptic-year, month-of-year 199 * and day-of-month fields. 200 * <p> 201 * This is equivalent to {@link LocalDate#of(int, int, int)}. 202 * 203 * @param prolepticYear the ISO proleptic-year 204 * @param month the ISO month-of-year 205 * @param dayOfMonth the ISO day-of-month 206 * @return the ISO local date, not null 207 * @throws DateTimeException if unable to create the date 208 */ 209 @Override // override with covariant return type date(int prolepticYear, int month, int dayOfMonth)210 public LocalDate date(int prolepticYear, int month, int dayOfMonth) { 211 return LocalDate.of(prolepticYear, month, dayOfMonth); 212 } 213 214 /** 215 * Obtains an ISO local date from the era, year-of-era and day-of-year fields. 216 * 217 * @param era the ISO era, not null 218 * @param yearOfEra the ISO year-of-era 219 * @param dayOfYear the ISO day-of-year 220 * @return the ISO local date, not null 221 * @throws DateTimeException if unable to create the date 222 */ 223 @Override // override with covariant return type dateYearDay(Era era, int yearOfEra, int dayOfYear)224 public LocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { 225 return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); 226 } 227 228 /** 229 * Obtains an ISO local date from the proleptic-year and day-of-year fields. 230 * <p> 231 * This is equivalent to {@link LocalDate#ofYearDay(int, int)}. 232 * 233 * @param prolepticYear the ISO proleptic-year 234 * @param dayOfYear the ISO day-of-year 235 * @return the ISO local date, not null 236 * @throws DateTimeException if unable to create the date 237 */ 238 @Override // override with covariant return type dateYearDay(int prolepticYear, int dayOfYear)239 public LocalDate dateYearDay(int prolepticYear, int dayOfYear) { 240 return LocalDate.ofYearDay(prolepticYear, dayOfYear); 241 } 242 243 /** 244 * Obtains an ISO local date from the epoch-day. 245 * <p> 246 * This is equivalent to {@link LocalDate#ofEpochDay(long)}. 247 * 248 * @param epochDay the epoch day 249 * @return the ISO local date, not null 250 * @throws DateTimeException if unable to create the date 251 */ 252 @Override // override with covariant return type dateEpochDay(long epochDay)253 public LocalDate dateEpochDay(long epochDay) { 254 return LocalDate.ofEpochDay(epochDay); 255 } 256 257 //----------------------------------------------------------------------- 258 /** 259 * Obtains an ISO local date from another date-time object. 260 * <p> 261 * This is equivalent to {@link LocalDate#from(TemporalAccessor)}. 262 * 263 * @param temporal the date-time object to convert, not null 264 * @return the ISO local date, not null 265 * @throws DateTimeException if unable to create the date 266 */ 267 @Override // override with covariant return type date(TemporalAccessor temporal)268 public LocalDate date(TemporalAccessor temporal) { 269 return LocalDate.from(temporal); 270 } 271 272 //----------------------------------------------------------------------- 273 /** 274 * Gets the number of seconds from the epoch of 1970-01-01T00:00:00Z. 275 * <p> 276 * The number of seconds is calculated using the year, 277 * month, day-of-month, hour, minute, second, and zoneOffset. 278 * 279 * @param prolepticYear the year, from MIN_YEAR to MAX_YEAR 280 * @param month the month-of-year, from 1 to 12 281 * @param dayOfMonth the day-of-month, from 1 to 31 282 * @param hour the hour-of-day, from 0 to 23 283 * @param minute the minute-of-hour, from 0 to 59 284 * @param second the second-of-minute, from 0 to 59 285 * @param zoneOffset the zone offset, not null 286 * @return the number of seconds relative to 1970-01-01T00:00:00Z, may be negative 287 * @throws DateTimeException if the value of any argument is out of range, 288 * or if the day-of-month is invalid for the month-of-year 289 * @since 9 290 */ 291 @Override epochSecond(int prolepticYear, int month, int dayOfMonth, int hour, int minute, int second, ZoneOffset zoneOffset)292 public long epochSecond(int prolepticYear, int month, int dayOfMonth, 293 int hour, int minute, int second, ZoneOffset zoneOffset) { 294 YEAR.checkValidValue(prolepticYear); 295 MONTH_OF_YEAR.checkValidValue(month); 296 DAY_OF_MONTH.checkValidValue(dayOfMonth); 297 HOUR_OF_DAY.checkValidValue(hour); 298 MINUTE_OF_HOUR.checkValidValue(minute); 299 SECOND_OF_MINUTE.checkValidValue(second); 300 Objects.requireNonNull(zoneOffset, "zoneOffset"); 301 if (dayOfMonth > 28) { 302 int dom = numberOfDaysOfMonth(prolepticYear, month); 303 if (dayOfMonth > dom) { 304 if (dayOfMonth == 29) { 305 throw new DateTimeException("Invalid date 'February 29' as '" + prolepticYear + "' is not a leap year"); 306 } else { 307 throw new DateTimeException("Invalid date '" + Month.of(month).name() + " " + dayOfMonth + "'"); 308 } 309 } 310 } 311 312 long totalDays = 0; 313 int timeinSec = 0; 314 totalDays += 365L * prolepticYear; 315 if (prolepticYear >= 0) { 316 totalDays += (prolepticYear + 3L) / 4 - (prolepticYear + 99L) / 100 + (prolepticYear + 399L) / 400; 317 } else { 318 totalDays -= prolepticYear / -4 - prolepticYear / -100 + prolepticYear / -400; 319 } 320 totalDays += (367 * month - 362) / 12; 321 totalDays += dayOfMonth - 1; 322 if (month > 2) { 323 totalDays--; 324 if (IsoChronology.INSTANCE.isLeapYear(prolepticYear) == false) { 325 totalDays--; 326 } 327 } 328 totalDays -= DAYS_0000_TO_1970; 329 timeinSec = (hour * 60 + minute ) * 60 + second; 330 return Math.addExact(Math.multiplyExact(totalDays, 86400L), timeinSec - zoneOffset.getTotalSeconds()); 331 } 332 333 /** 334 * Gets the number of days for the given month in the given year. 335 * 336 * @param year the year to represent, from MIN_YEAR to MAX_YEAR 337 * @param month the month-of-year to represent, from 1 to 12 338 * @return the number of days for the given month in the given year 339 */ numberOfDaysOfMonth(int year, int month)340 private int numberOfDaysOfMonth(int year, int month) { 341 int dom; 342 switch (month) { 343 case 2: 344 dom = (IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28); 345 break; 346 case 4: 347 case 6: 348 case 9: 349 case 11: 350 dom = 30; 351 break; 352 default: 353 dom = 31; 354 break; 355 } 356 return dom; 357 } 358 359 360 /** 361 * Obtains an ISO local date-time from another date-time object. 362 * <p> 363 * This is equivalent to {@link LocalDateTime#from(TemporalAccessor)}. 364 * 365 * @param temporal the date-time object to convert, not null 366 * @return the ISO local date-time, not null 367 * @throws DateTimeException if unable to create the date-time 368 */ 369 @Override // override with covariant return type localDateTime(TemporalAccessor temporal)370 public LocalDateTime localDateTime(TemporalAccessor temporal) { 371 return LocalDateTime.from(temporal); 372 } 373 374 /** 375 * Obtains an ISO zoned date-time from another date-time object. 376 * <p> 377 * This is equivalent to {@link ZonedDateTime#from(TemporalAccessor)}. 378 * 379 * @param temporal the date-time object to convert, not null 380 * @return the ISO zoned date-time, not null 381 * @throws DateTimeException if unable to create the date-time 382 */ 383 @Override // override with covariant return type zonedDateTime(TemporalAccessor temporal)384 public ZonedDateTime zonedDateTime(TemporalAccessor temporal) { 385 return ZonedDateTime.from(temporal); 386 } 387 388 /** 389 * Obtains an ISO zoned date-time in this chronology from an {@code Instant}. 390 * <p> 391 * This is equivalent to {@link ZonedDateTime#ofInstant(Instant, ZoneId)}. 392 * 393 * @param instant the instant to create the date-time from, not null 394 * @param zone the time-zone, not null 395 * @return the zoned date-time, not null 396 * @throws DateTimeException if the result exceeds the supported range 397 */ 398 @Override zonedDateTime(Instant instant, ZoneId zone)399 public ZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { 400 return ZonedDateTime.ofInstant(instant, zone); 401 } 402 403 //----------------------------------------------------------------------- 404 /** 405 * Obtains the current ISO local date from the system clock in the default time-zone. 406 * <p> 407 * This will query the {@link Clock#systemDefaultZone() system clock} in the default 408 * time-zone to obtain the current date. 409 * <p> 410 * Using this method will prevent the ability to use an alternate clock for testing 411 * because the clock is hard-coded. 412 * 413 * @return the current ISO local date using the system clock and default time-zone, not null 414 * @throws DateTimeException if unable to create the date 415 */ 416 @Override // override with covariant return type dateNow()417 public LocalDate dateNow() { 418 return dateNow(Clock.systemDefaultZone()); 419 } 420 421 /** 422 * Obtains the current ISO local date from the system clock in the specified time-zone. 423 * <p> 424 * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date. 425 * Specifying the time-zone avoids dependence on the default time-zone. 426 * <p> 427 * Using this method will prevent the ability to use an alternate clock for testing 428 * because the clock is hard-coded. 429 * 430 * @return the current ISO local date using the system clock, not null 431 * @throws DateTimeException if unable to create the date 432 */ 433 @Override // override with covariant return type dateNow(ZoneId zone)434 public LocalDate dateNow(ZoneId zone) { 435 return dateNow(Clock.system(zone)); 436 } 437 438 /** 439 * Obtains the current ISO local date from the specified clock. 440 * <p> 441 * This will query the specified clock to obtain the current date - today. 442 * Using this method allows the use of an alternate clock for testing. 443 * The alternate clock may be introduced using {@link Clock dependency injection}. 444 * 445 * @param clock the clock to use, not null 446 * @return the current ISO local date, not null 447 * @throws DateTimeException if unable to create the date 448 */ 449 @Override // override with covariant return type dateNow(Clock clock)450 public LocalDate dateNow(Clock clock) { 451 Objects.requireNonNull(clock, "clock"); 452 return date(LocalDate.now(clock)); 453 } 454 455 //----------------------------------------------------------------------- 456 /** 457 * Checks if the year is a leap year, according to the ISO proleptic 458 * calendar system rules. 459 * <p> 460 * This method applies the current rules for leap years across the whole time-line. 461 * In general, a year is a leap year if it is divisible by four without 462 * remainder. However, years divisible by 100, are not leap years, with 463 * the exception of years divisible by 400 which are. 464 * <p> 465 * For example, 1904 is a leap year it is divisible by 4. 466 * 1900 was not a leap year as it is divisible by 100, however 2000 was a 467 * leap year as it is divisible by 400. 468 * <p> 469 * The calculation is proleptic - applying the same rules into the far future and far past. 470 * This is historically inaccurate, but is correct for the ISO-8601 standard. 471 * 472 * @param prolepticYear the ISO proleptic year to check 473 * @return true if the year is leap, false otherwise 474 */ 475 @Override isLeapYear(long prolepticYear)476 public boolean isLeapYear(long prolepticYear) { 477 return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0); 478 } 479 480 @Override prolepticYear(Era era, int yearOfEra)481 public int prolepticYear(Era era, int yearOfEra) { 482 if (!(era instanceof IsoEra)) { 483 throw new ClassCastException("Era must be IsoEra"); 484 } 485 return (era == IsoEra.CE ? yearOfEra : 1 - yearOfEra); 486 } 487 488 @Override eraOf(int eraValue)489 public IsoEra eraOf(int eraValue) { 490 return IsoEra.of(eraValue); 491 } 492 493 @Override eras()494 public List<Era> eras() { 495 return List.of(IsoEra.values()); 496 } 497 498 //----------------------------------------------------------------------- 499 /** 500 * Resolves parsed {@code ChronoField} values into a date during parsing. 501 * <p> 502 * Most {@code TemporalField} implementations are resolved using the 503 * resolve method on the field. By contrast, the {@code ChronoField} class 504 * defines fields that only have meaning relative to the chronology. 505 * As such, {@code ChronoField} date fields are resolved here in the 506 * context of a specific chronology. 507 * <p> 508 * {@code ChronoField} instances on the ISO calendar system are resolved 509 * as follows. 510 * <ul> 511 * <li>{@code EPOCH_DAY} - If present, this is converted to a {@code LocalDate} 512 * and all other date fields are then cross-checked against the date. 513 * <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the 514 * {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart 515 * then the field is validated. 516 * <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they 517 * are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA} 518 * range is not validated, in smart and strict mode it is. The {@code ERA} is 519 * validated for range in all three modes. If only the {@code YEAR_OF_ERA} is 520 * present, and the mode is smart or lenient, then the current era (CE/AD) 521 * is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is 522 * left untouched. If only the {@code ERA} is present, then it is left untouched. 523 * <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} - 524 * If all three are present, then they are combined to form a {@code LocalDate}. 525 * In all three modes, the {@code YEAR} is validated. If the mode is smart or strict, 526 * then the month and day are validated, with the day validated from 1 to 31. 527 * If the mode is lenient, then the date is combined in a manner equivalent to 528 * creating a date on the first of January in the requested year, then adding 529 * the difference in months, then the difference in days. 530 * If the mode is smart, and the day-of-month is greater than the maximum for 531 * the year-month, then the day-of-month is adjusted to the last day-of-month. 532 * If the mode is strict, then the three fields must form a valid date. 533 * <li>{@code YEAR} and {@code DAY_OF_YEAR} - 534 * If both are present, then they are combined to form a {@code LocalDate}. 535 * In all three modes, the {@code YEAR} is validated. 536 * If the mode is lenient, then the date is combined in a manner equivalent to 537 * creating a date on the first of January in the requested year, then adding 538 * the difference in days. 539 * If the mode is smart or strict, then the two fields must form a valid date. 540 * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and 541 * {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} - 542 * If all four are present, then they are combined to form a {@code LocalDate}. 543 * In all three modes, the {@code YEAR} is validated. 544 * If the mode is lenient, then the date is combined in a manner equivalent to 545 * creating a date on the first of January in the requested year, then adding 546 * the difference in months, then the difference in weeks, then in days. 547 * If the mode is smart or strict, then the all four fields are validated to 548 * their outer ranges. The date is then combined in a manner equivalent to 549 * creating a date on the first day of the requested year and month, then adding 550 * the amount in weeks and days to reach their values. If the mode is strict, 551 * the date is additionally validated to check that the day and week adjustment 552 * did not change the month. 553 * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and 554 * {@code DAY_OF_WEEK} - If all four are present, then they are combined to 555 * form a {@code LocalDate}. The approach is the same as described above for 556 * years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}. 557 * The day-of-week is adjusted as the next or same matching day-of-week once 558 * the years, months and weeks have been handled. 559 * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} - 560 * If all three are present, then they are combined to form a {@code LocalDate}. 561 * In all three modes, the {@code YEAR} is validated. 562 * If the mode is lenient, then the date is combined in a manner equivalent to 563 * creating a date on the first of January in the requested year, then adding 564 * the difference in weeks, then in days. 565 * If the mode is smart or strict, then the all three fields are validated to 566 * their outer ranges. The date is then combined in a manner equivalent to 567 * creating a date on the first day of the requested year, then adding 568 * the amount in weeks and days to reach their values. If the mode is strict, 569 * the date is additionally validated to check that the day and week adjustment 570 * did not change the year. 571 * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} - 572 * If all three are present, then they are combined to form a {@code LocalDate}. 573 * The approach is the same as described above for years and weeks in 574 * {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the 575 * next or same matching day-of-week once the years and weeks have been handled. 576 * </ul> 577 * 578 * @param fieldValues the map of fields to values, which can be updated, not null 579 * @param resolverStyle the requested type of resolve, not null 580 * @return the resolved date, null if insufficient information to create a date 581 * @throws DateTimeException if the date cannot be resolved, typically 582 * because of a conflict in the input data 583 */ 584 @Override // override for performance resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)585 public LocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { 586 return (LocalDate) super.resolveDate(fieldValues, resolverStyle); 587 } 588 589 @Override // override for better proleptic algorithm resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)590 void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { 591 Long pMonth = fieldValues.remove(PROLEPTIC_MONTH); 592 if (pMonth != null) { 593 if (resolverStyle != ResolverStyle.LENIENT) { 594 PROLEPTIC_MONTH.checkValidValue(pMonth); 595 } 596 addFieldValue(fieldValues, MONTH_OF_YEAR, Math.floorMod(pMonth, 12) + 1); 597 addFieldValue(fieldValues, YEAR, Math.floorDiv(pMonth, 12)); 598 } 599 } 600 601 @Override // override for enhanced behaviour resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)602 LocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { 603 Long yoeLong = fieldValues.remove(YEAR_OF_ERA); 604 if (yoeLong != null) { 605 if (resolverStyle != ResolverStyle.LENIENT) { 606 YEAR_OF_ERA.checkValidValue(yoeLong); 607 } 608 Long era = fieldValues.remove(ERA); 609 if (era == null) { 610 Long year = fieldValues.get(YEAR); 611 if (resolverStyle == ResolverStyle.STRICT) { 612 // do not invent era if strict, but do cross-check with year 613 if (year != null) { 614 addFieldValue(fieldValues, YEAR, (year > 0 ? yoeLong: Math.subtractExact(1, yoeLong))); 615 } else { 616 // reinstate the field removed earlier, no cross-check issues 617 fieldValues.put(YEAR_OF_ERA, yoeLong); 618 } 619 } else { 620 // invent era 621 addFieldValue(fieldValues, YEAR, (year == null || year > 0 ? yoeLong: Math.subtractExact(1, yoeLong))); 622 } 623 } else if (era.longValue() == 1L) { 624 addFieldValue(fieldValues, YEAR, yoeLong); 625 } else if (era.longValue() == 0L) { 626 addFieldValue(fieldValues, YEAR, Math.subtractExact(1, yoeLong)); 627 } else { 628 throw new DateTimeException("Invalid value for era: " + era); 629 } 630 } else if (fieldValues.containsKey(ERA)) { 631 ERA.checkValidValue(fieldValues.get(ERA)); // always validated 632 } 633 return null; 634 } 635 636 @Override // override for performance resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle)637 LocalDate resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { 638 int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); 639 if (resolverStyle == ResolverStyle.LENIENT) { 640 long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); 641 long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1); 642 return LocalDate.of(y, 1, 1).plusMonths(months).plusDays(days); 643 } 644 int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR)); 645 int dom = DAY_OF_MONTH.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH)); 646 if (resolverStyle == ResolverStyle.SMART) { // previous valid 647 if (moy == 4 || moy == 6 || moy == 9 || moy == 11) { 648 dom = Math.min(dom, 30); 649 } else if (moy == 2) { 650 dom = Math.min(dom, Month.FEBRUARY.length(Year.isLeap(y))); 651 652 } 653 } 654 return LocalDate.of(y, moy, dom); 655 } 656 657 //----------------------------------------------------------------------- 658 @Override range(ChronoField field)659 public ValueRange range(ChronoField field) { 660 return field.range(); 661 } 662 663 //----------------------------------------------------------------------- 664 /** 665 * Obtains a period for this chronology based on years, months and days. 666 * <p> 667 * This returns a period tied to the ISO chronology using the specified 668 * years, months and days. See {@link Period} for further details. 669 * 670 * @param years the number of years, may be negative 671 * @param months the number of years, may be negative 672 * @param days the number of years, may be negative 673 * @return the ISO period, not null 674 */ 675 @Override // override with covariant return type period(int years, int months, int days)676 public Period period(int years, int months, int days) { 677 return Period.of(years, months, days); 678 } 679 680 //----------------------------------------------------------------------- 681 /** 682 * Writes the Chronology using a 683 * <a href="{@docRoot}/serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>. 684 * @serialData 685 * <pre> 686 * out.writeByte(1); // identifies a Chronology 687 * out.writeUTF(getId()); 688 * </pre> 689 * 690 * @return the instance of {@code Ser}, not null 691 */ 692 @Override 693 @java.io.Serial writeReplace()694 Object writeReplace() { 695 return super.writeReplace(); 696 } 697 698 /** 699 * Defend against malicious streams. 700 * 701 * @param s the stream to read 702 * @throws InvalidObjectException always 703 */ 704 @java.io.Serial readObject(ObjectInputStream s)705 private void readObject(ObjectInputStream s) throws InvalidObjectException { 706 throw new InvalidObjectException("Deserialization via serialization delegate"); 707 } 708 } 709