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