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 java.io.Serializable; 60 import java.time.Clock; 61 import java.time.DateTimeException; 62 import java.time.Instant; 63 import java.time.LocalDate; 64 import java.time.temporal.ChronoField; 65 import java.time.temporal.TemporalAccessor; 66 import java.time.temporal.ValueRange; 67 import java.time.Year; 68 import java.time.ZoneId; 69 import java.util.Arrays; 70 import java.util.Calendar; 71 import java.util.List; 72 import java.util.Locale; 73 74 import sun.util.calendar.CalendarSystem; 75 import sun.util.calendar.LocalGregorianCalendar; 76 77 /** 78 * The Japanese Imperial calendar system. 79 * <p> 80 * This chronology defines the rules of the Japanese Imperial calendar system. 81 * This calendar system is primarily used in Japan. 82 * The Japanese Imperial calendar system is the same as the ISO calendar system 83 * apart from the era-based year numbering. 84 * <p> 85 * Only Meiji (1865-04-07 - 1868-09-07) and later eras are supported. 86 * Older eras are handled as an unknown era where the year-of-era is the ISO year. 87 * 88 * <h3>Specification for implementors</h3> 89 * This class is immutable and thread-safe. 90 * 91 * @since 1.8 92 */ 93 public final class JapaneseChronology extends Chronology implements Serializable { 94 // TODO: definition for unknown era may break requirement that year-of-era >= 1 95 96 static final LocalGregorianCalendar JCAL = 97 (LocalGregorianCalendar) CalendarSystem.forName("japanese"); 98 99 // Locale for creating a JapaneseImpericalCalendar. 100 static final Locale LOCALE = Locale.forLanguageTag("ja-JP-u-ca-japanese"); 101 102 /** 103 * Singleton instance for Japanese chronology. 104 */ 105 public static final JapaneseChronology INSTANCE = new JapaneseChronology(); 106 107 /** 108 * The singleton instance for the before Meiji era ( - 1868-09-07) 109 * which has the value -999. 110 */ 111 public static final Era ERA_SEIREKI = JapaneseEra.SEIREKI; 112 /** 113 * The singleton instance for the Meiji era (1868-09-08 - 1912-07-29) 114 * which has the value -1. 115 */ 116 public static final Era ERA_MEIJI = JapaneseEra.MEIJI; 117 /** 118 * The singleton instance for the Taisho era (1912-07-30 - 1926-12-24) 119 * which has the value 0. 120 */ 121 public static final Era ERA_TAISHO = JapaneseEra.TAISHO; 122 /** 123 * The singleton instance for the Showa era (1926-12-25 - 1989-01-07) 124 * which has the value 1. 125 */ 126 public static final Era ERA_SHOWA = JapaneseEra.SHOWA; 127 /** 128 * The singleton instance for the Heisei era (1989-01-08 - current) 129 * which has the value 2. 130 */ 131 public static final Era ERA_HEISEI = JapaneseEra.HEISEI; 132 /** 133 * Serialization version. 134 */ 135 private static final long serialVersionUID = 459996390165777884L; 136 137 //----------------------------------------------------------------------- 138 /** 139 * Restricted constructor. 140 */ 141 private JapaneseChronology() { 142 } 143 144 /** 145 * Resolve singleton. 146 * 147 * @return the singleton instance, not null 148 */ 149 private Object readResolve() { 150 return INSTANCE; 151 } 152 153 //----------------------------------------------------------------------- 154 /** 155 * Gets the ID of the chronology - 'Japanese'. 156 * <p> 157 * The ID uniquely identifies the {@code Chronology}. 158 * It can be used to lookup the {@code Chronology} using {@link #of(String)}. 159 * 160 * @return the chronology ID - 'Japanese' 161 * @see #getCalendarType() 162 */ 163 @Override 164 public String getId() { 165 return "Japanese"; 166 } 167 168 /** 169 * Gets the calendar type of the underlying calendar system - 'japanese'. 170 * <p> 171 * The calendar type is an identifier defined by the 172 * <em>Unicode Locale Data Markup Language (LDML)</em> specification. 173 * It can be used to lookup the {@code Chronology} using {@link #of(String)}. 174 * It can also be used as part of a locale, accessible via 175 * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. 176 * 177 * @return the calendar system type - 'japanese' 178 * @see #getId() 179 */ 180 @Override 181 public String getCalendarType() { 182 return "japanese"; 183 } 184 185 //----------------------------------------------------------------------- 186 @Override 187 public JapaneseDate date(Era era, int yearOfEra, int month, int dayOfMonth) { 188 if (era instanceof JapaneseEra == false) { 189 throw new DateTimeException("Era must be JapaneseEra"); 190 } 191 return JapaneseDate.of((JapaneseEra) era, yearOfEra, month, dayOfMonth); 192 } 193 194 @Override 195 public JapaneseDate date(int prolepticYear, int month, int dayOfMonth) { 196 return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth)); 197 } 198 199 @Override 200 public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) { 201 LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear); 202 return date(prolepticYear, date.getMonthValue(), date.getDayOfMonth()); 203 } 204 205 @Override 206 public JapaneseDate date(TemporalAccessor temporal) { 207 if (temporal instanceof JapaneseDate) { 208 return (JapaneseDate) temporal; 209 } 210 return new JapaneseDate(LocalDate.from(temporal)); 211 } 212 213 @Override 214 public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { 215 return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); 216 } 217 218 @Override 219 public JapaneseDate dateNow() { 220 return dateNow(Clock.systemDefaultZone()); 221 } 222 223 @Override 224 public JapaneseDate dateNow(ZoneId zone) { 225 return dateNow(Clock.system(zone)); 226 } 227 228 @Override 229 public JapaneseDate dateNow(Clock clock) { 230 return date(LocalDate.now(clock)); 231 } 232 233 @Override 234 public ChronoLocalDateTime<JapaneseDate> localDateTime(TemporalAccessor temporal) { 235 return (ChronoLocalDateTime<JapaneseDate>)super.localDateTime(temporal); 236 } 237 238 @Override 239 public ChronoZonedDateTime<JapaneseDate> zonedDateTime(TemporalAccessor temporal) { 240 return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(temporal); 241 } 242 243 @Override 244 public ChronoZonedDateTime<JapaneseDate> zonedDateTime(Instant instant, ZoneId zone) { 245 return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(instant, zone); 246 } 247 248 //----------------------------------------------------------------------- 249 /** 250 * Checks if the specified year is a leap year. 251 * <p> 252 * Japanese calendar leap years occur exactly in line with ISO leap years. 253 * This method does not validate the year passed in, and only has a 254 * well-defined result for years in the supported range. 255 * 256 * @param prolepticYear the proleptic-year to check, not validated for range 257 * @return true if the year is a leap year 258 */ 259 @Override 260 public boolean isLeapYear(long prolepticYear) { 261 return IsoChronology.INSTANCE.isLeapYear(prolepticYear); 262 } 263 264 @Override 265 public int prolepticYear(Era era, int yearOfEra) { 266 if (era instanceof JapaneseEra == false) { 267 throw new DateTimeException("Era must be JapaneseEra"); 268 } 269 JapaneseEra jera = (JapaneseEra) era; 270 int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1; 271 if (yearOfEra == 1) { 272 return gregorianYear; 273 } 274 LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null); 275 jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1); 276 JCAL.normalize(jdate); 277 if (jdate.getNormalizedYear() == gregorianYear) { 278 return gregorianYear; 279 } 280 throw new DateTimeException("invalid yearOfEra value"); 281 } 282 283 /** 284 * Returns the calendar system era object from the given numeric value. 285 * 286 * See the description of each Era for the numeric values of: 287 * {@link #ERA_HEISEI}, {@link #ERA_SHOWA},{@link #ERA_TAISHO}, 288 * {@link #ERA_MEIJI}), only Meiji and later eras are supported. 289 * Prior to Meiji {@link #ERA_SEIREKI} is used. 290 * 291 * @param eraValue the era value 292 * @return the Japanese {@code Era} for the given numeric era value 293 * @throws DateTimeException if {@code eraValue} is invalid 294 */ 295 @Override 296 public Era eraOf(int eraValue) { 297 return JapaneseEra.of(eraValue); 298 } 299 300 @Override 301 public List<Era> eras() { 302 return Arrays.<Era>asList(JapaneseEra.values()); 303 } 304 305 //----------------------------------------------------------------------- 306 @Override 307 public ValueRange range(ChronoField field) { 308 switch (field) { 309 case DAY_OF_MONTH: 310 case DAY_OF_WEEK: 311 case MICRO_OF_DAY: 312 case MICRO_OF_SECOND: 313 case HOUR_OF_DAY: 314 case HOUR_OF_AMPM: 315 case MINUTE_OF_DAY: 316 case MINUTE_OF_HOUR: 317 case SECOND_OF_DAY: 318 case SECOND_OF_MINUTE: 319 case MILLI_OF_DAY: 320 case MILLI_OF_SECOND: 321 case NANO_OF_DAY: 322 case NANO_OF_SECOND: 323 case CLOCK_HOUR_OF_DAY: 324 case CLOCK_HOUR_OF_AMPM: 325 case EPOCH_DAY: 326 case EPOCH_MONTH: 327 return field.range(); 328 } 329 Calendar jcal = Calendar.getInstance(LOCALE); 330 int fieldIndex; 331 switch (field) { 332 case ERA: 333 return ValueRange.of(jcal.getMinimum(Calendar.ERA) - JapaneseEra.ERA_OFFSET, 334 jcal.getMaximum(Calendar.ERA) - JapaneseEra.ERA_OFFSET); 335 case YEAR: 336 case YEAR_OF_ERA: 337 return ValueRange.of(Year.MIN_VALUE, jcal.getGreatestMinimum(Calendar.YEAR), 338 jcal.getLeastMaximum(Calendar.YEAR), Year.MAX_VALUE); 339 case MONTH_OF_YEAR: 340 return ValueRange.of(jcal.getMinimum(Calendar.MONTH) + 1, jcal.getGreatestMinimum(Calendar.MONTH) + 1, 341 jcal.getLeastMaximum(Calendar.MONTH) + 1, jcal.getMaximum(Calendar.MONTH) + 1); 342 case DAY_OF_YEAR: 343 fieldIndex = Calendar.DAY_OF_YEAR; 344 break; 345 default: 346 // TODO: review the remaining fields 347 throw new UnsupportedOperationException("Unimplementable field: " + field); 348 } 349 return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex), 350 jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex)); 351 } 352 353 }