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.DataInput;
  60 import java.io.DataOutput;
  61 import java.io.IOException;
  62 import java.io.InvalidObjectException;
  63 import java.io.ObjectStreamException;
  64 import java.io.Serializable;
  65 import java.time.DateTimeException;
  66 import java.time.LocalDate;
  67 import java.util.Arrays;
  68 
  69 import sun.util.calendar.CalendarDate;
  70 
  71 /**
  72  * An era in the Japanese Imperial calendar system.
  73  * <p>
  74  * This class defines the valid eras for the Japanese chronology.
  75  * Only Meiji (1868-09-08 - 1912-07-29) and later eras are supported.
  76  * Japan introduced the Gregorian calendar since Meiji 6. The dates
  77  * between Meiji 1 - 5 are not historically correct.
  78  * The older eras are recognized as Seireki (Western calendar) era,
  79  * and the year of era of Seireki is proleptic Gregorian year.
  80  * (The Julian to Gregorian transition is not supported.)
  81  *
  82  * <h3>Specification for implementors</h3>
  83  * This class is immutable and thread-safe.
  84  *
  85  * @since 1.8
  86  */
  87 final class JapaneseEra
  88         implements Era, Serializable {
  89 
  90     // The offset value to 0-based index from the era value.
  91     // i.e., getValue() + ERA_OFFSET == 0-based index; except that -999 is mapped to zero
  92     static final int ERA_OFFSET = 2;
  93 
  94     static final sun.util.calendar.Era[] ERA_CONFIG;
  95 
  96     /**
  97      * The singleton instance for the before Meiji era ( - 1868-09-07)
  98      * which has the value -999.
  99      */
 100     public static final JapaneseEra SEIREKI = new JapaneseEra(-999, LocalDate.MIN);
 101     /**
 102      * The singleton instance for the 'Meiji' era (1868-09-08 - 1912-07-29)
 103      * which has the value -1.
 104      */
 105     public static final JapaneseEra MEIJI = new JapaneseEra(-1, LocalDate.of(1868, 9, 8));
 106     /**
 107      * The singleton instance for the 'Taisho' era (1912-07-30 - 1926-12-24)
 108      * which has the value 0.
 109      */
 110     public static final JapaneseEra TAISHO = new JapaneseEra(0, LocalDate.of(1912, 7, 30));
 111     /**
 112      * The singleton instance for the 'Showa' era (1926-12-25 - 1989-01-07)
 113      * which has the value 1.
 114      */
 115     public static final JapaneseEra SHOWA = new JapaneseEra(1, LocalDate.of(1926, 12, 25));
 116     /**
 117      * The singleton instance for the 'Heisei' era (1989-01-08 - current)
 118      * which has the value 2.
 119      */
 120     public static final JapaneseEra HEISEI = new JapaneseEra(2, LocalDate.of(1989, 1, 8));
 121 
 122     // the number of defined JapaneseEra constants.
 123     // There could be an extra era defined in its configuration.
 124     private static final int N_ERA_CONSTANTS = HEISEI.getValue() + ERA_OFFSET + 1;
 125 
 126     /**
 127      * Serialization version.
 128      */
 129     private static final long serialVersionUID = 1466499369062886794L;
 130 
 131     // array for the singleton JapaneseEra instances
 132     private static final JapaneseEra[] KNOWN_ERAS;
 133 
 134     static {
 135         sun.util.calendar.Era[] sunEras = JapaneseChronology.JCAL.getEras();
 136         ERA_CONFIG = new sun.util.calendar.Era[sunEras.length + 1];
 137         for (int i = 1; i < ERA_CONFIG.length; i++) {
 138             ERA_CONFIG[i] = sunEras[i - 1];
 139         }
 140         KNOWN_ERAS = new JapaneseEra[ERA_CONFIG.length];
 141         KNOWN_ERAS[0] = SEIREKI;
 142         KNOWN_ERAS[1] = MEIJI;
 143         KNOWN_ERAS[2] = TAISHO;
 144         KNOWN_ERAS[3] = SHOWA;
 145         KNOWN_ERAS[4] = HEISEI;
 146         for (int i = N_ERA_CONSTANTS; i < ERA_CONFIG.length; i++) {
 147             CalendarDate date = ERA_CONFIG[i].getSinceDate();
 148             LocalDate isoDate = LocalDate.of(date.getYear(), date.getMonth(), date.getDayOfMonth());
 149             KNOWN_ERAS[i] = new JapaneseEra(i - ERA_OFFSET, isoDate);
 150         }
 151     };
 152 
 153     /**
 154      * The era value.
 155      * @serial
 156      */
 157     private final int eraValue;
 158 
 159     // the first day of the era
 160     private final transient LocalDate since;
 161 
 162     /**
 163      * Creates an instance.
 164      *
 165      * @param eraValue  the era value, validated
 166      * @param since  the date representing the first date of the era, validated not null
 167      */
 168     private JapaneseEra(int eraValue, LocalDate since) {
 169         this.eraValue = eraValue;
 170         this.since = since;
 171     }
 172 
 173     /**
 174      * Returns the singleton {@code JapaneseEra} corresponding to this object.
 175      * It's possible that this version of {@code JapaneseEra} doesn't support the latest era value.
 176      * In that case, this method throws an {@code ObjectStreamException}.
 177      *
 178      * @return the singleton {@code JapaneseEra} for this object
 179      * @throws ObjectStreamException if the deserialized object has any unknown numeric era value.
 180      */
 181     private Object readResolve() throws ObjectStreamException {
 182         try {
 183             return of(eraValue);
 184         } catch (DateTimeException e) {
 185             InvalidObjectException ex = new InvalidObjectException("Invalid era");
 186             ex.initCause(e);
 187             throw ex;
 188         }
 189     }
 190 
 191     //-----------------------------------------------------------------------
 192     /**
 193      * Returns the Sun private Era instance corresponding to this {@code JapaneseEra}.
 194      * SEIREKI doesn't have its corresponding one.
 195      *
 196      * @return the Sun private Era instance for this {@code JapaneseEra},
 197      *         or null for SEIREKI.
 198      */
 199     sun.util.calendar.Era getPrivateEra() {
 200         return ERA_CONFIG[ordinal(eraValue)];
 201     }
 202 
 203     //-----------------------------------------------------------------------
 204     /**
 205      * Obtains an instance of {@code JapaneseEra} from a value.
 206      * <p>
 207      * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1
 208      * Later era is numbered 2 ({@link #HEISEI}). Earlier eras are numbered 0 ({@link #TAISHO}),
 209      * -1 ({@link #MEIJI}), only Meiji and later eras are supported. The prior to Meiji,
 210      * {@link #SEIREKI} is used.
 211      *
 212      * @param japaneseEra  the era to represent
 213      * @return the {@code JapaneseEra} singleton, never null
 214      * @throws DateTimeException if {@code japaneseEra} is invalid
 215      */
 216     public static JapaneseEra of(int japaneseEra) {
 217         if (japaneseEra != SEIREKI.eraValue &&
 218             (japaneseEra < MEIJI.eraValue || japaneseEra > HEISEI.eraValue)) {
 219             throw new DateTimeException("japaneseEra is invalid");
 220         }
 221         return KNOWN_ERAS[ordinal(japaneseEra)];
 222     }
 223 
 224     /**
 225      * Returns an array of JapaneseEras.
 226      * @return an array of JapaneseEras
 227      */
 228     static JapaneseEra[] values() {
 229         return Arrays.copyOf(KNOWN_ERAS, KNOWN_ERAS.length);
 230     }
 231 
 232     //-----------------------------------------------------------------------
 233     /**
 234      * Obtains an instance of {@code JapaneseEra} from a date.
 235      *
 236      * @param date  the date, not null
 237      * @return the Era singleton, never null
 238      */
 239     static JapaneseEra from(LocalDate date) {
 240         for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
 241             JapaneseEra era = KNOWN_ERAS[i];
 242             if (date.compareTo(era.since) >= 0) {
 243                 return era;
 244             }
 245         }
 246         return SEIREKI;
 247     }
 248 
 249     static JapaneseEra toJapaneseEra(sun.util.calendar.Era privateEra) {
 250         for (int i = ERA_CONFIG.length - 1; i > 0; i--) {
 251             if (ERA_CONFIG[i].equals(privateEra)) {
 252                 return KNOWN_ERAS[i];
 253             }
 254         }
 255         return SEIREKI;
 256     }
 257 
 258     static sun.util.calendar.Era privateEraFrom(LocalDate isoDate) {
 259         for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
 260             JapaneseEra era = KNOWN_ERAS[i];
 261             if (isoDate.compareTo(era.since) >= 0) {
 262                 return ERA_CONFIG[i];
 263             }
 264         }
 265         return null;
 266     }
 267 
 268     /**
 269      * Returns the index into the arrays from the Era value.
 270      * the eraValue is a valid Era number, -999, -1..2.
 271      * @param eravalue the era value to convert to the index
 272      * @return the index of the current Era
 273      */
 274     private static int ordinal(int eravalue) {
 275         return (eravalue == SEIREKI.eraValue) ? 0 : eravalue + ERA_OFFSET;
 276     }
 277 
 278     //-----------------------------------------------------------------------
 279     /**
 280      * Returns the numeric value of this {@code JapaneseEra}.
 281      * <p>
 282      * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1.
 283      * Later eras are numbered from 2 ({@link #HEISEI}).
 284      * Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI}), and -999 ({@link #SEIREKI}).
 285      *
 286      * @return the era value
 287      */
 288     @Override
 289     public int getValue() {
 290         return eraValue;
 291     }
 292 
 293     @Override
 294     public JapaneseChronology getChronology() {
 295         return JapaneseChronology.INSTANCE;
 296     }
 297 
 298     //-----------------------------------------------------------------------
 299     String getAbbreviation() {
 300         int index = ordinal(getValue());
 301         if (index == 0) {
 302             return "";
 303         }
 304         return ERA_CONFIG[index].getAbbreviation();
 305     }
 306 
 307     String getName() {
 308         int index = ordinal(getValue());
 309         if (index == 0) {
 310             return "Seireki";
 311         }
 312         return ERA_CONFIG[index].getName();
 313     }
 314 
 315     @Override
 316     public String toString() {
 317         return getName();
 318     }
 319 
 320     //-----------------------------------------------------------------------
 321     private Object writeReplace() {
 322         return new Ser(Ser.JAPANESE_ERA_TYPE, this);
 323     }
 324 
 325     void writeExternal(DataOutput out) throws IOException {
 326         out.writeByte(this.getValue());
 327     }
 328 
 329     static JapaneseEra readExternal(DataInput in) throws IOException {
 330         byte eraValue = in.readByte();
 331         return JapaneseEra.of(eraValue);
 332     }
 333 
 334 }