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