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.util.Arrays;
  63 import java.util.List;
  64 import java.util.Locale;
  65 
  66 import java.time.DateTimeException;
  67 import java.time.temporal.ChronoField;
  68 import java.time.temporal.TemporalAccessor;
  69 import java.time.temporal.ValueRange;
  70 import java.time.chrono.Chronology;
  71 import java.time.chrono.ChronoLocalDate;
  72 import java.time.chrono.Era;
  73 
  74 /**
  75  * The Coptic calendar system.
  76  * <p>
  77  * This chronology defines the rules of the Coptic calendar system.
  78  * This calendar system is primarily used in Christian Egypt.
  79  * Dates are aligned such that {@code 0001AM-01-01 (Coptic)} is {@code 0284-08-29 (ISO)}.
  80  * <p>
  81  * The fields are defined as follows:
  82  * <p><ul>
  83  * <li>era - There are two eras, the current 'Era of the Martyrs' (AM) and the previous era (ERA_ERA_BEFORE_AM).
  84  * <li>year-of-era - The year-of-era for the current era increases uniformly from the epoch at year one.
  85  *  For the previous era the year increases from one as time goes backwards.
  86  * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
  87  *  current era. For the previous era, years have zero, then negative values.
  88  * <li>month-of-year - There are 13 months in a Coptic year, numbered from 1 to 13.
  89  * <li>day-of-month - There are 30 days in each of the first 12 Coptic months, numbered 1 to 30.
  90  *  The 13th month has 5 days, or 6 in a leap year, numbered 1 to 5 or 1 to 6.
  91  * <li>day-of-year - There are 365 days in a standard Coptic year and 366 in a leap year.
  92  *  The days are numbered from 1 to 365 or 1 to 366.
  93  * <li>leap-year - Leap years occur every 4 years.
  94  * </ul><p>
  95  *
  96  * <h4>Implementation notes</h4>
  97  * This class is immutable and thread-safe.
  98  */
  99 public final class CopticChronology extends Chronology implements Serializable {
 100 
 101     /**
 102      * Singleton instance of the Coptic chronology.
 103      */
 104     public static final CopticChronology INSTANCE = new CopticChronology();
 105     /**
 106      * The singleton instance for the era BEFORE_AM.
 107      * This has the numeric value of {@code 0}.
 108      */
 109     public static final Era ERA_BEFORE_AM = CopticEra.BEFORE_AM;
 110     /**
 111      * The singleton instance for the era AM - 'Era of the Martyrs'.
 112      * This has the numeric value of {@code 1}.
 113      */
 114     public static final Era ERA_AM = CopticEra.AM;
 115 
 116     /**
 117      * Serialization version.
 118      */
 119     private static final long serialVersionUID = 7291205177830286973L;
 120     /**
 121      * Range of months.
 122      */
 123     static final ValueRange MOY_RANGE = ValueRange.of(1, 13);
 124     /**
 125      * Range of days.
 126      */
 127     static final ValueRange DOM_RANGE = ValueRange.of(1, 5, 30);
 128     /**
 129      * Range of days.
 130      */
 131     static final ValueRange DOM_RANGE_NONLEAP = ValueRange.of(1, 5);
 132     /**
 133      * Range of days.
 134      */
 135     static final ValueRange DOM_RANGE_LEAP = ValueRange.of(1, 6);
 136 
 137     /**
 138      * Public Constructor to be instantiated by the ServiceLoader
 139      */
 140     public CopticChronology() {
 141     }
 142 
 143     /**
 144      * Resolve singleton.
 145      *
 146      * @return the singleton instance, not null
 147      */
 148     private Object readResolve() {
 149         return INSTANCE;
 150     }
 151 
 152     //-----------------------------------------------------------------------
 153     /**
 154      * Gets the ID of the chronology - 'Coptic'.
 155      * <p>
 156      * The ID uniquely identifies the {@code Chronology}.
 157      * It can be used to lookup the {@code Chronology} using {@link #of(String)}.
 158      *
 159      * @return the chronology ID - 'Coptic'
 160      * @see #getCalendarType()
 161      */
 162     @Override
 163     public String getId() {
 164         return "Coptic";
 165     }
 166 
 167     /**
 168      * Gets the calendar type of the underlying calendar system - 'coptic'.
 169      * <p>
 170      * The calendar type is an identifier defined by the
 171      * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
 172      * It can be used to lookup the {@code Chronology} using {@link #of(String)}.
 173      * It can also be used as part of a locale, accessible via
 174      * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
 175      *
 176      * @return the calendar system type - 'coptic'
 177      * @see #getId()
 178      */
 179     @Override
 180     public String getCalendarType() {
 181         return "coptic";
 182     }
 183 
 184     //-----------------------------------------------------------------------
 185     @Override
 186     public CopticDate date(int prolepticYear, int month, int dayOfMonth) {
 187         return new CopticDate(prolepticYear, month, dayOfMonth);
 188     }
 189 
 190     @Override
 191     public CopticDate dateYearDay(int prolepticYear, int dayOfYear) {
 192         return new CopticDate(prolepticYear, (dayOfYear - 1) / 30 + 1, (dayOfYear - 1) % 30 + 1);
 193     }
 194 
 195     @Override
 196     public CopticDate date(TemporalAccessor dateTime) {
 197         if (dateTime instanceof CopticDate) {
 198             return (CopticDate) dateTime;
 199         }
 200         return CopticDate.ofEpochDay(dateTime.getLong(EPOCH_DAY));
 201     }
 202 
 203     //-----------------------------------------------------------------------
 204     /**
 205      * Checks if the specified year is a leap year.
 206      * <p>
 207      * A Coptic proleptic-year is leap if the remainder after division by four equals three.
 208      * This method does not validate the year passed in, and only has a
 209      * well-defined result for years in the supported range.
 210      *
 211      * @param prolepticYear  the proleptic-year to check, not validated for range
 212      * @return true if the year is a leap year
 213      */
 214     @Override
 215     public boolean isLeapYear(long prolepticYear) {
 216         return Math.floorMod(prolepticYear, 4) == 3;
 217     }
 218 
 219     @Override
 220     public int prolepticYear(Era era, int yearOfEra) {
 221         if (era instanceof CopticEra == false) {
 222             throw new DateTimeException("Era must be CopticEra");
 223         }
 224         return (era == CopticEra.AM ? yearOfEra : 1 - yearOfEra);
 225     }
 226 
 227     @Override
 228     public Era eraOf(int eraValue) {
 229         return CopticEra.of(eraValue);
 230     }
 231 
 232     @Override
 233     public List<Era> eras() {
 234         return Arrays.<Era>asList(CopticEra.values());
 235     }
 236 
 237     //-----------------------------------------------------------------------
 238     @Override
 239     public ValueRange range(ChronoField field) {
 240         switch (field) {
 241             case DAY_OF_MONTH: return ValueRange.of(1, 5, 30);
 242             case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, 1, 5);
 243             case MONTH_OF_YEAR: return ValueRange.of(1, 13);
 244             case EPOCH_MONTH: return ValueRange.of(-1000, 1000);  // TODO
 245             case YEAR_OF_ERA: return ValueRange.of(1, 999, 1000);  // TODO
 246             case YEAR: return ValueRange.of(-1000, 1000);  // TODO
 247         }
 248         return field.range();
 249     }
 250 
 251 }