1 /*
   2  * Copyright (c) 2012, 2018, 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  * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
  28  *
  29  * All rights reserved.
  30  *
  31  * Redistribution and use in source and binary forms, with or without
  32  * modification, are permitted provided that the following conditions are met:
  33  *
  34  *  * Redistributions of source code must retain the above copyright notice,
  35  *    this list of conditions and the following disclaimer.
  36  *
  37  *  * Redistributions in binary form must reproduce the above copyright notice,
  38  *    this list of conditions and the following disclaimer in the documentation
  39  *    and/or other materials provided with the distribution.
  40  *
  41  *  * Neither the name of JSR-310 nor the names of its contributors
  42  *    may be used to endorse or promote products derived from this software
  43  *    without specific prior written permission.
  44  *
  45  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  46  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  47  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  48  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  49  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  50  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  51  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  52  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  53  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  54  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  55  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  56  */
  57 package java.time.chrono;
  58 
  59 import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
  60 import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
  61 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
  62 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
  63 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
  64 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
  65 import static java.time.temporal.ChronoField.YEAR;
  66 
  67 import java.io.DataInput;
  68 import java.io.DataOutput;
  69 import java.io.IOException;
  70 import java.io.InvalidObjectException;
  71 import java.io.ObjectInputStream;
  72 import java.io.Serializable;
  73 import java.time.Clock;
  74 import java.time.DateTimeException;
  75 import java.time.LocalDate;
  76 import java.time.LocalTime;
  77 import java.time.Period;
  78 import java.time.ZoneId;
  79 import java.time.temporal.ChronoField;
  80 import java.time.temporal.TemporalAccessor;
  81 import java.time.temporal.TemporalAdjuster;
  82 import java.time.temporal.TemporalAmount;
  83 import java.time.temporal.TemporalField;
  84 import java.time.temporal.TemporalQuery;
  85 import java.time.temporal.TemporalUnit;
  86 import java.time.temporal.UnsupportedTemporalTypeException;
  87 import java.time.temporal.ValueRange;
  88 import java.util.Calendar;
  89 import java.util.Objects;
  90 
  91 import sun.util.calendar.CalendarDate;
  92 import sun.util.calendar.LocalGregorianCalendar;
  93 
  94 /**
  95  * A date in the Japanese Imperial calendar system.
  96  * <p>
  97  * This date operates using the {@linkplain JapaneseChronology Japanese Imperial calendar}.
  98  * This calendar system is primarily used in Japan.
  99  * <p>
 100  * The Japanese Imperial calendar system is the same as the ISO calendar system
 101  * apart from the era-based year numbering. The proleptic-year is defined to be
 102  * equal to the ISO proleptic-year.
 103  * <p>
 104  * Japan introduced the Gregorian calendar starting with Meiji 6.
 105  * Only Meiji and later eras are supported;
 106  * dates before Meiji 6, January 1 are not supported.
 107  * <p>
 108  * For example, the Japanese year "Heisei 24" corresponds to ISO year "2012".<br>
 109  * Calling {@code japaneseDate.get(YEAR_OF_ERA)} will return 24.<br>
 110  * Calling {@code japaneseDate.get(YEAR)} will return 2012.<br>
 111  * Calling {@code japaneseDate.get(ERA)} will return 2, corresponding to
 112  * {@code JapaneseChronology.ERA_HEISEI}.<br>
 113  *
 114  * <p>
 115  * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
 116  * class; use of identity-sensitive operations (including reference equality
 117  * ({@code ==}), identity hash code, or synchronization) on instances of
 118  * {@code JapaneseDate} may have unpredictable results and should be avoided.
 119  * The {@code equals} method should be used for comparisons.
 120  *
 121  * @implSpec
 122  * This class is immutable and thread-safe.
 123  *
 124  * @since 1.8
 125  */
 126 public final class JapaneseDate
 127         extends ChronoLocalDateImpl<JapaneseDate>
 128         implements ChronoLocalDate, Serializable {
 129 
 130     /**
 131      * Serialization version.
 132      */
 133     @java.io.Serial
 134     private static final long serialVersionUID = -305327627230580483L;
 135 
 136     /**
 137      * The underlying ISO local date.
 138      */
 139     private final transient LocalDate isoDate;
 140     /**
 141      * The JapaneseEra of this date.
 142      */
 143     private transient JapaneseEra era;
 144     /**
 145      * The Japanese imperial calendar year of this date.
 146      */
 147     private transient int yearOfEra;
 148 
 149     /**
 150      * The first day supported by the JapaneseChronology is Meiji 6, January 1st.
 151      */
 152     static final LocalDate MEIJI_6_ISODATE = LocalDate.of(1873, 1, 1);
 153 
 154     //-----------------------------------------------------------------------
 155     /**
 156      * Obtains the current {@code JapaneseDate} from the system clock in the default time-zone.
 157      * <p>
 158      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
 159      * time-zone to obtain the current date.
 160      * <p>
 161      * Using this method will prevent the ability to use an alternate clock for testing
 162      * because the clock is hard-coded.
 163      *
 164      * @return the current date using the system clock and default time-zone, not null
 165      */
 166     public static JapaneseDate now() {
 167         return now(Clock.systemDefaultZone());
 168     }
 169 
 170     /**
 171      * Obtains the current {@code JapaneseDate} from the system clock in the specified time-zone.
 172      * <p>
 173      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
 174      * Specifying the time-zone avoids dependence on the default time-zone.
 175      * <p>
 176      * Using this method will prevent the ability to use an alternate clock for testing
 177      * because the clock is hard-coded.
 178      *
 179      * @param zone  the zone ID to use, not null
 180      * @return the current date using the system clock, not null
 181      */
 182     public static JapaneseDate now(ZoneId zone) {
 183         return now(Clock.system(zone));
 184     }
 185 
 186     /**
 187      * Obtains the current {@code JapaneseDate} from the specified clock.
 188      * <p>
 189      * This will query the specified clock to obtain the current date - today.
 190      * Using this method allows the use of an alternate clock for testing.
 191      * The alternate clock may be introduced using {@linkplain Clock dependency injection}.
 192      *
 193      * @param clock  the clock to use, not null
 194      * @return the current date, not null
 195      * @throws DateTimeException if the current date cannot be obtained
 196      */
 197     public static JapaneseDate now(Clock clock) {
 198         return new JapaneseDate(LocalDate.now(clock));
 199     }
 200 
 201     /**
 202      * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
 203      * system from the era, year-of-era, month-of-year and day-of-month fields.
 204      * <p>
 205      * This returns a {@code JapaneseDate} with the specified fields.
 206      * The day must be valid for the year and month, otherwise an exception will be thrown.
 207      * <p>
 208      * The Japanese month and day-of-month are the same as those in the
 209      * ISO calendar system. They are not reset when the era changes.
 210      * For example:
 211      * <pre>
 212      *  6th Jan Showa 64 = ISO 1989-01-06
 213      *  7th Jan Showa 64 = ISO 1989-01-07
 214      *  8th Jan Heisei 1 = ISO 1989-01-08
 215      *  9th Jan Heisei 1 = ISO 1989-01-09
 216      * </pre>
 217      *
 218      * @param era  the Japanese era, not null
 219      * @param yearOfEra  the Japanese year-of-era
 220      * @param month  the Japanese month-of-year, from 1 to 12
 221      * @param dayOfMonth  the Japanese day-of-month, from 1 to 31
 222      * @return the date in Japanese calendar system, not null
 223      * @throws DateTimeException if the value of any field is out of range,
 224      *  or if the day-of-month is invalid for the month-year,
 225      *  or if the date is not a Japanese era
 226      */
 227     public static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) {
 228         Objects.requireNonNull(era, "era");
 229         LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
 230         jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth);
 231         if (!JapaneseChronology.JCAL.validate(jdate)) {
 232             throw new DateTimeException("year, month, and day not valid for Era");
 233         }
 234         LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth);
 235         return new JapaneseDate(era, yearOfEra, date);
 236     }
 237 
 238     /**
 239      * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
 240      * system from the proleptic-year, month-of-year and day-of-month fields.
 241      * <p>
 242      * This returns a {@code JapaneseDate} with the specified fields.
 243      * The day must be valid for the year and month, otherwise an exception will be thrown.
 244      * <p>
 245      * The Japanese proleptic year, month and day-of-month are the same as those
 246      * in the ISO calendar system. They are not reset when the era changes.
 247      *
 248      * @param prolepticYear  the Japanese proleptic-year
 249      * @param month  the Japanese month-of-year, from 1 to 12
 250      * @param dayOfMonth  the Japanese day-of-month, from 1 to 31
 251      * @return the date in Japanese calendar system, not null
 252      * @throws DateTimeException if the value of any field is out of range,
 253      *  or if the day-of-month is invalid for the month-year
 254      */
 255     public static JapaneseDate of(int prolepticYear, int month, int dayOfMonth) {
 256         return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
 257     }
 258 
 259     /**
 260      * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
 261      * system from the era, year-of-era and day-of-year fields.
 262      * <p>
 263      * This returns a {@code JapaneseDate} with the specified fields.
 264      * The day must be valid for the year, otherwise an exception will be thrown.
 265      * <p>
 266      * The day-of-year in this factory is expressed relative to the start of the year-of-era.
 267      * This definition changes the normal meaning of day-of-year only in those years
 268      * where the year-of-era is reset to one due to a change in the era.
 269      * For example:
 270      * <pre>
 271      *  6th Jan Showa 64 = day-of-year 6
 272      *  7th Jan Showa 64 = day-of-year 7
 273      *  8th Jan Heisei 1 = day-of-year 1
 274      *  9th Jan Heisei 1 = day-of-year 2
 275      * </pre>
 276      *
 277      * @param era  the Japanese era, not null
 278      * @param yearOfEra  the Japanese year-of-era
 279      * @param dayOfYear  the chronology day-of-year, from 1 to 366
 280      * @return the date in Japanese calendar system, not null
 281      * @throws DateTimeException if the value of any field is out of range,
 282      *  or if the day-of-year is invalid for the year
 283      */
 284     static JapaneseDate ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear) {
 285         Objects.requireNonNull(era, "era");
 286         CalendarDate firstDay = era.getPrivateEra().getSinceDate();
 287         LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
 288         jdate.setEra(era.getPrivateEra());
 289         if (yearOfEra == 1) {
 290             jdate.setDate(yearOfEra, firstDay.getMonth(), firstDay.getDayOfMonth() + dayOfYear - 1);
 291         } else {
 292             jdate.setDate(yearOfEra, 1, dayOfYear);
 293         }
 294         JapaneseChronology.JCAL.normalize(jdate);
 295         if (era.getPrivateEra() != jdate.getEra() || yearOfEra != jdate.getYear()) {
 296             throw new DateTimeException("Invalid parameters");
 297         }
 298         LocalDate localdate = LocalDate.of(jdate.getNormalizedYear(),
 299                                       jdate.getMonth(), jdate.getDayOfMonth());
 300         return new JapaneseDate(era, yearOfEra, localdate);
 301     }
 302 
 303     /**
 304      * Obtains a {@code JapaneseDate} from a temporal object.
 305      * <p>
 306      * This obtains a date in the Japanese calendar system based on the specified temporal.
 307      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
 308      * which this factory converts to an instance of {@code JapaneseDate}.
 309      * <p>
 310      * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
 311      * field, which is standardized across calendar systems.
 312      * <p>
 313      * This method matches the signature of the functional interface {@link TemporalQuery}
 314      * allowing it to be used as a query via method reference, {@code JapaneseDate::from}.
 315      *
 316      * @param temporal  the temporal object to convert, not null
 317      * @return the date in Japanese calendar system, not null
 318      * @throws DateTimeException if unable to convert to a {@code JapaneseDate}
 319      */
 320     public static JapaneseDate from(TemporalAccessor temporal) {
 321         return JapaneseChronology.INSTANCE.date(temporal);
 322     }
 323 
 324     //-----------------------------------------------------------------------
 325     /**
 326      * Creates an instance from an ISO date.
 327      *
 328      * @param isoDate  the standard local date, validated not null
 329      */
 330     JapaneseDate(LocalDate isoDate) {
 331         if (isoDate.isBefore(MEIJI_6_ISODATE)) {
 332             throw new DateTimeException("JapaneseDate before Meiji 6 is not supported");
 333         }
 334         LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate);
 335         this.era = JapaneseEra.toJapaneseEra(jdate.getEra());
 336         this.yearOfEra = jdate.getYear();
 337         this.isoDate = isoDate;
 338     }
 339 
 340     /**
 341      * Constructs a {@code JapaneseDate}. This constructor does NOT validate the given parameters,
 342      * and {@code era} and {@code year} must agree with {@code isoDate}.
 343      *
 344      * @param era  the era, validated not null
 345      * @param year  the year-of-era, validated
 346      * @param isoDate  the standard local date, validated not null
 347      */
 348     JapaneseDate(JapaneseEra era, int year, LocalDate isoDate) {
 349         if (isoDate.isBefore(MEIJI_6_ISODATE)) {
 350             throw new DateTimeException("JapaneseDate before Meiji 6 is not supported");
 351         }
 352         this.era = era;
 353         this.yearOfEra = year;
 354         this.isoDate = isoDate;
 355     }
 356 
 357     //-----------------------------------------------------------------------
 358     /**
 359      * Gets the chronology of this date, which is the Japanese calendar system.
 360      * <p>
 361      * The {@code Chronology} represents the calendar system in use.
 362      * The era and other fields in {@link ChronoField} are defined by the chronology.
 363      *
 364      * @return the Japanese chronology, not null
 365      */
 366     @Override
 367     public JapaneseChronology getChronology() {
 368         return JapaneseChronology.INSTANCE;
 369     }
 370 
 371     /**
 372      * Gets the era applicable at this date.
 373      * <p>
 374      * The Japanese calendar system has multiple eras defined by {@link JapaneseEra}.
 375      *
 376      * @return the era applicable at this date, not null
 377      */
 378     @Override
 379     public JapaneseEra getEra() {
 380         return era;
 381     }
 382 
 383     /**
 384      * Returns the length of the month represented by this date.
 385      * <p>
 386      * This returns the length of the month in days.
 387      * Month lengths match those of the ISO calendar system.
 388      *
 389      * @return the length of the month in days
 390      */
 391     @Override
 392     public int lengthOfMonth() {
 393         return isoDate.lengthOfMonth();
 394     }
 395 
 396     @Override
 397     public int lengthOfYear() {
 398         Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
 399         jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
 400         jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
 401         return  jcal.getActualMaximum(Calendar.DAY_OF_YEAR);
 402     }
 403 
 404     //-----------------------------------------------------------------------
 405     /**
 406      * Checks if the specified field is supported.
 407      * <p>
 408      * This checks if this date can be queried for the specified field.
 409      * If false, then calling the {@link #range(TemporalField) range} and
 410      * {@link #get(TemporalField) get} methods will throw an exception.
 411      * <p>
 412      * If the field is a {@link ChronoField} then the query is implemented here.
 413      * The supported fields are:
 414      * <ul>
 415      * <li>{@code DAY_OF_WEEK}
 416      * <li>{@code DAY_OF_MONTH}
 417      * <li>{@code DAY_OF_YEAR}
 418      * <li>{@code EPOCH_DAY}
 419      * <li>{@code MONTH_OF_YEAR}
 420      * <li>{@code PROLEPTIC_MONTH}
 421      * <li>{@code YEAR_OF_ERA}
 422      * <li>{@code YEAR}
 423      * <li>{@code ERA}
 424      * </ul>
 425      * All other {@code ChronoField} instances will return false.
 426      * <p>
 427      * If the field is not a {@code ChronoField}, then the result of this method
 428      * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
 429      * passing {@code this} as the argument.
 430      * Whether the field is supported is determined by the field.
 431      *
 432      * @param field  the field to check, null returns false
 433      * @return true if the field is supported on this date, false if not
 434      */
 435     @Override
 436     public boolean isSupported(TemporalField field) {
 437         if (field == ALIGNED_DAY_OF_WEEK_IN_MONTH || field == ALIGNED_DAY_OF_WEEK_IN_YEAR ||
 438                 field == ALIGNED_WEEK_OF_MONTH || field == ALIGNED_WEEK_OF_YEAR) {
 439             return false;
 440         }
 441         return super.isSupported(field);
 442     }
 443 
 444     @Override
 445     public ValueRange range(TemporalField field) {
 446         if (field instanceof ChronoField) {
 447             if (isSupported(field)) {
 448                 ChronoField f = (ChronoField) field;
 449                 switch (f) {
 450                     case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
 451                     case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
 452                     case YEAR_OF_ERA: {
 453                         Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
 454                         jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
 455                         jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
 456                         return ValueRange.of(1, jcal.getActualMaximum(Calendar.YEAR));
 457                     }
 458                 }
 459                 return getChronology().range(f);
 460             }
 461             throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
 462         }
 463         return field.rangeRefinedBy(this);
 464     }
 465 
 466     @Override
 467     public long getLong(TemporalField field) {
 468         if (field instanceof ChronoField) {
 469             // same as ISO:
 470             // DAY_OF_WEEK, DAY_OF_MONTH, EPOCH_DAY, MONTH_OF_YEAR, PROLEPTIC_MONTH, YEAR
 471             //
 472             // calendar specific fields
 473             // DAY_OF_YEAR, YEAR_OF_ERA, ERA
 474             switch ((ChronoField) field) {
 475                 case ALIGNED_DAY_OF_WEEK_IN_MONTH:
 476                 case ALIGNED_DAY_OF_WEEK_IN_YEAR:
 477                 case ALIGNED_WEEK_OF_MONTH:
 478                 case ALIGNED_WEEK_OF_YEAR:
 479                     throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
 480                 case YEAR_OF_ERA:
 481                     return yearOfEra;
 482                 case ERA:
 483                     return era.getValue();
 484                 case DAY_OF_YEAR:
 485                     Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
 486                     jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
 487                     jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
 488                     return jcal.get(Calendar.DAY_OF_YEAR);
 489             }
 490             return isoDate.getLong(field);
 491         }
 492         return field.getFrom(this);
 493     }
 494 
 495     /**
 496      * Returns a {@code LocalGregorianCalendar.Date} converted from the given {@code isoDate}.
 497      *
 498      * @param isoDate  the local date, not null
 499      * @return a {@code LocalGregorianCalendar.Date}, not null
 500      */
 501     private static LocalGregorianCalendar.Date toPrivateJapaneseDate(LocalDate isoDate) {
 502         LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
 503         sun.util.calendar.Era sunEra = JapaneseEra.privateEraFrom(isoDate);
 504         int year = isoDate.getYear();
 505         if (sunEra != null) {
 506             year -= sunEra.getSinceDate().getYear() - 1;
 507         }
 508         jdate.setEra(sunEra).setYear(year).setMonth(isoDate.getMonthValue()).setDayOfMonth(isoDate.getDayOfMonth());
 509         JapaneseChronology.JCAL.normalize(jdate);
 510         return jdate;
 511     }
 512 
 513     //-----------------------------------------------------------------------
 514     @Override
 515     public JapaneseDate with(TemporalField field, long newValue) {
 516         if (field instanceof ChronoField) {
 517             ChronoField f = (ChronoField) field;
 518             if (getLong(f) == newValue) {  // getLong() validates for supported fields
 519                 return this;
 520             }
 521             switch (f) {
 522                 case YEAR_OF_ERA:
 523                 case YEAR:
 524                 case ERA: {
 525                     int nvalue = getChronology().range(f).checkValidIntValue(newValue, f);
 526                     switch (f) {
 527                         case YEAR_OF_ERA:
 528                             return this.withYear(nvalue);
 529                         case YEAR:
 530                             return with(isoDate.withYear(nvalue));
 531                         case ERA: {
 532                             return this.withYear(JapaneseEra.of(nvalue), yearOfEra);
 533                         }
 534                     }
 535                 }
 536             }
 537             // YEAR, PROLEPTIC_MONTH and others are same as ISO
 538             return with(isoDate.with(field, newValue));
 539         }
 540         return super.with(field, newValue);
 541     }
 542 
 543     /**
 544      * {@inheritDoc}
 545      * @throws DateTimeException {@inheritDoc}
 546      * @throws ArithmeticException {@inheritDoc}
 547      */
 548     @Override
 549     public  JapaneseDate with(TemporalAdjuster adjuster) {
 550         return super.with(adjuster);
 551     }
 552 
 553     /**
 554      * {@inheritDoc}
 555      * @throws DateTimeException {@inheritDoc}
 556      * @throws ArithmeticException {@inheritDoc}
 557      */
 558     @Override
 559     public JapaneseDate plus(TemporalAmount amount) {
 560         return super.plus(amount);
 561     }
 562 
 563     /**
 564      * {@inheritDoc}
 565      * @throws DateTimeException {@inheritDoc}
 566      * @throws ArithmeticException {@inheritDoc}
 567      */
 568     @Override
 569     public JapaneseDate minus(TemporalAmount amount) {
 570         return super.minus(amount);
 571     }
 572     //-----------------------------------------------------------------------
 573     /**
 574      * Returns a copy of this date with the year altered.
 575      * <p>
 576      * This method changes the year of the date.
 577      * If the month-day is invalid for the year, then the previous valid day
 578      * will be selected instead.
 579      * <p>
 580      * This instance is immutable and unaffected by this method call.
 581      *
 582      * @param era  the era to set in the result, not null
 583      * @param yearOfEra  the year-of-era to set in the returned date
 584      * @return a {@code JapaneseDate} based on this date with the requested year, never null
 585      * @throws DateTimeException if {@code year} is invalid
 586      */
 587     private JapaneseDate withYear(JapaneseEra era, int yearOfEra) {
 588         int year = JapaneseChronology.INSTANCE.prolepticYear(era, yearOfEra);
 589         return with(isoDate.withYear(year));
 590     }
 591 
 592     /**
 593      * Returns a copy of this date with the year-of-era altered.
 594      * <p>
 595      * This method changes the year-of-era of the date.
 596      * If the month-day is invalid for the year, then the previous valid day
 597      * will be selected instead.
 598      * <p>
 599      * This instance is immutable and unaffected by this method call.
 600      *
 601      * @param year  the year to set in the returned date
 602      * @return a {@code JapaneseDate} based on this date with the requested year-of-era, never null
 603      * @throws DateTimeException if {@code year} is invalid
 604      */
 605     private JapaneseDate withYear(int year) {
 606         return withYear(getEra(), year);
 607     }
 608 
 609     //-----------------------------------------------------------------------
 610     @Override
 611     JapaneseDate plusYears(long years) {
 612         return with(isoDate.plusYears(years));
 613     }
 614 
 615     @Override
 616     JapaneseDate plusMonths(long months) {
 617         return with(isoDate.plusMonths(months));
 618     }
 619 
 620     @Override
 621     JapaneseDate plusWeeks(long weeksToAdd) {
 622         return with(isoDate.plusWeeks(weeksToAdd));
 623     }
 624 
 625     @Override
 626     JapaneseDate plusDays(long days) {
 627         return with(isoDate.plusDays(days));
 628     }
 629 
 630     @Override
 631     public JapaneseDate plus(long amountToAdd, TemporalUnit unit) {
 632         return super.plus(amountToAdd, unit);
 633     }
 634 
 635     @Override
 636     public JapaneseDate minus(long amountToAdd, TemporalUnit unit) {
 637         return super.minus(amountToAdd, unit);
 638     }
 639 
 640     @Override
 641     JapaneseDate minusYears(long yearsToSubtract) {
 642         return super.minusYears(yearsToSubtract);
 643     }
 644 
 645     @Override
 646     JapaneseDate minusMonths(long monthsToSubtract) {
 647         return super.minusMonths(monthsToSubtract);
 648     }
 649 
 650     @Override
 651     JapaneseDate minusWeeks(long weeksToSubtract) {
 652         return super.minusWeeks(weeksToSubtract);
 653     }
 654 
 655     @Override
 656     JapaneseDate minusDays(long daysToSubtract) {
 657         return super.minusDays(daysToSubtract);
 658     }
 659 
 660     private JapaneseDate with(LocalDate newDate) {
 661         return (newDate.equals(isoDate) ? this : new JapaneseDate(newDate));
 662     }
 663 
 664     @Override        // for javadoc and covariant return type
 665     @SuppressWarnings("unchecked")
 666     public final ChronoLocalDateTime<JapaneseDate> atTime(LocalTime localTime) {
 667         return (ChronoLocalDateTime<JapaneseDate>)super.atTime(localTime);
 668     }
 669 
 670     @Override
 671     public ChronoPeriod until(ChronoLocalDate endDate) {
 672         Period period = isoDate.until(endDate);
 673         return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
 674     }
 675 
 676     @Override  // override for performance
 677     public long toEpochDay() {
 678         return isoDate.toEpochDay();
 679     }
 680 
 681     //-------------------------------------------------------------------------
 682     /**
 683      * Compares this date to another date, including the chronology.
 684      * <p>
 685      * Compares this {@code JapaneseDate} with another ensuring that the date is the same.
 686      * <p>
 687      * Only objects of type {@code JapaneseDate} are compared, other types return false.
 688      * To compare the dates of two {@code TemporalAccessor} instances, including dates
 689      * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
 690      *
 691      * @param obj  the object to check, null returns false
 692      * @return true if this is equal to the other date
 693      */
 694     @Override  // override for performance
 695     public boolean equals(Object obj) {
 696         if (this == obj) {
 697             return true;
 698         }
 699         if (obj instanceof JapaneseDate) {
 700             JapaneseDate otherDate = (JapaneseDate) obj;
 701             return this.isoDate.equals(otherDate.isoDate);
 702         }
 703         return false;
 704     }
 705 
 706     /**
 707      * A hash code for this date.
 708      *
 709      * @return a suitable hash code based only on the Chronology and the date
 710      */
 711     @Override  // override for performance
 712     public int hashCode() {
 713         return getChronology().getId().hashCode() ^ isoDate.hashCode();
 714     }
 715 
 716     //-----------------------------------------------------------------------
 717     /**
 718      * Defend against malicious streams.
 719      *
 720      * @param s the stream to read
 721      * @throws InvalidObjectException always
 722      */
 723     @java.io.Serial
 724     private void readObject(ObjectInputStream s) throws InvalidObjectException {
 725         throw new InvalidObjectException("Deserialization via serialization delegate");
 726     }
 727 
 728     /**
 729      * Writes the object using a
 730      * <a href="{@docRoot}/serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
 731      * @serialData
 732      * <pre>
 733      *  out.writeByte(4);                 // identifies a JapaneseDate
 734      *  out.writeInt(get(YEAR));
 735      *  out.writeByte(get(MONTH_OF_YEAR));
 736      *  out.writeByte(get(DAY_OF_MONTH));
 737      * </pre>
 738      *
 739      * @return the instance of {@code Ser}, not null
 740      */
 741     @java.io.Serial
 742     private Object writeReplace() {
 743         return new Ser(Ser.JAPANESE_DATE_TYPE, this);
 744     }
 745 
 746     void writeExternal(DataOutput out) throws IOException {
 747         // JapaneseChronology is implicit in the JAPANESE_DATE_TYPE
 748         out.writeInt(get(YEAR));
 749         out.writeByte(get(MONTH_OF_YEAR));
 750         out.writeByte(get(DAY_OF_MONTH));
 751     }
 752 
 753     static JapaneseDate readExternal(DataInput in) throws IOException {
 754         int year = in.readInt();
 755         int month = in.readByte();
 756         int dayOfMonth = in.readByte();
 757         return JapaneseChronology.INSTANCE.date(year, month, dayOfMonth);
 758     }
 759 
 760 }