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