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  * 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/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     private static final long serialVersionUID = -305327627230580483L;
 134 
 135     /**
 136      * The underlying ISO local date.
 137      */
 138     private final transient LocalDate isoDate;
 139     /**
 140      * The JapaneseEra of this date.
 141      */
 142     private transient JapaneseEra era;
 143     /**
 144      * The Japanese imperial calendar year of this date.
 145      */
 146     private transient int yearOfEra;
 147 
 148     /**
 149      * The first day supported by the JapaneseChronology is Meiji 6, January 1st.
 150      */
 151     static final LocalDate MEIJI_6_ISODATE = LocalDate.of(1873, 1, 1);
 152 
 153     //-----------------------------------------------------------------------
 154     /**
 155      * Obtains the current {@code JapaneseDate} from the system clock in the default time-zone.
 156      * <p>
 157      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
 158      * time-zone to obtain the current date.
 159      * <p>
 160      * Using this method will prevent the ability to use an alternate clock for testing
 161      * because the clock is hard-coded.
 162      *
 163      * @return the current date using the system clock and default time-zone, not null
 164      */
 165     public static JapaneseDate now() {
 166         return now(Clock.systemDefaultZone());
 167     }
 168 
 169     /**
 170      * Obtains the current {@code JapaneseDate} from the system clock in the specified time-zone.
 171      * <p>
 172      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
 173      * Specifying the time-zone avoids dependence on the default time-zone.
 174      * <p>
 175      * Using this method will prevent the ability to use an alternate clock for testing
 176      * because the clock is hard-coded.
 177      *
 178      * @param zone  the zone ID to use, not null
 179      * @return the current date using the system clock, not null
 180      */
 181     public static JapaneseDate now(ZoneId zone) {
 182         return now(Clock.system(zone));
 183     }
 184 
 185     /**
 186      * Obtains the current {@code JapaneseDate} from the specified clock.
 187      * <p>
 188      * This will query the specified clock to obtain the current date - today.
 189      * Using this method allows the use of an alternate clock for testing.
 190      * The alternate clock may be introduced using {@linkplain Clock dependency injection}.
 191      *
 192      * @param clock  the clock to use, not null
 193      * @return the current date, not null
 194      * @throws DateTimeException if the current date cannot be obtained
 195      */
 196     public static JapaneseDate now(Clock clock) {
 197         return new JapaneseDate(LocalDate.now(clock));
 198     }
 199 
 200     /**
 201      * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
 202      * system from the era, year-of-era, month-of-year and day-of-month fields.
 203      * <p>
 204      * This returns a {@code JapaneseDate} with the specified fields.
 205      * The day must be valid for the year and month, otherwise an exception will be thrown.
 206      * <p>
 207      * The Japanese month and day-of-month are the same as those in the
 208      * ISO calendar system. They are not reset when the era changes.
 209      * For example:
 210      * <pre>
 211      *  6th Jan Showa 64 = ISO 1989-01-06
 212      *  7th Jan Showa 64 = ISO 1989-01-07
 213      *  8th Jan Heisei 1 = ISO 1989-01-08
 214      *  9th Jan Heisei 1 = ISO 1989-01-09
 215      * </pre>
 216      *
 217      * @param era  the Japanese era, not null
 218      * @param yearOfEra  the Japanese year-of-era
 219      * @param month  the Japanese month-of-year, from 1 to 12
 220      * @param dayOfMonth  the Japanese day-of-month, from 1 to 31
 221      * @return the date in Japanese calendar system, not null
 222      * @throws DateTimeException if the value of any field is out of range,
 223      *  or if the day-of-month is invalid for the month-year,
 224      *  or if the date is not a Japanese era
 225      */
 226     public static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) {
 227         Objects.requireNonNull(era, "era");
 228         LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
 229         jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth);
 230         if (!JapaneseChronology.JCAL.validate(jdate)) {
 231             throw new DateTimeException("year, month, and day not valid for Era");
 232         }
 233         LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth);
 234         return new JapaneseDate(era, yearOfEra, date);
 235     }
 236 
 237     /**
 238      * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
 239      * system from the proleptic-year, month-of-year and day-of-month fields.
 240      * <p>
 241      * This returns a {@code JapaneseDate} with the specified fields.
 242      * The day must be valid for the year and month, otherwise an exception will be thrown.
 243      * <p>
 244      * The Japanese proleptic year, month and day-of-month are the same as those
 245      * in the ISO calendar system. They are not reset when the era changes.
 246      *
 247      * @param prolepticYear  the Japanese proleptic-year
 248      * @param month  the Japanese month-of-year, from 1 to 12
 249      * @param dayOfMonth  the Japanese day-of-month, from 1 to 31
 250      * @return the date in Japanese calendar system, not null
 251      * @throws DateTimeException if the value of any field is out of range,
 252      *  or if the day-of-month is invalid for the month-year
 253      */
 254     public static JapaneseDate of(int prolepticYear, int month, int dayOfMonth) {
 255         return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
 256     }
 257 
 258     /**
 259      * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
 260      * system from the era, year-of-era and day-of-year fields.
 261      * <p>
 262      * This returns a {@code JapaneseDate} with the specified fields.
 263      * The day must be valid for the year, otherwise an exception will be thrown.
 264      * <p>
 265      * The day-of-year in this factory is expressed relative to the start of the year-of-era.
 266      * This definition changes the normal meaning of day-of-year only in those years
 267      * where the year-of-era is reset to one due to a change in the era.
 268      * For example:
 269      * <pre>
 270      *  6th Jan Showa 64 = day-of-year 6
 271      *  7th Jan Showa 64 = day-of-year 7
 272      *  8th Jan Heisei 1 = day-of-year 1
 273      *  9th Jan Heisei 1 = day-of-year 2
 274      * </pre>
 275      *
 276      * @param era  the Japanese era, not null
 277      * @param yearOfEra  the Japanese year-of-era
 278      * @param dayOfYear  the chronology day-of-year, from 1 to 366
 279      * @return the date in Japanese calendar system, not null
 280      * @throws DateTimeException if the value of any field is out of range,
 281      *  or if the day-of-year is invalid for the year
 282      */
 283     static JapaneseDate ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear) {
 284         Objects.requireNonNull(era, "era");
 285         CalendarDate firstDay = era.getPrivateEra().getSinceDate();
 286         LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
 287         jdate.setEra(era.getPrivateEra());
 288         if (yearOfEra == 1) {
 289             jdate.setDate(yearOfEra, firstDay.getMonth(), firstDay.getDayOfMonth() + dayOfYear - 1);
 290         } else {
 291             jdate.setDate(yearOfEra, 1, dayOfYear);
 292         }
 293         JapaneseChronology.JCAL.normalize(jdate);
 294         if (era.getPrivateEra() != jdate.getEra() || yearOfEra != jdate.getYear()) {
 295             throw new DateTimeException("Invalid parameters");
 296         }
 297         LocalDate localdate = LocalDate.of(jdate.getNormalizedYear(),
 298                                       jdate.getMonth(), jdate.getDayOfMonth());
 299         return new JapaneseDate(era, yearOfEra, localdate);
 300     }
 301 
 302     /**
 303      * Obtains a {@code JapaneseDate} from a temporal object.
 304      * <p>
 305      * This obtains a date in the Japanese calendar system based on the specified temporal.
 306      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
 307      * which this factory converts to an instance of {@code JapaneseDate}.
 308      * <p>
 309      * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
 310      * field, which is standardized across calendar systems.
 311      * <p>
 312      * This method matches the signature of the functional interface {@link TemporalQuery}
 313      * allowing it to be used as a query via method reference, {@code JapaneseDate::from}.
 314      *
 315      * @param temporal  the temporal object to convert, not null
 316      * @return the date in Japanese calendar system, not null
 317      * @throws DateTimeException if unable to convert to a {@code JapaneseDate}
 318      */
 319     public static JapaneseDate from(TemporalAccessor temporal) {
 320         return JapaneseChronology.INSTANCE.date(temporal);
 321     }
 322 
 323     //-----------------------------------------------------------------------
 324     /**
 325      * Creates an instance from an ISO date.
 326      *
 327      * @param isoDate  the standard local date, validated not null
 328      */
 329     JapaneseDate(LocalDate isoDate) {
 330         if (isoDate.isBefore(MEIJI_6_ISODATE)) {
 331             throw new DateTimeException("JapaneseDate before Meiji 6 is not supported");
 332         }
 333         LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate);
 334         this.era = JapaneseEra.toJapaneseEra(jdate.getEra());
 335         this.yearOfEra = jdate.getYear();
 336         this.isoDate = isoDate;
 337     }
 338 
 339     /**
 340      * Constructs a {@code JapaneseDate}. This constructor does NOT validate the given parameters,
 341      * and {@code era} and {@code year} must agree with {@code isoDate}.
 342      *
 343      * @param era  the era, validated not null
 344      * @param year  the year-of-era, validated
 345      * @param isoDate  the standard local date, validated not null
 346      */
 347     JapaneseDate(JapaneseEra era, int year, LocalDate isoDate) {
 348         if (isoDate.isBefore(MEIJI_6_ISODATE)) {
 349             throw new DateTimeException("JapaneseDate before Meiji 6 is not supported");
 350         }
 351         this.era = era;
 352         this.yearOfEra = year;
 353         this.isoDate = isoDate;
 354     }
 355 
 356     //-----------------------------------------------------------------------
 357     /**
 358      * Gets the chronology of this date, which is the Japanese calendar system.
 359      * <p>
 360      * The {@code Chronology} represents the calendar system in use.
 361      * The era and other fields in {@link ChronoField} are defined by the chronology.
 362      *
 363      * @return the Japanese chronology, not null
 364      */
 365     @Override
 366     public JapaneseChronology getChronology() {
 367         return JapaneseChronology.INSTANCE;
 368     }
 369 
 370     /**
 371      * Gets the era applicable at this date.
 372      * <p>
 373      * The Japanese calendar system has multiple eras defined by {@link JapaneseEra}.
 374      *
 375      * @return the era applicable at this date, not null
 376      */
 377     @Override
 378     public JapaneseEra getEra() {
 379         return era;
 380     }
 381 
 382     /**
 383      * Returns the length of the month represented by this date.
 384      * <p>
 385      * This returns the length of the month in days.
 386      * Month lengths match those of the ISO calendar system.
 387      *
 388      * @return the length of the month in days
 389      */
 390     @Override
 391     public int lengthOfMonth() {
 392         return isoDate.lengthOfMonth();
 393     }
 394 
 395     @Override
 396     public int lengthOfYear() {
 397         Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
 398         jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
 399         jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
 400         return  jcal.getActualMaximum(Calendar.DAY_OF_YEAR);
 401     }
 402 
 403     //-----------------------------------------------------------------------
 404     /**
 405      * Checks if the specified field is supported.
 406      * <p>
 407      * This checks if this date can be queried for the specified field.
 408      * If false, then calling the {@link #range(TemporalField) range} and
 409      * {@link #get(TemporalField) get} methods will throw an exception.
 410      * <p>
 411      * If the field is a {@link ChronoField} then the query is implemented here.
 412      * The supported fields are:
 413      * <ul>
 414      * <li>{@code DAY_OF_WEEK}
 415      * <li>{@code DAY_OF_MONTH}
 416      * <li>{@code DAY_OF_YEAR}
 417      * <li>{@code EPOCH_DAY}
 418      * <li>{@code MONTH_OF_YEAR}
 419      * <li>{@code PROLEPTIC_MONTH}
 420      * <li>{@code YEAR_OF_ERA}
 421      * <li>{@code YEAR}
 422      * <li>{@code ERA}
 423      * </ul>
 424      * All other {@code ChronoField} instances will return false.
 425      * <p>
 426      * If the field is not a {@code ChronoField}, then the result of this method
 427      * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
 428      * passing {@code this} as the argument.
 429      * Whether the field is supported is determined by the field.
 430      *
 431      * @param field  the field to check, null returns false
 432      * @return true if the field is supported on this date, false if not
 433      */
 434     @Override
 435     public boolean isSupported(TemporalField field) {
 436         if (field == ALIGNED_DAY_OF_WEEK_IN_MONTH || field == ALIGNED_DAY_OF_WEEK_IN_YEAR ||
 437                 field == ALIGNED_WEEK_OF_MONTH || field == ALIGNED_WEEK_OF_YEAR) {
 438             return false;
 439         }
 440         return super.isSupported(field);
 441     }
 442 
 443     @Override
 444     public ValueRange range(TemporalField field) {
 445         if (field instanceof ChronoField) {
 446             if (isSupported(field)) {
 447                 ChronoField f = (ChronoField) field;
 448                 switch (f) {
 449                     case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
 450                     case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
 451                     case YEAR_OF_ERA: {
 452                         Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
 453                         jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
 454                         jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
 455                         return ValueRange.of(1, jcal.getActualMaximum(Calendar.YEAR));
 456                     }
 457                 }
 458                 return getChronology().range(f);
 459             }
 460             throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
 461         }
 462         return field.rangeRefinedBy(this);
 463     }
 464 
 465     @Override
 466     public long getLong(TemporalField field) {
 467         if (field instanceof ChronoField) {
 468             // same as ISO:
 469             // DAY_OF_WEEK, DAY_OF_MONTH, EPOCH_DAY, MONTH_OF_YEAR, PROLEPTIC_MONTH, YEAR
 470             //
 471             // calendar specific fields
 472             // DAY_OF_YEAR, YEAR_OF_ERA, ERA
 473             switch ((ChronoField) field) {
 474                 case ALIGNED_DAY_OF_WEEK_IN_MONTH:
 475                 case ALIGNED_DAY_OF_WEEK_IN_YEAR:
 476                 case ALIGNED_WEEK_OF_MONTH:
 477                 case ALIGNED_WEEK_OF_YEAR:
 478                     throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
 479                 case YEAR_OF_ERA:
 480                     return yearOfEra;
 481                 case ERA:
 482                     return era.getValue();
 483                 case DAY_OF_YEAR:
 484                     Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
 485                     jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
 486                     jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
 487                     return jcal.get(Calendar.DAY_OF_YEAR);
 488             }
 489             return isoDate.getLong(field);
 490         }
 491         return field.getFrom(this);
 492     }
 493 
 494     /**
 495      * Returns a {@code LocalGregorianCalendar.Date} converted from the given {@code isoDate}.
 496      *
 497      * @param isoDate  the local date, not null
 498      * @return a {@code LocalGregorianCalendar.Date}, not null
 499      */
 500     private static LocalGregorianCalendar.Date toPrivateJapaneseDate(LocalDate isoDate) {
 501         LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
 502         sun.util.calendar.Era sunEra = JapaneseEra.privateEraFrom(isoDate);
 503         int year = isoDate.getYear();
 504         if (sunEra != null) {
 505             year -= sunEra.getSinceDate().getYear() - 1;
 506         }
 507         jdate.setEra(sunEra).setYear(year).setMonth(isoDate.getMonthValue()).setDayOfMonth(isoDate.getDayOfMonth());
 508         JapaneseChronology.JCAL.normalize(jdate);
 509         return jdate;
 510     }
 511 
 512     //-----------------------------------------------------------------------
 513     @Override
 514     public JapaneseDate with(TemporalField field, long newValue) {
 515         if (field instanceof ChronoField) {
 516             ChronoField f = (ChronoField) field;
 517             if (getLong(f) == newValue) {  // getLong() validates for supported fields
 518                 return this;
 519             }
 520             switch (f) {
 521                 case YEAR_OF_ERA:
 522                 case YEAR:
 523                 case ERA: {
 524                     int nvalue = getChronology().range(f).checkValidIntValue(newValue, f);
 525                     switch (f) {
 526                         case YEAR_OF_ERA:
 527                             return this.withYear(nvalue);
 528                         case YEAR:
 529                             return with(isoDate.withYear(nvalue));
 530                         case ERA: {
 531                             return this.withYear(JapaneseEra.of(nvalue), yearOfEra);
 532                         }
 533                     }
 534                 }
 535             }
 536             // YEAR, PROLEPTIC_MONTH and others are same as ISO
 537             return with(isoDate.with(field, newValue));
 538         }
 539         return super.with(field, newValue);
 540     }
 541 
 542     /**
 543      * {@inheritDoc}
 544      * @throws DateTimeException {@inheritDoc}
 545      * @throws ArithmeticException {@inheritDoc}
 546      */
 547     @Override
 548     public  JapaneseDate with(TemporalAdjuster adjuster) {
 549         return super.with(adjuster);
 550     }
 551 
 552     /**
 553      * {@inheritDoc}
 554      * @throws DateTimeException {@inheritDoc}
 555      * @throws ArithmeticException {@inheritDoc}
 556      */
 557     @Override
 558     public JapaneseDate plus(TemporalAmount amount) {
 559         return super.plus(amount);
 560     }
 561 
 562     /**
 563      * {@inheritDoc}
 564      * @throws DateTimeException {@inheritDoc}
 565      * @throws ArithmeticException {@inheritDoc}
 566      */
 567     @Override
 568     public JapaneseDate minus(TemporalAmount amount) {
 569         return super.minus(amount);
 570     }
 571     //-----------------------------------------------------------------------
 572     /**
 573      * Returns a copy of this date with the year altered.
 574      * <p>
 575      * This method changes the year of the date.
 576      * If the month-day is invalid for the year, then the previous valid day
 577      * will be selected instead.
 578      * <p>
 579      * This instance is immutable and unaffected by this method call.
 580      *
 581      * @param era  the era to set in the result, not null
 582      * @param yearOfEra  the year-of-era to set in the returned date
 583      * @return a {@code JapaneseDate} based on this date with the requested year, never null
 584      * @throws DateTimeException if {@code year} is invalid
 585      */
 586     private JapaneseDate withYear(JapaneseEra era, int yearOfEra) {
 587         int year = JapaneseChronology.INSTANCE.prolepticYear(era, yearOfEra);
 588         return with(isoDate.withYear(year));
 589     }
 590 
 591     /**
 592      * Returns a copy of this date with the year-of-era altered.
 593      * <p>
 594      * This method changes the year-of-era of the date.
 595      * If the month-day is invalid for the year, then the previous valid day
 596      * will be selected instead.
 597      * <p>
 598      * This instance is immutable and unaffected by this method call.
 599      *
 600      * @param year  the year to set in the returned date
 601      * @return a {@code JapaneseDate} based on this date with the requested year-of-era, never null
 602      * @throws DateTimeException if {@code year} is invalid
 603      */
 604     private JapaneseDate withYear(int year) {
 605         return withYear(getEra(), year);
 606     }
 607 
 608     //-----------------------------------------------------------------------
 609     @Override
 610     JapaneseDate plusYears(long years) {
 611         return with(isoDate.plusYears(years));
 612     }
 613 
 614     @Override
 615     JapaneseDate plusMonths(long months) {
 616         return with(isoDate.plusMonths(months));
 617     }
 618 
 619     @Override
 620     JapaneseDate plusWeeks(long weeksToAdd) {
 621         return with(isoDate.plusWeeks(weeksToAdd));
 622     }
 623 
 624     @Override
 625     JapaneseDate plusDays(long days) {
 626         return with(isoDate.plusDays(days));
 627     }
 628 
 629     @Override
 630     public JapaneseDate plus(long amountToAdd, TemporalUnit unit) {
 631         return super.plus(amountToAdd, unit);
 632     }
 633 
 634     @Override
 635     public JapaneseDate minus(long amountToAdd, TemporalUnit unit) {
 636         return super.minus(amountToAdd, unit);
 637     }
 638 
 639     @Override
 640     JapaneseDate minusYears(long yearsToSubtract) {
 641         return super.minusYears(yearsToSubtract);
 642     }
 643 
 644     @Override
 645     JapaneseDate minusMonths(long monthsToSubtract) {
 646         return super.minusMonths(monthsToSubtract);
 647     }
 648 
 649     @Override
 650     JapaneseDate minusWeeks(long weeksToSubtract) {
 651         return super.minusWeeks(weeksToSubtract);
 652     }
 653 
 654     @Override
 655     JapaneseDate minusDays(long daysToSubtract) {
 656         return super.minusDays(daysToSubtract);
 657     }
 658 
 659     private JapaneseDate with(LocalDate newDate) {
 660         return (newDate.equals(isoDate) ? this : new JapaneseDate(newDate));
 661     }
 662 
 663     @Override        // for javadoc and covariant return type
 664     @SuppressWarnings("unchecked")
 665     public final ChronoLocalDateTime<JapaneseDate> atTime(LocalTime localTime) {
 666         return (ChronoLocalDateTime<JapaneseDate>)super.atTime(localTime);
 667     }
 668 
 669     @Override
 670     public ChronoPeriod until(ChronoLocalDate endDate) {
 671         Period period = isoDate.until(endDate);
 672         return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
 673     }
 674 
 675     @Override  // override for performance
 676     public long toEpochDay() {
 677         return isoDate.toEpochDay();
 678     }
 679 
 680     //-------------------------------------------------------------------------
 681     /**
 682      * Compares this date to another date, including the chronology.
 683      * <p>
 684      * Compares this {@code JapaneseDate} with another ensuring that the date is the same.
 685      * <p>
 686      * Only objects of type {@code JapaneseDate} are compared, other types return false.
 687      * To compare the dates of two {@code TemporalAccessor} instances, including dates
 688      * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
 689      *
 690      * @param obj  the object to check, null returns false
 691      * @return true if this is equal to the other date
 692      */
 693     @Override  // override for performance
 694     public boolean equals(Object obj) {
 695         if (this == obj) {
 696             return true;
 697         }
 698         if (obj instanceof JapaneseDate) {
 699             JapaneseDate otherDate = (JapaneseDate) obj;
 700             return this.isoDate.equals(otherDate.isoDate);
 701         }
 702         return false;
 703     }
 704 
 705     /**
 706      * A hash code for this date.
 707      *
 708      * @return a suitable hash code based only on the Chronology and the date
 709      */
 710     @Override  // override for performance
 711     public int hashCode() {
 712         return getChronology().getId().hashCode() ^ isoDate.hashCode();
 713     }
 714 
 715     //-----------------------------------------------------------------------
 716     /**
 717      * Defend against malicious streams.
 718      *
 719      * @param s the stream to read
 720      * @throws InvalidObjectException always
 721      */
 722     private void readObject(ObjectInputStream s) throws InvalidObjectException {
 723         throw new InvalidObjectException("Deserialization via serialization delegate");
 724     }
 725 
 726     /**
 727      * Writes the object using a
 728      * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
 729      * @serialData
 730      * <pre>
 731      *  out.writeByte(4);                 // identifies a JapaneseDate
 732      *  out.writeInt(get(YEAR));
 733      *  out.writeByte(get(MONTH_OF_YEAR));
 734      *  out.writeByte(get(DAY_OF_MONTH));
 735      * </pre>
 736      *
 737      * @return the instance of {@code Ser}, not null
 738      */
 739     private Object writeReplace() {
 740         return new Ser(Ser.JAPANESE_DATE_TYPE, this);
 741     }
 742 
 743     void writeExternal(DataOutput out) throws IOException {
 744         // JapaneseChronology is implicit in the JAPANESE_DATE_TYPE
 745         out.writeInt(get(YEAR));
 746         out.writeByte(get(MONTH_OF_YEAR));
 747         out.writeByte(get(DAY_OF_MONTH));
 748     }
 749 
 750     static JapaneseDate readExternal(DataInput in) throws IOException {
 751         int year = in.readInt();
 752         int month = in.readByte();
 753         int dayOfMonth = in.readByte();
 754         return JapaneseChronology.INSTANCE.date(year, month, dayOfMonth);
 755     }
 756 
 757 }