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