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 */ 57 package java.time.chrono; 58 59 import static java.time.temporal.ChronoField.DAY_OF_MONTH; 60 import static java.time.temporal.ChronoField.DAY_OF_YEAR; 61 import static java.time.temporal.ChronoField.ERA; 62 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 63 import static java.time.temporal.ChronoField.YEAR; 64 import static java.time.temporal.ChronoField.YEAR_OF_ERA; 65 import static java.time.temporal.ChronoUnit.DAYS; 66 import static java.time.temporal.ChronoUnit.MONTHS; 67 68 import java.io.InvalidObjectException; 69 import java.io.ObjectInputStream; 70 import java.io.Serializable; 71 import java.time.Clock; 72 import java.time.DateTimeException; 73 import java.time.Instant; 74 import java.time.LocalDate; 75 import java.time.Year; 76 import java.time.ZoneId; 77 import java.time.format.ResolverStyle; 78 import java.time.temporal.ChronoField; 79 import java.time.temporal.TemporalAccessor; 80 import java.time.temporal.TemporalAdjusters; 81 import java.time.temporal.TemporalField; 82 import java.time.temporal.UnsupportedTemporalTypeException; 83 import java.time.temporal.ValueRange; 84 import java.util.Calendar; 85 import java.util.List; 86 import java.util.Locale; 87 import java.util.Map; 88 import java.util.TimeZone; 89 90 import sun.util.calendar.CalendarSystem; 91 import sun.util.calendar.LocalGregorianCalendar; 92 93 /** 94 * The Japanese Imperial calendar system. 95 * <p> 96 * This chronology defines the rules of the Japanese Imperial calendar system. 97 * This calendar system is primarily used in Japan. 98 * The Japanese Imperial calendar system is the same as the ISO calendar system 99 * apart from the era-based year numbering. 100 * <p> 101 * Japan introduced the Gregorian calendar starting with Meiji 6. 102 * Only Meiji and later eras are supported; 103 * dates before Meiji 6, January 1 are not supported. 104 * <p> 105 * The supported {@code ChronoField} instances are: 106 * <ul> 107 * <li>{@code DAY_OF_WEEK} 108 * <li>{@code DAY_OF_MONTH} 109 * <li>{@code DAY_OF_YEAR} 110 * <li>{@code EPOCH_DAY} 111 * <li>{@code MONTH_OF_YEAR} 112 * <li>{@code PROLEPTIC_MONTH} 113 * <li>{@code YEAR_OF_ERA} 114 * <li>{@code YEAR} 115 * <li>{@code ERA} 116 * </ul> 117 * 118 * @implSpec 119 * This class is immutable and thread-safe. 120 * 121 * @since 1.8 122 */ 123 public final class JapaneseChronology extends AbstractChronology implements Serializable { 124 125 static final LocalGregorianCalendar JCAL = 126 (LocalGregorianCalendar) CalendarSystem.forName("japanese"); 127 128 // Android-changed: don't use locale to create japanese imperial calendar, as it's not generally 129 // supported on Android. Use Calendar.getJapaneseImperialInstance() instead. See .createCalendar 130 // Locale for creating a JapaneseImpericalCalendar. 131 private static final Locale LOCALE = Locale.forLanguageTag("ja-JP-u-ca-japanese"); 132 createCalendar()133 static Calendar createCalendar() { 134 return Calendar.getJapaneseImperialInstance(TimeZone.getDefault(), LOCALE); 135 } 136 137 /** 138 * Singleton instance for Japanese chronology. 139 */ 140 public static final JapaneseChronology INSTANCE = new JapaneseChronology(); 141 142 /** 143 * Serialization version. 144 */ 145 private static final long serialVersionUID = 459996390165777884L; 146 147 //----------------------------------------------------------------------- 148 /** 149 * Restricted constructor. 150 */ JapaneseChronology()151 private JapaneseChronology() { 152 } 153 154 //----------------------------------------------------------------------- 155 /** 156 * Gets the ID of the chronology - 'Japanese'. 157 * <p> 158 * The ID uniquely identifies the {@code Chronology}. 159 * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. 160 * 161 * @return the chronology ID - 'Japanese' 162 * @see #getCalendarType() 163 */ 164 @Override getId()165 public String getId() { 166 return "Japanese"; 167 } 168 169 /** 170 * Gets the calendar type of the underlying calendar system - 'japanese'. 171 * <p> 172 * The calendar type is an identifier defined by the 173 * <em>Unicode Locale Data Markup Language (LDML)</em> specification. 174 * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}. 175 * It can also be used as part of a locale, accessible via 176 * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. 177 * 178 * @return the calendar system type - 'japanese' 179 * @see #getId() 180 */ 181 @Override getCalendarType()182 public String getCalendarType() { 183 return "japanese"; 184 } 185 186 //----------------------------------------------------------------------- 187 /** 188 * Obtains a local date in Japanese calendar system from the 189 * era, year-of-era, month-of-year and day-of-month fields. 190 * <p> 191 * The Japanese month and day-of-month are the same as those in the 192 * ISO calendar system. They are not reset when the era changes. 193 * For example: 194 * <pre> 195 * 6th Jan Showa 64 = ISO 1989-01-06 196 * 7th Jan Showa 64 = ISO 1989-01-07 197 * 8th Jan Heisei 1 = ISO 1989-01-08 198 * 9th Jan Heisei 1 = ISO 1989-01-09 199 * </pre> 200 * 201 * @param era the Japanese era, not null 202 * @param yearOfEra the year-of-era 203 * @param month the month-of-year 204 * @param dayOfMonth the day-of-month 205 * @return the Japanese local date, not null 206 * @throws DateTimeException if unable to create the date 207 * @throws ClassCastException if the {@code era} is not a {@code JapaneseEra} 208 */ 209 @Override date(Era era, int yearOfEra, int month, int dayOfMonth)210 public JapaneseDate date(Era era, int yearOfEra, int month, int dayOfMonth) { 211 if (era instanceof JapaneseEra == false) { 212 throw new ClassCastException("Era must be JapaneseEra"); 213 } 214 return JapaneseDate.of((JapaneseEra) era, yearOfEra, month, dayOfMonth); 215 } 216 217 /** 218 * Obtains a local date in Japanese calendar system from the 219 * proleptic-year, month-of-year and day-of-month fields. 220 * <p> 221 * The Japanese proleptic year, month and day-of-month are the same as those 222 * in the ISO calendar system. They are not reset when the era changes. 223 * 224 * @param prolepticYear the proleptic-year 225 * @param month the month-of-year 226 * @param dayOfMonth the day-of-month 227 * @return the Japanese local date, not null 228 * @throws DateTimeException if unable to create the date 229 */ 230 @Override date(int prolepticYear, int month, int dayOfMonth)231 public JapaneseDate date(int prolepticYear, int month, int dayOfMonth) { 232 return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth)); 233 } 234 235 /** 236 * Obtains a local date in Japanese calendar system from the 237 * era, year-of-era and day-of-year fields. 238 * <p> 239 * The day-of-year in this factory is expressed relative to the start of the year-of-era. 240 * This definition changes the normal meaning of day-of-year only in those years 241 * where the year-of-era is reset to one due to a change in the era. 242 * For example: 243 * <pre> 244 * 6th Jan Showa 64 = day-of-year 6 245 * 7th Jan Showa 64 = day-of-year 7 246 * 8th Jan Heisei 1 = day-of-year 1 247 * 9th Jan Heisei 1 = day-of-year 2 248 * </pre> 249 * 250 * @param era the Japanese era, not null 251 * @param yearOfEra the year-of-era 252 * @param dayOfYear the day-of-year 253 * @return the Japanese local date, not null 254 * @throws DateTimeException if unable to create the date 255 * @throws ClassCastException if the {@code era} is not a {@code JapaneseEra} 256 */ 257 @Override dateYearDay(Era era, int yearOfEra, int dayOfYear)258 public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { 259 return JapaneseDate.ofYearDay((JapaneseEra) era, yearOfEra, dayOfYear); 260 } 261 262 /** 263 * Obtains a local date in Japanese calendar system from the 264 * proleptic-year and day-of-year fields. 265 * <p> 266 * The day-of-year in this factory is expressed relative to the start of the proleptic year. 267 * The Japanese proleptic year and day-of-year are the same as those in the ISO calendar system. 268 * They are not reset when the era changes. 269 * 270 * @param prolepticYear the proleptic-year 271 * @param dayOfYear the day-of-year 272 * @return the Japanese local date, not null 273 * @throws DateTimeException if unable to create the date 274 */ 275 @Override dateYearDay(int prolepticYear, int dayOfYear)276 public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) { 277 return new JapaneseDate(LocalDate.ofYearDay(prolepticYear, dayOfYear)); 278 } 279 280 /** 281 * Obtains a local date in the Japanese calendar system from the epoch-day. 282 * 283 * @param epochDay the epoch day 284 * @return the Japanese local date, not null 285 * @throws DateTimeException if unable to create the date 286 */ 287 @Override // override with covariant return type dateEpochDay(long epochDay)288 public JapaneseDate dateEpochDay(long epochDay) { 289 return new JapaneseDate(LocalDate.ofEpochDay(epochDay)); 290 } 291 292 @Override dateNow()293 public JapaneseDate dateNow() { 294 return dateNow(Clock.systemDefaultZone()); 295 } 296 297 @Override dateNow(ZoneId zone)298 public JapaneseDate dateNow(ZoneId zone) { 299 return dateNow(Clock.system(zone)); 300 } 301 302 @Override dateNow(Clock clock)303 public JapaneseDate dateNow(Clock clock) { 304 return date(LocalDate.now(clock)); 305 } 306 307 @Override date(TemporalAccessor temporal)308 public JapaneseDate date(TemporalAccessor temporal) { 309 if (temporal instanceof JapaneseDate) { 310 return (JapaneseDate) temporal; 311 } 312 return new JapaneseDate(LocalDate.from(temporal)); 313 } 314 315 @Override 316 @SuppressWarnings("unchecked") localDateTime(TemporalAccessor temporal)317 public ChronoLocalDateTime<JapaneseDate> localDateTime(TemporalAccessor temporal) { 318 return (ChronoLocalDateTime<JapaneseDate>)super.localDateTime(temporal); 319 } 320 321 @Override 322 @SuppressWarnings("unchecked") zonedDateTime(TemporalAccessor temporal)323 public ChronoZonedDateTime<JapaneseDate> zonedDateTime(TemporalAccessor temporal) { 324 return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(temporal); 325 } 326 327 @Override 328 @SuppressWarnings("unchecked") zonedDateTime(Instant instant, ZoneId zone)329 public ChronoZonedDateTime<JapaneseDate> zonedDateTime(Instant instant, ZoneId zone) { 330 return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(instant, zone); 331 } 332 333 //----------------------------------------------------------------------- 334 /** 335 * Checks if the specified year is a leap year. 336 * <p> 337 * Japanese calendar leap years occur exactly in line with ISO leap years. 338 * This method does not validate the year passed in, and only has a 339 * well-defined result for years in the supported range. 340 * 341 * @param prolepticYear the proleptic-year to check, not validated for range 342 * @return true if the year is a leap year 343 */ 344 @Override isLeapYear(long prolepticYear)345 public boolean isLeapYear(long prolepticYear) { 346 return IsoChronology.INSTANCE.isLeapYear(prolepticYear); 347 } 348 349 @Override prolepticYear(Era era, int yearOfEra)350 public int prolepticYear(Era era, int yearOfEra) { 351 if (era instanceof JapaneseEra == false) { 352 throw new ClassCastException("Era must be JapaneseEra"); 353 } 354 355 JapaneseEra jera = (JapaneseEra) era; 356 int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1; 357 if (yearOfEra == 1) { 358 return gregorianYear; 359 } 360 if (gregorianYear >= Year.MIN_VALUE && gregorianYear <= Year.MAX_VALUE) { 361 LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null); 362 jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1); 363 if (JapaneseChronology.JCAL.validate(jdate)) { 364 return gregorianYear; 365 } 366 } 367 throw new DateTimeException("Invalid yearOfEra value"); 368 } 369 370 // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa. 371 /** 372 * Returns the calendar system era object from the given numeric value. 373 * 374 * The numeric values supported by this method are the same as the 375 * numeric values supported by {@link JapaneseEra#of(int)}. 376 * 377 * @param eraValue the era value 378 * @return the Japanese {@code Era} for the given numeric era value 379 * @throws DateTimeException if {@code eraValue} is invalid 380 */ 381 @Override eraOf(int eraValue)382 public JapaneseEra eraOf(int eraValue) { 383 return JapaneseEra.of(eraValue); 384 } 385 386 @Override eras()387 public List<Era> eras() { 388 return List.of(JapaneseEra.values()); 389 } 390 getCurrentEra()391 JapaneseEra getCurrentEra() { 392 // Assume that the last JapaneseEra is the current one. 393 JapaneseEra[] eras = JapaneseEra.values(); 394 return eras[eras.length - 1]; 395 } 396 397 //----------------------------------------------------------------------- 398 @Override range(ChronoField field)399 public ValueRange range(ChronoField field) { 400 switch (field) { 401 case ALIGNED_DAY_OF_WEEK_IN_MONTH: 402 case ALIGNED_DAY_OF_WEEK_IN_YEAR: 403 case ALIGNED_WEEK_OF_MONTH: 404 case ALIGNED_WEEK_OF_YEAR: 405 throw new UnsupportedTemporalTypeException("Unsupported field: " + field); 406 case YEAR_OF_ERA: { 407 // Android-changed: use #createCalendar() to create calendar. 408 Calendar jcal = createCalendar(); 409 int startYear = getCurrentEra().getPrivateEra().getSinceDate().getYear(); 410 return ValueRange.of(1, jcal.getGreatestMinimum(Calendar.YEAR), 411 jcal.getLeastMaximum(Calendar.YEAR) + 1, // +1 due to the different definitions 412 Year.MAX_VALUE - startYear); 413 } 414 case DAY_OF_YEAR: { 415 // Android-changed: use #createCalendar() to create calendar. 416 Calendar jcal = createCalendar(); 417 int fieldIndex = Calendar.DAY_OF_YEAR; 418 return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex), 419 jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex)); 420 } 421 case YEAR: 422 return ValueRange.of(JapaneseDate.MEIJI_6_ISODATE.getYear(), Year.MAX_VALUE); 423 case ERA: 424 return ValueRange.of(JapaneseEra.MEIJI.getValue(), getCurrentEra().getValue()); 425 default: 426 return field.range(); 427 } 428 } 429 430 //----------------------------------------------------------------------- 431 @Override // override for return type resolveDate(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle)432 public JapaneseDate resolveDate(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { 433 return (JapaneseDate) super.resolveDate(fieldValues, resolverStyle); 434 } 435 436 @Override // override for special Japanese behavior resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)437 ChronoLocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { 438 // validate era and year-of-era 439 Long eraLong = fieldValues.get(ERA); 440 JapaneseEra era = null; 441 if (eraLong != null) { 442 era = eraOf(range(ERA).checkValidIntValue(eraLong, ERA)); // always validated 443 } 444 Long yoeLong = fieldValues.get(YEAR_OF_ERA); 445 int yoe = 0; 446 if (yoeLong != null) { 447 yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); // always validated 448 } 449 // if only year-of-era and no year then invent era unless strict 450 if (era == null && yoeLong != null && fieldValues.containsKey(YEAR) == false && resolverStyle != ResolverStyle.STRICT) { 451 era = JapaneseEra.values()[JapaneseEra.values().length - 1]; 452 } 453 // if both present, then try to create date 454 if (yoeLong != null && era != null) { 455 if (fieldValues.containsKey(MONTH_OF_YEAR)) { 456 if (fieldValues.containsKey(DAY_OF_MONTH)) { 457 return resolveYMD(era, yoe, fieldValues, resolverStyle); 458 } 459 } 460 if (fieldValues.containsKey(DAY_OF_YEAR)) { 461 return resolveYD(era, yoe, fieldValues, resolverStyle); 462 } 463 } 464 return null; 465 } 466 prolepticYearLenient(JapaneseEra era, int yearOfEra)467 private int prolepticYearLenient(JapaneseEra era, int yearOfEra) { 468 return era.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1; 469 } 470 resolveYMD(JapaneseEra era, int yoe, Map<TemporalField,Long> fieldValues, ResolverStyle resolverStyle)471 private ChronoLocalDate resolveYMD(JapaneseEra era, int yoe, Map<TemporalField,Long> fieldValues, ResolverStyle resolverStyle) { 472 fieldValues.remove(ERA); 473 fieldValues.remove(YEAR_OF_ERA); 474 if (resolverStyle == ResolverStyle.LENIENT) { 475 int y = prolepticYearLenient(era, yoe); 476 long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); 477 long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1); 478 return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS); 479 } 480 int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); 481 int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH); 482 if (resolverStyle == ResolverStyle.SMART) { // previous valid 483 if (yoe < 1) { 484 throw new DateTimeException("Invalid YearOfEra: " + yoe); 485 } 486 int y = prolepticYearLenient(era, yoe); 487 JapaneseDate result; 488 try { 489 result = date(y, moy, dom); 490 } catch (DateTimeException ex) { 491 result = date(y, moy, 1).with(TemporalAdjusters.lastDayOfMonth()); 492 } 493 // handle the era being changed 494 // only allow if the new date is in the same Jan-Dec as the era change 495 // determine by ensuring either original yoe or result yoe is 1 496 if (result.getEra() != era && result.get(YEAR_OF_ERA) > 1 && yoe > 1) { 497 throw new DateTimeException("Invalid YearOfEra for Era: " + era + " " + yoe); 498 } 499 return result; 500 } 501 return date(era, yoe, moy, dom); 502 } 503 resolveYD(JapaneseEra era, int yoe, Map <TemporalField,Long> fieldValues, ResolverStyle resolverStyle)504 private ChronoLocalDate resolveYD(JapaneseEra era, int yoe, Map <TemporalField,Long> fieldValues, ResolverStyle resolverStyle) { 505 fieldValues.remove(ERA); 506 fieldValues.remove(YEAR_OF_ERA); 507 if (resolverStyle == ResolverStyle.LENIENT) { 508 int y = prolepticYearLenient(era, yoe); 509 long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1); 510 return dateYearDay(y, 1).plus(days, DAYS); 511 } 512 int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR); 513 return dateYearDay(era, yoe, doy); // smart is same as strict 514 } 515 516 //----------------------------------------------------------------------- 517 /** 518 * Writes the Chronology using a 519 * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>. 520 * @serialData 521 * <pre> 522 * out.writeByte(1); // identifies a Chronology 523 * out.writeUTF(getId()); 524 * </pre> 525 * 526 * @return the instance of {@code Ser}, not null 527 */ 528 @Override writeReplace()529 Object writeReplace() { 530 return super.writeReplace(); 531 } 532 533 /** 534 * Defend against malicious streams. 535 * 536 * @param s the stream to read 537 * @throws InvalidObjectException always 538 */ readObject(ObjectInputStream s)539 private void readObject(ObjectInputStream s) throws InvalidObjectException { 540 throw new InvalidObjectException("Deserialization via serialization delegate"); 541 } 542 } 543