Home | History | Annotate | Download | only in chrono
      1 /*
      2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      3  *
      4  * This code is free software; you can redistribute it and/or modify it
      5  * under the terms of the GNU General Public License version 2 only, as
      6  * published by the Free Software Foundation.  Oracle designates this
      7  * particular file as subject to the "Classpath" exception as provided
      8  * by Oracle in the LICENSE file that accompanied this code.
      9  *
     10  * This code is distributed in the hope that it will be useful, but WITHOUT
     11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     13  * version 2 for more details (a copy is included in the LICENSE file that
     14  * accompanied this code).
     15  *
     16  * You should have received a copy of the GNU General Public License version
     17  * 2 along with this work; if not, write to the Free Software Foundation,
     18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     19  *
     20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     21  * or visit www.oracle.com if you need additional information or have any
     22  * questions.
     23  */
     24 
     25 /*
     26  * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
     27  *
     28  * All rights reserved.
     29  *
     30  * Redistribution and use in source and binary forms, with or without
     31  * modification, are permitted provided that the following conditions are met:
     32  *
     33  *  * Redistributions of source code must retain the above copyright notice,
     34  *    this list of conditions and the following disclaimer.
     35  *
     36  *  * Redistributions in binary form must reproduce the above copyright notice,
     37  *    this list of conditions and the following disclaimer in the documentation
     38  *    and/or other materials provided with the distribution.
     39  *
     40  *  * Neither the name of JSR-310 nor the names of its contributors
     41  *    may be used to endorse or promote products derived from this software
     42  *    without specific prior written permission.
     43  *
     44  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     45  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     46  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     47  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     48  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     49  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     50  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     51  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     52  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     53  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     54  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     55  */
     56 
     57 package tck.java.time.chrono;
     58 
     59 import static java.time.temporal.ChronoField.EPOCH_DAY;
     60 
     61 import java.io.Serializable;
     62 import java.time.chrono.AbstractChronology;
     63 import java.time.chrono.Era;
     64 import java.time.temporal.ChronoField;
     65 import java.time.temporal.TemporalAccessor;
     66 import java.time.temporal.ValueRange;
     67 import java.util.Arrays;
     68 import java.util.List;
     69 import java.util.Locale;
     70 
     71 /**
     72  * The Coptic calendar system.
     73  * <p>
     74  * This chronology defines the rules of the Coptic calendar system.
     75  * This calendar system is primarily used in Christian Egypt.
     76  * Dates are aligned such that {@code 0001AM-01-01 (Coptic)} is {@code 0284-08-29 (ISO)}.
     77  * <p>
     78  * The fields are defined as follows:
     79  * <p><ul>
     80  * <li>era - There are two eras, the current 'Era of the Martyrs' (AM) and the previous era (ERA_ERA_BEFORE_AM).
     81  * <li>year-of-era - The year-of-era for the current era increases uniformly from the epoch at year one.
     82  *  For the previous era the year increases from one as time goes backwards.
     83  * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
     84  *  current era. For the previous era, years have zero, then negative values.
     85  * <li>month-of-year - There are 13 months in a Coptic year, numbered from 1 to 13.
     86  * <li>day-of-month - There are 30 days in each of the first 12 Coptic months, numbered 1 to 30.
     87  *  The 13th month has 5 days, or 6 in a leap year, numbered 1 to 5 or 1 to 6.
     88  * <li>day-of-year - There are 365 days in a standard Coptic year and 366 in a leap year.
     89  *  The days are numbered from 1 to 365 or 1 to 366.
     90  * <li>leap-year - Leap years occur every 4 years.
     91  * </ul><p>
     92  *
     93  * <h4>Implementation notes</h4>
     94  * This class is immutable and thread-safe.
     95  */
     96 public final class CopticChronology extends AbstractChronology implements Serializable {
     97 
     98     /**
     99      * Singleton instance of the Coptic chronology.
    100      */
    101     public static final CopticChronology INSTANCE = new CopticChronology();
    102 
    103     /**
    104      * Serialization version.
    105      */
    106     private static final long serialVersionUID = 7291205177830286973L;
    107     /**
    108      * Range of months.
    109      */
    110     static final ValueRange MOY_RANGE = ValueRange.of(1, 13);
    111     /**
    112      * Range of days.
    113      */
    114     static final ValueRange DOM_RANGE = ValueRange.of(1, 5, 30);
    115     /**
    116      * Range of days.
    117      */
    118     static final ValueRange DOM_RANGE_NONLEAP = ValueRange.of(1, 5);
    119     /**
    120      * Range of days.
    121      */
    122     static final ValueRange DOM_RANGE_LEAP = ValueRange.of(1, 6);
    123 
    124     /**
    125      * Public Constructor to be instantiated by the ServiceLoader
    126      */
    127     public CopticChronology() {
    128     }
    129 
    130     /**
    131      * Resolve singleton.
    132      *
    133      * @return the singleton instance, not null
    134      */
    135     private Object readResolve() {
    136         return INSTANCE;
    137     }
    138 
    139     //-----------------------------------------------------------------------
    140     /**
    141      * Gets the ID of the chronology - 'Coptic'.
    142      * <p>
    143      * The ID uniquely identifies the {@code Chronology}.
    144      * It can be used to lookup the {@code Chronology} using {@link #of(String)}.
    145      *
    146      * @return the chronology ID - 'Coptic'
    147      * @see #getCalendarType()
    148      */
    149     @Override
    150     public String getId() {
    151         return "Coptic";
    152     }
    153 
    154     /**
    155      * Gets the calendar type of the underlying calendar system - 'coptic'.
    156      * <p>
    157      * The calendar type is an identifier defined by the
    158      * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
    159      * It can be used to lookup the {@code Chronology} using {@link #of(String)}.
    160      * It can also be used as part of a locale, accessible via
    161      * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
    162      *
    163      * @return the calendar system type - 'coptic'
    164      * @see #getId()
    165      */
    166     @Override
    167     public String getCalendarType() {
    168         return "coptic";
    169     }
    170 
    171     //-----------------------------------------------------------------------
    172     @Override
    173     public CopticDate date(int prolepticYear, int month, int dayOfMonth) {
    174         return new CopticDate(prolepticYear, month, dayOfMonth);
    175     }
    176 
    177     @Override
    178     public CopticDate dateYearDay(int prolepticYear, int dayOfYear) {
    179         return new CopticDate(prolepticYear, (dayOfYear - 1) / 30 + 1, (dayOfYear - 1) % 30 + 1);
    180     }
    181 
    182     @Override
    183     public CopticDate dateEpochDay(long epochDay) {
    184         return CopticDate.ofEpochDay(epochDay);
    185     }
    186 
    187     @Override
    188     public CopticDate date(TemporalAccessor dateTime) {
    189         if (dateTime instanceof CopticDate) {
    190             return (CopticDate) dateTime;
    191         }
    192         return CopticDate.ofEpochDay(dateTime.getLong(EPOCH_DAY));
    193     }
    194 
    195     //-----------------------------------------------------------------------
    196     /**
    197      * Checks if the specified year is a leap year.
    198      * <p>
    199      * A Coptic proleptic-year is leap if the remainder after division by four equals three.
    200      * This method does not validate the year passed in, and only has a
    201      * well-defined result for years in the supported range.
    202      *
    203      * @param prolepticYear  the proleptic-year to check, not validated for range
    204      * @return true if the year is a leap year
    205      */
    206     @Override
    207     public boolean isLeapYear(long prolepticYear) {
    208         return Math.floorMod(prolepticYear, 4) == 3;
    209     }
    210 
    211     @Override
    212     public int prolepticYear(Era era, int yearOfEra) {
    213         if (era instanceof CopticEra == false) {
    214             throw new ClassCastException("Era must be CopticEra");
    215         }
    216         return (era == CopticEra.AM ? yearOfEra : 1 - yearOfEra);
    217     }
    218 
    219     @Override
    220     public Era eraOf(int eraValue) {
    221         return CopticEra.of(eraValue);
    222     }
    223 
    224     @Override
    225     public List<Era> eras() {
    226         return Arrays.<Era>asList(CopticEra.values());
    227     }
    228 
    229     //-----------------------------------------------------------------------
    230     @Override
    231     public ValueRange range(ChronoField field) {
    232         switch (field) {
    233             case DAY_OF_MONTH: return ValueRange.of(1, 5, 30);
    234             case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, 1, 5);
    235             case MONTH_OF_YEAR: return ValueRange.of(1, 13);
    236             case PROLEPTIC_MONTH: return ValueRange.of(-1000, 1000);  // TODO
    237             case YEAR_OF_ERA: return ValueRange.of(1, 999, 1000);  // TODO
    238             case YEAR: return ValueRange.of(-1000, 1000);  // TODO
    239         }
    240         return field.range();
    241     }
    242 
    243 }
    244