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