• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *  * Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  *  * Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  *  * Neither the name of JSR-310 nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.threeten.bp.chrono;
33 
34 import static org.threeten.bp.temporal.ChronoField.DAY_OF_MONTH;
35 import static org.threeten.bp.temporal.ChronoField.MONTH_OF_YEAR;
36 import static org.threeten.bp.temporal.ChronoField.YEAR;
37 
38 import java.io.DataInput;
39 import java.io.DataOutput;
40 import java.io.IOException;
41 import java.io.ObjectInputStream;
42 import java.io.Serializable;
43 import java.util.Calendar;
44 
45 import org.threeten.bp.Clock;
46 import org.threeten.bp.DateTimeException;
47 import org.threeten.bp.LocalDate;
48 import org.threeten.bp.LocalTime;
49 import org.threeten.bp.Period;
50 import org.threeten.bp.ZoneId;
51 import org.threeten.bp.jdk8.Jdk8Methods;
52 import org.threeten.bp.temporal.ChronoField;
53 import org.threeten.bp.temporal.TemporalAccessor;
54 import org.threeten.bp.temporal.TemporalAdjuster;
55 import org.threeten.bp.temporal.TemporalAmount;
56 import org.threeten.bp.temporal.TemporalField;
57 import org.threeten.bp.temporal.TemporalQuery;
58 import org.threeten.bp.temporal.TemporalUnit;
59 import org.threeten.bp.temporal.UnsupportedTemporalTypeException;
60 import org.threeten.bp.temporal.ValueRange;
61 
62 /**
63  * A date in the Japanese Imperial calendar system.
64  * <p>
65  * This date operates using the {@linkplain JapaneseChronology Japanese Imperial calendar}.
66  * This calendar system is primarily used in Japan.
67  * <p>
68  * The Japanese Imperial calendar system is the same as the ISO calendar system
69  * apart from the era-based year numbering. The proleptic-year is defined to be
70  * equal to the ISO proleptic-year.
71  * <p>
72  * Japan introduced the Gregorian calendar starting with Meiji 6.
73  * Only Meiji and later eras are supported.
74  * <p>
75  * For example, the Japanese year "Heisei 24" corresponds to ISO year "2012".<br>
76  * Calling {@code japaneseDate.get(YEAR_OF_ERA)} will return 24.<br>
77  * Calling {@code japaneseDate.get(YEAR)} will return 2012.<br>
78  * Calling {@code japaneseDate.get(ERA)} will return 2, corresponding to
79  * {@code JapaneseChEra.HEISEI}.<br>
80  *
81  * <h3>Specification for implementors</h3>
82  * This class is immutable and thread-safe.
83  */
84 public final class JapaneseDate
85         extends ChronoDateImpl<JapaneseDate>
86         implements Serializable {
87 
88     /**
89      * Serialization version.
90      */
91     private static final long serialVersionUID = -305327627230580483L;
92     /**
93      * Minimum date.
94      */
95     static final LocalDate MIN_DATE = LocalDate.of(1873, 1, 1);
96 
97     /**
98      * The underlying ISO local date.
99      * @serial
100      */
101     private final LocalDate isoDate;
102     /**
103      * The JapaneseEra of this date.
104      */
105     private transient JapaneseEra era;
106     /**
107      * The Japanese imperial calendar year of this date.
108      */
109     private transient int yearOfEra;
110 
111     //-----------------------------------------------------------------------
112     /**
113      * Obtains the current {@code JapaneseDate} from the system clock in the default time-zone.
114      * <p>
115      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
116      * time-zone to obtain the current date.
117      * <p>
118      * Using this method will prevent the ability to use an alternate clock for testing
119      * because the clock is hard-coded.
120      *
121      * @return the current date using the system clock and default time-zone, not null
122      */
now()123     public static JapaneseDate now() {
124         return now(Clock.systemDefaultZone());
125     }
126 
127     /**
128      * Obtains the current {@code JapaneseDate} from the system clock in the specified time-zone.
129      * <p>
130      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
131      * Specifying the time-zone avoids dependence on the default time-zone.
132      * <p>
133      * Using this method will prevent the ability to use an alternate clock for testing
134      * because the clock is hard-coded.
135      *
136      * @param zone  the zone ID to use, not null
137      * @return the current date using the system clock, not null
138      */
now(ZoneId zone)139     public static JapaneseDate now(ZoneId zone) {
140         return now(Clock.system(zone));
141     }
142 
143     /**
144      * Obtains the current {@code JapaneseDate} from the specified clock.
145      * <p>
146      * This will query the specified clock to obtain the current date - today.
147      * Using this method allows the use of an alternate clock for testing.
148      * The alternate clock may be introduced using {@linkplain Clock dependency injection}.
149      *
150      * @param clock  the clock to use, not null
151      * @return the current date, not null
152      * @throws DateTimeException if the current date cannot be obtained
153      */
now(Clock clock)154     public static JapaneseDate now(Clock clock) {
155         return new JapaneseDate(LocalDate.now(clock));
156     }
157 
158     /**
159      * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
160      * system from the era, year-of-era, month-of-year and day-of-month fields.
161      * <p>
162      * This returns a {@code JapaneseDate} with the specified fields.
163      * The day must be valid for the year and month, otherwise an exception will be thrown.
164      * <p>
165      * The Japanese month and day-of-month are the same as those in the
166      * ISO calendar system. They are not reset when the era changes.
167      * For example:
168      * <pre>
169      *  6th Jan Showa 64 = ISO 1989-01-06
170      *  7th Jan Showa 64 = ISO 1989-01-07
171      *  8th Jan Heisei 1 = ISO 1989-01-08
172      *  9th Jan Heisei 1 = ISO 1989-01-09
173      * </pre>
174      *
175      * @param era  the Japanese era, not null
176      * @param yearOfEra  the Japanese year-of-era
177      * @param month  the Japanese month-of-year, from 1 to 12
178      * @param dayOfMonth  the Japanese day-of-month, from 1 to 31
179      * @return the date in Japanese calendar system, not null
180      * @throws DateTimeException if the value of any field is out of range,
181      *  or if the day-of-month is invalid for the month-year
182      */
of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth)183     public static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) {
184         Jdk8Methods.requireNonNull(era, "era");
185         if (yearOfEra < 1) {
186             throw new DateTimeException("Invalid YearOfEra: " + yearOfEra);
187         }
188         LocalDate eraStartDate = era.startDate();
189         LocalDate eraEndDate = era.endDate();
190         int yearOffset = eraStartDate.getYear() - 1;
191         LocalDate date = LocalDate.of(yearOfEra + yearOffset, month, dayOfMonth);
192         if (date.isBefore(eraStartDate) || date.isAfter(eraEndDate)) {
193             throw new DateTimeException("Requested date is outside bounds of era " + era);
194         }
195         return new JapaneseDate(era, yearOfEra, date);
196     }
197 
198     /**
199      * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
200      * system from the era, year-of-era and day-of-year fields.
201      * <p>
202      * This returns a {@code JapaneseDate} with the specified fields.
203      * The day must be valid for the year, otherwise an exception will be thrown.
204      * The Japanese day-of-year is reset when the era changes.
205      *
206      * @param era  the Japanese era, not null
207      * @param yearOfEra  the Japanese year-of-era
208      * @param dayOfYear  the Japanese day-of-year, from 1 to 31
209      * @return the date in Japanese calendar system, not null
210      * @throws DateTimeException if the value of any field is out of range,
211      *  or if the day-of-year is invalid for the year
212      */
ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear)213     static JapaneseDate ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear) {
214         Jdk8Methods.requireNonNull(era, "era");
215         if (yearOfEra < 1) {
216             throw new DateTimeException("Invalid YearOfEra: " + yearOfEra);
217         }
218         LocalDate eraStartDate = era.startDate();
219         LocalDate eraEndDate = era.endDate();
220         if (yearOfEra == 1) {
221             dayOfYear += eraStartDate.getDayOfYear() - 1;
222             if (dayOfYear > eraStartDate.lengthOfYear()) {
223                 throw new DateTimeException("DayOfYear exceeds maximum allowed in the first year of era " + era);
224             }
225         }
226         int yearOffset = eraStartDate.getYear() - 1;
227         LocalDate isoDate = LocalDate.ofYearDay(yearOfEra + yearOffset, dayOfYear);
228         if (isoDate.isBefore(eraStartDate) || isoDate.isAfter(eraEndDate)) {
229             throw new DateTimeException("Requested date is outside bounds of era " + era);
230         }
231         return new JapaneseDate(era, yearOfEra, isoDate);
232     }
233 
234     /**
235      * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
236      * system from the proleptic-year, month-of-year and day-of-month fields.
237      * <p>
238      * This returns a {@code JapaneseDate} with the specified fields.
239      * The day must be valid for the year and month, otherwise an exception will be thrown.
240      * <p>
241      * The Japanese proleptic year, month and day-of-month are the same as those
242      * in the ISO calendar system. They are not reset when the era changes.
243      *
244      * @param prolepticYear  the Japanese proleptic-year
245      * @param month  the Japanese month-of-year, from 1 to 12
246      * @param dayOfMonth  the Japanese day-of-month, from 1 to 31
247      * @return the date in Japanese calendar system, not null
248      * @throws DateTimeException if the value of any field is out of range,
249      *  or if the day-of-month is invalid for the month-year
250      */
of(int prolepticYear, int month, int dayOfMonth)251     public static JapaneseDate of(int prolepticYear, int month, int dayOfMonth) {
252         return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
253     }
254 
255     /**
256      * Obtains a {@code JapaneseDate} from a temporal object.
257      * <p>
258      * This obtains a date in the Japanese calendar system based on the specified temporal.
259      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
260      * which this factory converts to an instance of {@code JapaneseDate}.
261      * <p>
262      * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
263      * field, which is standardized across calendar systems.
264      * <p>
265      * This method matches the signature of the functional interface {@link TemporalQuery}
266      * allowing it to be used as a query via method reference, {@code JapaneseDate::from}.
267      *
268      * @param temporal  the temporal object to convert, not null
269      * @return the date in Japanese calendar system, not null
270      * @throws DateTimeException if unable to convert to a {@code JapaneseDate}
271      */
from(TemporalAccessor temporal)272     public static JapaneseDate from(TemporalAccessor temporal) {
273         return JapaneseChronology.INSTANCE.date(temporal);
274     }
275 
276     //-----------------------------------------------------------------------
277     /**
278      * Creates an instance from an ISO date.
279      *
280      * @param isoDate  the standard local date, validated not null
281      */
JapaneseDate(LocalDate isoDate)282     JapaneseDate(LocalDate isoDate) {
283         if (isoDate.isBefore(MIN_DATE)) {
284             throw new DateTimeException("Minimum supported date is January 1st Meiji 6");
285         }
286         this.era = JapaneseEra.from(isoDate);
287         int yearOffset = this.era.startDate().getYear() - 1;
288         this.yearOfEra = isoDate.getYear() - yearOffset;
289         this.isoDate = isoDate;
290     }
291 
292     /**
293      * Constructs a {@code JapaneseDate}. This constructor does NOT validate the given parameters,
294      * and {@code era} and {@code year} must agree with {@code isoDate}.
295      *
296      * @param era  the era, validated not null
297      * @param year  the year-of-era, validated
298      * @param isoDate  the standard local date, validated not null
299      */
JapaneseDate(JapaneseEra era, int year, LocalDate isoDate)300     JapaneseDate(JapaneseEra era, int year, LocalDate isoDate) {
301         if (isoDate.isBefore(MIN_DATE)) {
302             throw new DateTimeException("Minimum supported date is January 1st Meiji 6");
303         }
304         this.era = era;
305         this.yearOfEra = year;
306         this.isoDate = isoDate;
307     }
308 
309     /**
310      * Reconstitutes this object from a stream.
311      *
312      * @param stream object input stream
313      */
readObject(ObjectInputStream stream)314     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
315         stream.defaultReadObject();
316         this.era = JapaneseEra.from(isoDate);
317         int yearOffset = this.era.startDate().getYear() - 1;
318         this.yearOfEra = isoDate.getYear() - yearOffset;
319     }
320 
321     //-----------------------------------------------------------------------
322     @Override
getChronology()323     public JapaneseChronology getChronology() {
324         return JapaneseChronology.INSTANCE;
325     }
326 
327     @Override
getEra()328     public JapaneseEra getEra() {
329         return era;
330     }
331 
332     @Override
lengthOfMonth()333     public int lengthOfMonth() {
334         return isoDate.lengthOfMonth();
335     }
336 
337     @Override
lengthOfYear()338     public int lengthOfYear() {
339         Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
340         jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
341         jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
342         return  jcal.getActualMaximum(Calendar.DAY_OF_YEAR);
343     }
344 
345     //-----------------------------------------------------------------------
346     /**
347      * Checks if the specified field is supported.
348      * <p>
349      * This checks if this date can be queried for the specified field.
350      * If false, then calling the {@link #range(TemporalField) range} and
351      * {@link #get(TemporalField) get} methods will throw an exception.
352      * <p>
353      * If the field is a {@link ChronoField} then the query is implemented here.
354      * The supported fields are:
355      * <ul>
356      * <li>{@code DAY_OF_WEEK}
357      * <li>{@code DAY_OF_MONTH}
358      * <li>{@code DAY_OF_YEAR}
359      * <li>{@code EPOCH_DAY}
360      * <li>{@code MONTH_OF_YEAR}
361      * <li>{@code PROLEPTIC_MONTH}
362      * <li>{@code YEAR_OF_ERA}
363      * <li>{@code YEAR}
364      * <li>{@code ERA}
365      * </ul>
366      * All other {@code ChronoField} instances will return false.
367      * <p>
368      * If the field is not a {@code ChronoField}, then the result of this method
369      * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
370      * passing {@code this} as the argument.
371      * Whether the field is supported is determined by the field.
372      *
373      * @param field  the field to check, null returns false
374      * @return true if the field is supported on this date, false if not
375      */
376     @Override
isSupported(TemporalField field)377     public boolean isSupported(TemporalField field) {
378         if (field == ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH ||
379                 field == ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR ||
380                 field == ChronoField.ALIGNED_WEEK_OF_MONTH ||
381                 field == ChronoField.ALIGNED_WEEK_OF_YEAR) {
382             return false;
383         }
384         return super.isSupported(field);
385     }
386 
387     @Override
range(TemporalField field)388     public ValueRange range(TemporalField field) {
389         if (field instanceof ChronoField) {
390             if (isSupported(field)) {
391                 ChronoField f = (ChronoField) field;
392                 switch (f) {
393                     case DAY_OF_YEAR:
394                         return actualRange(Calendar.DAY_OF_YEAR);
395                     case YEAR_OF_ERA:
396                         return actualRange(Calendar.YEAR);
397                 }
398                 return getChronology().range(f);
399             }
400             throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
401         }
402         return field.rangeRefinedBy(this);
403     }
404 
actualRange(int calendarField)405     private ValueRange actualRange(int calendarField) {
406         Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
407         jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
408         jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
409         return ValueRange.of(jcal.getActualMinimum(calendarField),
410                                      jcal.getActualMaximum(calendarField));
411     }
412 
413     @Override
getLong(TemporalField field)414     public long getLong(TemporalField field) {
415         if (field instanceof ChronoField) {
416             switch ((ChronoField) field) {
417                 case ALIGNED_DAY_OF_WEEK_IN_MONTH:
418                 case ALIGNED_DAY_OF_WEEK_IN_YEAR:
419                 case ALIGNED_WEEK_OF_MONTH:
420                 case ALIGNED_WEEK_OF_YEAR:
421                     throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
422                 case YEAR_OF_ERA:
423                     return yearOfEra;
424                 case ERA:
425                     return era.getValue();
426                 case DAY_OF_YEAR:
427                     return getDayOfYear();
428             }
429             return isoDate.getLong(field);
430         }
431         return field.getFrom(this);
432     }
433 
getDayOfYear()434     private long getDayOfYear() {
435         if (yearOfEra == 1) {
436             return isoDate.getDayOfYear() - era.startDate().getDayOfYear() + 1;
437         }
438         return isoDate.getDayOfYear();
439     }
440 
441     //-----------------------------------------------------------------------
442     @Override
with(TemporalAdjuster adjuster)443     public JapaneseDate with(TemporalAdjuster adjuster) {
444         return (JapaneseDate) super.with(adjuster);
445     }
446 
447     @Override
with(TemporalField field, long newValue)448     public JapaneseDate with(TemporalField field, long newValue) {
449         if (field instanceof ChronoField) {
450             ChronoField f = (ChronoField) field;
451             if (getLong(f) == newValue) {  // validates unsupported fields
452                 return this;
453             }
454             switch (f) {
455                 case DAY_OF_YEAR:
456                 case YEAR_OF_ERA:
457                 case ERA: {
458                     int nvalue = getChronology().range(f).checkValidIntValue(newValue, f);
459                     switch (f) {
460                         case DAY_OF_YEAR:
461                             return with(isoDate.plusDays(nvalue - getDayOfYear()));
462                         case YEAR_OF_ERA:
463                             return this.withYear(nvalue);
464                         case ERA: {
465                             return this.withYear(JapaneseEra.of(nvalue), yearOfEra);
466                         }
467                     }
468                 }
469             }
470             return with(isoDate.with(field, newValue));
471         }
472         return field.adjustInto(this, newValue);
473     }
474 
475     @Override
plus(TemporalAmount amount)476     public JapaneseDate plus(TemporalAmount amount) {
477         return (JapaneseDate) super.plus(amount);
478     }
479 
480     @Override
plus(long amountToAdd, TemporalUnit unit)481     public JapaneseDate plus(long amountToAdd, TemporalUnit unit) {
482         return (JapaneseDate) super.plus(amountToAdd, unit);
483     }
484 
485     @Override
minus(TemporalAmount amount)486     public JapaneseDate minus(TemporalAmount amount) {
487         return (JapaneseDate) super.minus(amount);
488     }
489 
490     @Override
minus(long amountToAdd, TemporalUnit unit)491     public JapaneseDate minus(long amountToAdd, TemporalUnit unit) {
492         return (JapaneseDate) super.minus(amountToAdd, unit);
493     }
494 
495     //-----------------------------------------------------------------------
496     /**
497      * Returns a copy of this date with the year altered.
498      * <p>
499      * This method changes the year of the date.
500      * If the month-day is invalid for the year, then the previous valid day
501      * will be selected instead.
502      * <p>
503      * This instance is immutable and unaffected by this method call.
504      *
505      * @param era  the era to set in the result, not null
506      * @param yearOfEra  the year-of-era to set in the returned date
507      * @return a {@code JapaneseDate} based on this date with the requested year, never null
508      * @throws DateTimeException if {@code year} is invalid
509      */
withYear(JapaneseEra era, int yearOfEra)510     private JapaneseDate withYear(JapaneseEra era, int yearOfEra) {
511         int year = JapaneseChronology.INSTANCE.prolepticYear(era, yearOfEra);
512         return with(isoDate.withYear(year));
513     }
514 
515     /**
516      * Returns a copy of this date with the year-of-era altered.
517      * <p>
518      * This method changes the year-of-era of the date.
519      * If the month-day is invalid for the year, then the previous valid day
520      * will be selected instead.
521      * <p>
522      * This instance is immutable and unaffected by this method call.
523      *
524      * @param year  the year to set in the returned date
525      * @return a {@code JapaneseDate} based on this date with the requested year-of-era, never null
526      * @throws DateTimeException if {@code year} is invalid
527      */
withYear(int year)528     private JapaneseDate withYear(int year) {
529         return withYear(getEra(), year);
530     }
531 
532     //-----------------------------------------------------------------------
533     @Override
plusYears(long years)534     JapaneseDate plusYears(long years) {
535         return with(isoDate.plusYears(years));
536     }
537 
538     @Override
plusMonths(long months)539     JapaneseDate plusMonths(long months) {
540         return with(isoDate.plusMonths(months));
541     }
542 
543     @Override
plusDays(long days)544     JapaneseDate plusDays(long days) {
545         return with(isoDate.plusDays(days));
546     }
547 
with(LocalDate newDate)548     private JapaneseDate with(LocalDate newDate) {
549         return (newDate.equals(isoDate) ? this : new JapaneseDate(newDate));
550     }
551 
552     @Override
553     @SuppressWarnings("unchecked")
atTime(LocalTime localTime)554     public final ChronoLocalDateTime<JapaneseDate> atTime(LocalTime localTime) {
555         return (ChronoLocalDateTime<JapaneseDate>)super.atTime(localTime);
556     }
557 
558     @Override
until(ChronoLocalDate endDate)559     public ChronoPeriod until(ChronoLocalDate endDate) {
560         Period period = isoDate.until(endDate);
561         return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
562     }
563 
564     @Override  // override for performance
toEpochDay()565     public long toEpochDay() {
566         return isoDate.toEpochDay();
567     }
568 
569     //-------------------------------------------------------------------------
570     @Override  // override for performance
equals(Object obj)571     public boolean equals(Object obj) {
572         if (this == obj) {
573             return true;
574         }
575         if (obj instanceof JapaneseDate) {
576             JapaneseDate otherDate = (JapaneseDate) obj;
577             return this.isoDate.equals(otherDate.isoDate);
578         }
579         return false;
580     }
581 
582     @Override  // override for performance
hashCode()583     public int hashCode() {
584         return getChronology().getId().hashCode() ^ isoDate.hashCode();
585     }
586 
587     //-----------------------------------------------------------------------
writeReplace()588     private Object writeReplace() {
589         return new Ser(Ser.JAPANESE_DATE_TYPE, this);
590     }
591 
writeExternal(DataOutput out)592     void writeExternal(DataOutput out) throws IOException {
593         // JapaneseChrono is implicit in the JAPANESE_DATE_TYPE
594         out.writeInt(get(YEAR));
595         out.writeByte(get(MONTH_OF_YEAR));
596         out.writeByte(get(DAY_OF_MONTH));
597     }
598 
readExternal(DataInput in)599     static ChronoLocalDate readExternal(DataInput in) throws IOException {
600         int year = in.readInt();
601         int month = in.readByte();
602         int dayOfMonth = in.readByte();
603         return JapaneseChronology.INSTANCE.date(year, month, dayOfMonth);
604     }
605 
606 
607 }
608