12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others.
22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/*
47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 2005-2011, International Business Machines Corporation and    *
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved.                                                *
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.util;
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Date;
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale;
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale.Category;
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Base class for EthiopicCalendar and CopticCalendar.
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertabstract class CECalendar extends Calendar {
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // jdk1.4.2 serialver
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final long serialVersionUID = -999547623066414271L;
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int LIMITS[][] = {
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Minimum  Greatest    Least  Maximum
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        //           Minimum  Maximum
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {        0,        0,       1,       1 }, // ERA
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {        1,        1, 5000000, 5000000 }, // YEAR
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {        0,        0,      12,      12 }, // MONTH
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {        1,        1,      52,      53 }, // WEEK_OF_YEAR
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // WEEK_OF_MONTH
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {        1,        1,       5,      30 }, // DAY_OF_MONTH
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {        1,        1,     365,     366 }, // DAY_OF_YEAR
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // DAY_OF_WEEK
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {       -1,       -1,       1,       5 }, // DAY_OF_WEEK_IN_MONTH
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // AM_PM
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // HOUR
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // HOUR_OF_DAY
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // MINUTE
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // SECOND
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // MILLISECOND
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // ZONE_OFFSET
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // DST_OFFSET
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        { -5000000, -5000000, 5000000, 5000000 }, // YEAR_WOY
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // DOW_LOCAL
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        { -5000000, -5000000, 5000000, 5000000 }, // EXTENDED_YEAR
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // JULIAN_DAY
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {/*                                  */}, // MILLISECONDS_IN_DAY
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //-------------------------------------------------------------------------
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Constructors...
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //-------------------------------------------------------------------------
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a default <code>CECalendar</code> using the current time
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in the default time zone with the default <code>FORMAT</code> locale.
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected CECalendar() {
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a <code>CECalendar</code> based on the current time
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in the given time zone with the default <code>FORMAT</code> locale.
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param zone The time zone for the new calendar.
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected CECalendar(TimeZone zone) {
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(zone, ULocale.getDefault(Category.FORMAT));
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a <code>CECalendar</code> based on the current time
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in the default time zone with the given locale.
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param aLocale The locale for the new calendar.
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected CECalendar(Locale aLocale) {
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(TimeZone.getDefault(), aLocale);
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a <code>CECalendar</code> based on the current time
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in the default time zone with the given locale.
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param locale The locale for the new calendar.
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected CECalendar(ULocale locale) {
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(TimeZone.getDefault(), locale);
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a <code>CECalendar</code> based on the current time
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in the given time zone with the given locale.
957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param zone The time zone for the new calendar.
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param aLocale The locale for the new calendar.
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected CECalendar(TimeZone zone, Locale aLocale) {
1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super(zone, aLocale);
1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setTimeInMillis(System.currentTimeMillis());
1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a <code>CECalendar</code> based on the current time
1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in the given time zone with the given locale.
1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param zone The time zone for the new calendar.
1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param locale The locale for the new calendar.
1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected CECalendar(TimeZone zone, ULocale locale) {
1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super(zone, locale);
1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setTimeInMillis(System.currentTimeMillis());
1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a <code>CECalendar</code> with the given date set
1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in the default time zone with the default <code>FORMAT</code> locale.
1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param year      The value used to set the calendar's {@link #YEAR YEAR} time field.
1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month     The value used to set the calendar's {@link #MONTH MONTH} time field.
1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                  The value is 0-based. e.g., 0 for Tishri.
1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param date      The value used to set the calendar's {@link #DATE DATE} time field.
1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected CECalendar(int year, int month, int date) {
1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.set(year, month, date);
1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a <code>CECalendar</code> with the given date set
1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in the default time zone with the default <code>FORMAT</code> locale.
1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param date      The date to which the new calendar is set.
1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected CECalendar(Date date) {
1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.setTime(date);
1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a <code>CECalendar</code> with the given date
1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * and time set for the default time zone with the default <code>FORMAT</code> locale.
1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param year      The value used to set the calendar's {@link #YEAR YEAR} time field.
1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month     The value used to set the calendar's {@link #MONTH MONTH} time field.
1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                  The value is 0-based. e.g., 0 for Tishri.
1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param date      The value used to set the calendar's {@link #DATE DATE} time field.
1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param hour      The value used to set the calendar's {@link #HOUR_OF_DAY HOUR_OF_DAY} time field.
1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param minute    The value used to set the calendar's {@link #MINUTE MINUTE} time field.
1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param second    The value used to set the calendar's {@link #SECOND SECOND} time field.
1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected CECalendar(int year, int month, int date, int hour,
1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                         int minute, int second)
1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.set(year, month, date, hour, minute, second);
1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //-------------------------------------------------------------------------
1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Calendar framework
1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //-------------------------------------------------------------------------
1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The Coptic and Ethiopic calendars differ only in their epochs.
1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This method must be implemented by CECalendar subclasses to
1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * return the date offset from Julian.
1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    abstract protected int getJDEpochOffset();
1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Return JD of start of given month/extended year
1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected int handleComputeMonthStart(int eyear,
1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                          int emonth,
1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                          boolean useMonth) {
1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return ceToJD(eyear, emonth, 0, getJDEpochOffset());
1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Calculate the limit for a specified type of limit and field
1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected int handleGetLimit(int field, int limitType) {
1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return LIMITS[field][limitType];
1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // (The following method is not called because all existing subclasses
1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // override it.
1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    ///CLOVER:OFF
1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Return the number of days in the given month of the given extended
1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * year of this calendar system.  Subclasses should override this
1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * method if they can provide a more correct or more efficient
1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * implementation than the default implementation in Calendar.
1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected int handleGetMonthLength(int extendedYear, int month)
2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // The Ethiopian and Coptic calendars have 13 months, 12 of 30 days each and
2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // an intercalary month at the end of the year of 5 or 6 days, depending whether
2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // the year is a leap year or not. The Leap Year follows the same rules as the
2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Julian Calendar so that the extra month always has six days in the year before
2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // a Julian Leap Year.
2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if ((month + 1) % 13 != 0)
2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // not intercalary month
2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return 30;
2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        else
2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        {
2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // intercalary month 5 days + possible leap day
2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return ((extendedYear % 4) / 3) + 5;
2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    ///CLOVER:ON
2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //-------------------------------------------------------------------------
2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Calendar framework
2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //-------------------------------------------------------------------------
2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Convert an Coptic/Ethiopic year, month and day to a Julian day
2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param year the extended year
2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param month the month
2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param day the day
2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return Julian day
2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static int ceToJD(long year, int month, int day, int jdEpochOffset) {
2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Julian<->Ethiopic algorithms from:
2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // "Calendars in Ethiopia", Berhanu Beyene, Manfred Kudlek, International Conference
2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // of Ethiopian Studies XV, Hamburg, 2003
2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // handle month > 12, < 0 (e.g. from add/set)
2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if ( month >= 0 ) {
2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            year += month/13;
2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            month %= 13;
2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ++month;
2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            year += month/13 - 1;
2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            month = month%13 + 12;
2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (int) (
2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            jdEpochOffset           // difference from Julian epoch to 1,1,1
2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            + 365 * year            // number of days from years
2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            + floorDivide(year, 4)  // extra day of leap year
2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            + 30 * month            // number of days from months (months are 0-based)
2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            + day - 1               // number of days for present month (1 based)
2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            );
2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Convert a Julian day to an Coptic/Ethiopic year, month and day
2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static void jdToCE(int julianDay, int jdEpochOffset, int[] fields) {
2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int c4; // number of 4 year cycle (1461 days)
2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int[] r4 = new int[1]; // remainder of 4 year cycle, always positive
2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        c4 = floorDivide(julianDay - jdEpochOffset, 1461, r4);
2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // exteded year
2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        fields[0] = 4 * c4 + (r4[0]/365 - r4[0]/1460); // 4 * <number of 4year cycle> + <years within the last cycle>
2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int doy = (r4[0] == 1460) ? 365 : (r4[0] % 365); // days in present year
2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // month
2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        fields[1] = doy / 30; // 30 -> Coptic/Ethiopic month length up to 12th month
2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // day
2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        fields[2] = (doy % 30) + 1; // 1-based days in a month
2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
277