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