001/*
002 *  Copyright 2001-2009 Stephen Colebourne
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.joda.time.chrono;
017
018import java.io.Serializable;
019import java.util.HashMap;
020import java.util.Map;
021
022import org.joda.time.Chronology;
023import org.joda.time.DateTime;
024import org.joda.time.DateTimeConstants;
025import org.joda.time.DateTimeField;
026import org.joda.time.DateTimeZone;
027
028/**
029 * Implements the Islamic, or Hijri, calendar system using arithmetic rules.
030 * <p>
031 * This calendar is a lunar calendar with a shorter year than ISO.
032 * Year 1 in the Islamic calendar began on July 16, 622 CE (Julian), thus
033 * Islamic years do not begin at the same time as Julian years. This chronology
034 * is not proleptic, as it does not allow dates before the first Islamic year.
035 * <p>
036 * There are two basic forms of the Islamic calendar, the tabular and the
037 * observed. The observed form cannot easily be used by computers as it
038 * relies on human observation of the new moon.
039 * The tabular calendar, implemented here, is an arithmetical approximation
040 * of the observed form that follows relatively simple rules.
041 * <p>
042 * The tabular form of the calendar defines 12 months of alternately
043 * 30 and 29 days. The last month is extended to 30 days in a leap year.
044 * Leap years occur according to a 30 year cycle. There are four recognised
045 * patterns of leap years in the 30 year cycle:
046 * <pre>
047 * Years 2, 5, 7, 10, 13, 15, 18, 21, 24, 26 & 29 - 15-based, used by Microsoft
048 * Years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26 & 29 - 16-based, most commonly used
049 * Years 2, 5, 8, 10, 13, 16, 19, 21, 24, 27 & 29 - Indian
050 * Years 2, 5, 8, 11, 13, 16, 19, 21, 24, 27 & 30 - Habash al-Hasib
051 * </pre>
052 * You can select which pattern to use via the factory methods, or use the
053 * default (16-based).
054 * <p>
055 * This implementation defines a day as midnight to midnight exactly as per
056 * the ISO chronology. This correct start of day is at sunset on the previous
057 * day, however this cannot readily be modelled and has been ignored.
058 * <p>
059 * IslamicChronology is thread-safe and immutable.
060 *
061 * @see <a href="http://en.wikipedia.org/wiki/Islamic_calendar">Wikipedia</a>
062 *
063 * @author Stephen Colebourne
064 * @since 1.2
065 */
066public final class IslamicChronology extends BasicChronology {
067
068    /** Serialization lock */
069    private static final long serialVersionUID = -3663823829888L;
070
071    /**
072     * Constant value for 'Anno Hegirae', equivalent
073     * to the value returned for AD/CE.
074     */
075    public static final int AH = DateTimeConstants.CE;
076
077    /** A singleton era field. */
078    private static final DateTimeField ERA_FIELD = new BasicSingleEraDateTimeField("AH");
079
080    /** Leap year 15-based pattern. */
081    public static final LeapYearPatternType LEAP_YEAR_15_BASED = new LeapYearPatternType(0, 623158436);
082    /** Leap year 16-based pattern. */
083    public static final LeapYearPatternType LEAP_YEAR_16_BASED = new LeapYearPatternType(1, 623191204);
084    /** Leap year Indian pattern. */
085    public static final LeapYearPatternType LEAP_YEAR_INDIAN = new LeapYearPatternType(2, 690562340);
086    /** Leap year Habash al-Hasib pattern. */
087    public static final LeapYearPatternType LEAP_YEAR_HABASH_AL_HASIB = new LeapYearPatternType(3, 153692453);
088
089    /** The lowest year that can be fully supported. */
090    private static final int MIN_YEAR = -292269337;
091
092    /**
093     * The highest year that can be fully supported.
094     * Although calculateFirstDayOfYearMillis can go higher without
095     * overflowing, the getYear method overflows when it adds the
096     * approximate millis at the epoch.
097     */
098    private static final int MAX_YEAR = 292271022;
099
100    /** The days in a pair of months. */
101    private static final int MONTH_PAIR_LENGTH = 59;
102
103    /** The length of the long month. */
104    private static final int LONG_MONTH_LENGTH = 30;
105
106    /** The length of the short month. */
107    private static final int SHORT_MONTH_LENGTH = 29;
108
109    /** The length of the long month in millis. */
110    private static final long MILLIS_PER_MONTH_PAIR = 59L * DateTimeConstants.MILLIS_PER_DAY;
111
112    /** The length of the long month in millis. */
113    private static final long MILLIS_PER_MONTH = (long) (29.53056 * DateTimeConstants.MILLIS_PER_DAY);
114
115    /** The length of the long month in millis. */
116    private static final long MILLIS_PER_LONG_MONTH = 30L * DateTimeConstants.MILLIS_PER_DAY;
117
118    /** The typical millis per year. */
119    private static final long MILLIS_PER_YEAR = (long) (354.36667 * DateTimeConstants.MILLIS_PER_DAY);
120
121    /** The typical millis per year. */
122    private static final long MILLIS_PER_SHORT_YEAR = 354L * DateTimeConstants.MILLIS_PER_DAY;
123
124    /** The typical millis per year. */
125    private static final long MILLIS_PER_LONG_YEAR = 355L * DateTimeConstants.MILLIS_PER_DAY;
126
127    /** The millis of 0001-01-01. */
128    private static final long MILLIS_YEAR_1 = -42521587200000L;
129                                    //        -42520809600000L;
130//    long start = 0L - 278L * DateTimeConstants.MILLIS_PER_DAY;
131//    long cy = 46L * MILLIS_PER_CYCLE;  // 1381-01-01
132//    long rem = 5L * MILLIS_PER_SHORT_YEAR +
133//            3L * MILLIS_PER_LONG_YEAR;  // 1389-01-01
134
135    /** The length of the cycle of leap years. */
136    private static final int CYCLE = 30;
137
138    /** The millis of a 30 year cycle. */
139    private static final long MILLIS_PER_CYCLE = ((19L * 354L + 11L * 355L) * DateTimeConstants.MILLIS_PER_DAY);
140
141    /** Cache of zone to chronology arrays */
142    private static final Map<DateTimeZone, IslamicChronology[]> cCache = new HashMap<DateTimeZone, IslamicChronology[]>();
143
144    /** Singleton instance of a UTC IslamicChronology */
145    private static final IslamicChronology INSTANCE_UTC;
146    static {
147        // init after static fields
148        INSTANCE_UTC = getInstance(DateTimeZone.UTC);
149    }
150
151    /** The leap years to use. */
152    private final LeapYearPatternType iLeapYears;
153
154    //-----------------------------------------------------------------------
155    /**
156     * Gets an instance of the IslamicChronology.
157     * The time zone of the returned instance is UTC.
158     * 
159     * @return a singleton UTC instance of the chronology
160     */
161    public static IslamicChronology getInstanceUTC() {
162        return INSTANCE_UTC;
163    }
164
165    /**
166     * Gets an instance of the IslamicChronology in the default time zone.
167     * 
168     * @return a chronology in the default time zone
169     */
170    public static IslamicChronology getInstance() {
171        return getInstance(DateTimeZone.getDefault(), LEAP_YEAR_16_BASED);
172    }
173
174    /**
175     * Gets an instance of the IslamicChronology in the given time zone.
176     * 
177     * @param zone  the time zone to get the chronology in, null is default
178     * @return a chronology in the specified time zone
179     */
180    public static IslamicChronology getInstance(DateTimeZone zone) {
181        return getInstance(zone, LEAP_YEAR_16_BASED);
182    }
183
184    /**
185     * Gets an instance of the IslamicChronology in the given time zone.
186     * 
187     * @param zone  the time zone to get the chronology in, null is default
188     * @param leapYears  the type defining the leap year pattern
189     * @return a chronology in the specified time zone
190     */
191    public static IslamicChronology getInstance(DateTimeZone zone, LeapYearPatternType leapYears) {
192        if (zone == null) {
193            zone = DateTimeZone.getDefault();
194        }
195        IslamicChronology chrono;
196        synchronized (cCache) {
197            IslamicChronology[] chronos = cCache.get(zone);
198            if (chronos == null) {
199                chronos = new IslamicChronology[4];
200                cCache.put(zone, chronos);
201            }
202            chrono = chronos[leapYears.index];
203            if (chrono == null) {
204                if (zone == DateTimeZone.UTC) {
205                    // First create without a lower limit.
206                    chrono = new IslamicChronology(null, null, leapYears);
207                    // Impose lower limit and make another IslamicChronology.
208                    DateTime lowerLimit = new DateTime(1, 1, 1, 0, 0, 0, 0, chrono);
209                    chrono = new IslamicChronology(
210                        LimitChronology.getInstance(chrono, lowerLimit, null),
211                         null, leapYears);
212                } else {
213                    chrono = getInstance(DateTimeZone.UTC, leapYears);
214                    chrono = new IslamicChronology
215                        (ZonedChronology.getInstance(chrono, zone), null, leapYears);
216                }
217                chronos[leapYears.index] = chrono;
218            }
219        }
220        return chrono;
221    }
222
223    // Constructors and instance variables
224    //-----------------------------------------------------------------------
225    /**
226     * Restricted constructor.
227     */
228    IslamicChronology(Chronology base, Object param, LeapYearPatternType leapYears) {
229        super(base, param, 4);
230        this.iLeapYears = leapYears;
231    }
232
233    /**
234     * Serialization singleton.
235     */
236    private Object readResolve() {
237        Chronology base = getBase();
238        return base == null ? getInstanceUTC() : getInstance(base.getZone());
239    }
240
241    //-----------------------------------------------------------------------
242    /**
243     * Gets the leap year pattern type.
244     *
245     * @return the pattern type
246     */
247    public LeapYearPatternType getLeapYearPatternType() {
248        return iLeapYears;
249    }
250
251    // Conversion
252    //-----------------------------------------------------------------------
253    /**
254     * Gets the Chronology in the UTC time zone.
255     * 
256     * @return the chronology in UTC
257     */
258    public Chronology withUTC() {
259        return INSTANCE_UTC;
260    }
261
262    /**
263     * Gets the Chronology in a specific time zone.
264     * 
265     * @param zone  the zone to get the chronology in, null is default
266     * @return the chronology
267     */
268    public Chronology withZone(DateTimeZone zone) {
269        if (zone == null) {
270            zone = DateTimeZone.getDefault();
271        }
272        if (zone == getZone()) {
273            return this;
274        }
275        return getInstance(zone);
276    }
277
278    /**
279     * A suitable hash code for the chronology.
280     * 
281     * @return the hash code
282     * @since 1.6
283     */
284    public int hashCode() {
285        return super.hashCode() * 13 + getLeapYearPatternType().hashCode();
286    }
287
288    //-----------------------------------------------------------------------
289    int getYear(long instant) {
290        long millisIslamic = instant - MILLIS_YEAR_1;
291        long cycles = millisIslamic / MILLIS_PER_CYCLE;
292        long cycleRemainder = millisIslamic % MILLIS_PER_CYCLE;
293        
294        int year = (int) ((cycles * CYCLE) + 1L);
295        long yearMillis = (isLeapYear(year) ? MILLIS_PER_LONG_YEAR : MILLIS_PER_SHORT_YEAR);
296        while (cycleRemainder >= yearMillis) {
297            cycleRemainder -= yearMillis;
298            yearMillis = (isLeapYear(++year) ? MILLIS_PER_LONG_YEAR : MILLIS_PER_SHORT_YEAR);
299        }
300        return year;
301    }
302
303    long setYear(long instant, int year) {
304        // optimsed implementation of set, due to fixed months
305        int thisYear = getYear(instant);
306        int dayOfYear = getDayOfYear(instant, thisYear);
307        int millisOfDay = getMillisOfDay(instant);
308
309        if (dayOfYear > 354) {
310            // Current year is leap, and day is leap.
311            if (!isLeapYear(year)) {
312                // Moving to a non-leap year, leap day doesn't exist.
313                dayOfYear--;
314            }
315        }
316
317        instant = getYearMonthDayMillis(year, 1, dayOfYear);
318        instant += millisOfDay;
319        return instant;
320    }
321
322    //-----------------------------------------------------------------------
323    long getYearDifference(long minuendInstant, long subtrahendInstant) {
324        // optimsed implementation of getDifference, due to fixed months
325        int minuendYear = getYear(minuendInstant);
326        int subtrahendYear = getYear(subtrahendInstant);
327
328        // Inlined remainder method to avoid duplicate calls to get.
329        long minuendRem = minuendInstant - getYearMillis(minuendYear);
330        long subtrahendRem = subtrahendInstant - getYearMillis(subtrahendYear);
331
332        int difference = minuendYear - subtrahendYear;
333        if (minuendRem < subtrahendRem) {
334            difference--;
335        }
336        return difference;
337    }
338
339    //-----------------------------------------------------------------------
340    long getTotalMillisByYearMonth(int year, int month) {
341        if (--month % 2 == 1) {
342            month /= 2;
343            return month * MILLIS_PER_MONTH_PAIR + MILLIS_PER_LONG_MONTH;
344        } else {
345            month /= 2;
346            return month * MILLIS_PER_MONTH_PAIR;
347        }
348    }
349
350    //-----------------------------------------------------------------------
351    int getDayOfMonth(long millis) {
352        // optimised for simple months
353        int doy = getDayOfYear(millis) - 1;
354        if (doy == 354) {
355            return 30;
356        }
357        return (doy % MONTH_PAIR_LENGTH) % LONG_MONTH_LENGTH + 1;
358    }
359
360    //-----------------------------------------------------------------------
361    boolean isLeapYear(int year) {
362        return iLeapYears.isLeapYear(year);
363    }
364
365    //-----------------------------------------------------------------------
366    int getDaysInYearMax() {
367        return 355;
368    }
369
370    //-----------------------------------------------------------------------
371    int getDaysInYear(int year) {
372        return isLeapYear(year) ? 355 : 354;
373    }
374
375    //-----------------------------------------------------------------------
376    int getDaysInYearMonth(int year, int month) {
377        if (month == 12 && isLeapYear(year)) {
378            return LONG_MONTH_LENGTH;
379        }
380        return (--month % 2 == 0 ? LONG_MONTH_LENGTH : SHORT_MONTH_LENGTH);
381    }
382
383    //-----------------------------------------------------------------------
384    int getDaysInMonthMax() {
385        return LONG_MONTH_LENGTH;
386    }
387
388    //-----------------------------------------------------------------------
389    int getDaysInMonthMax(int month) {
390        if (month == 12) {
391            return LONG_MONTH_LENGTH;
392        }
393        return (--month % 2 == 0 ? LONG_MONTH_LENGTH : SHORT_MONTH_LENGTH);
394    }
395
396    //-----------------------------------------------------------------------
397    int getMonthOfYear(long millis, int year) {
398        int doyZeroBased = (int) ((millis - getYearMillis(year)) / DateTimeConstants.MILLIS_PER_DAY);
399        if (doyZeroBased == 354) {
400            return 12;
401        }
402        return ((doyZeroBased * 2) / MONTH_PAIR_LENGTH) + 1;
403//        return (int) (doyZeroBased / 29.9f) + 1;
404//        
405//        int monthPairZeroBased = doyZeroBased / MONTH_PAIR_LENGTH;
406//        int monthPairRemainder = doyZeroBased % MONTH_PAIR_LENGTH;
407//        return (monthPairZeroBased * 2) + 1 + (monthPairRemainder >= LONG_MONTH_LENGTH ? 1 : 0);
408    }
409
410    //-----------------------------------------------------------------------
411    long getAverageMillisPerYear() {
412        return MILLIS_PER_YEAR;
413    }
414
415    //-----------------------------------------------------------------------
416    long getAverageMillisPerYearDividedByTwo() {
417        return MILLIS_PER_YEAR / 2;
418    }
419
420    //-----------------------------------------------------------------------
421    long getAverageMillisPerMonth() {
422        return MILLIS_PER_MONTH;
423    }
424
425    //-----------------------------------------------------------------------
426    long calculateFirstDayOfYearMillis(int year) {
427        if (year > MAX_YEAR) {
428            throw new ArithmeticException("Year is too large: " + year + " > " + MAX_YEAR);
429        }
430        if (year < MIN_YEAR) {
431            throw new ArithmeticException("Year is too small: " + year + " < " + MIN_YEAR);
432        }
433
434        // Java epoch is 1970-01-01 Gregorian which is 0622-07-16 Islamic.
435        // 0001-01-01 Islamic is -42520809600000L
436        // would prefer to calculate against year zero, but leap year
437        // can be in that year so it doesn't work
438        year--;
439        long cycle = year / CYCLE;
440        long millis = MILLIS_YEAR_1 + cycle * MILLIS_PER_CYCLE;
441        int cycleRemainder = (year % CYCLE) + 1;
442        
443        for (int i = 1; i < cycleRemainder; i++) {
444            millis += (isLeapYear(i) ? MILLIS_PER_LONG_YEAR : MILLIS_PER_SHORT_YEAR);
445        }
446        
447        return millis;
448    }
449
450    //-----------------------------------------------------------------------
451    int getMinYear() {
452        return 1; //MIN_YEAR;
453    }
454
455    //-----------------------------------------------------------------------
456    int getMaxYear() {
457        return MAX_YEAR;
458    }
459
460    //-----------------------------------------------------------------------
461    long getApproxMillisAtEpochDividedByTwo() {
462        // Epoch 1970-01-01 ISO = 1389-10-22 Islamic
463        return (-MILLIS_YEAR_1) / 2;
464    }
465
466    //-----------------------------------------------------------------------
467    protected void assemble(Fields fields) {
468        if (getBase() == null) {
469            super.assemble(fields);
470
471            fields.era = ERA_FIELD;
472            fields.monthOfYear = new BasicMonthOfYearDateTimeField(this, 12);
473            fields.months = fields.monthOfYear.getDurationField();
474        }
475    }
476
477    //-----------------------------------------------------------------------
478    /**
479     * Opaque object describing a leap year pattern for the Islamic Chronology.
480     *
481     * @since 1.2
482     */
483    public static class LeapYearPatternType implements Serializable {
484        /** Serialization lock */
485        private static final long serialVersionUID = 26581275372698L;
486//        /** Leap year raw data encoded into bits. */
487//        private static final int[][] LEAP_YEARS = {
488//            {2, 5, 7, 10, 13, 15, 18, 21, 24, 26, 29},  // 623158436
489//            {2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29},  // 623191204
490//            {2, 5, 8, 10, 13, 16, 19, 21, 24, 27, 29},  // 690562340
491//            {0, 2, 5, 8, 11, 13, 16, 19, 21, 24, 27},   // 153692453
492//        };
493        
494        /** The index. */
495        final byte index;
496        /** The leap year pattern, a bit-based 1=true pattern. */
497        final int pattern;
498        
499        /**
500         * Constructor.
501         * This constructor takes a bit pattern where bits 0-29 correspond
502         * to years 0-29 in the 30 year Islamic cycle of years. This allows
503         * a highly efficient lookup by bit-matching.
504         *
505         * @param index  the index
506         * @param pattern  the bit pattern
507         */
508        LeapYearPatternType(int index, int pattern) {
509            super();
510            this.index = (byte) index;
511            this.pattern = pattern;
512        }
513        
514        /**
515         * Is the year a leap year.
516         * @param year  the year to query
517         * @return true if leap
518         */
519        boolean isLeapYear(int year) {
520            int key = 1 << (year % 30);
521            return ((pattern & key) > 0);
522        }
523        
524        /**
525         * Ensure a singleton is returned if possible.
526         * @return the singleton instance
527         */
528        private Object readResolve() {
529            switch (index) {
530                case 0:
531                    return LEAP_YEAR_15_BASED;
532                case 1:
533                    return LEAP_YEAR_16_BASED;
534                case 2:
535                    return LEAP_YEAR_INDIAN;
536                case 3:
537                    return LEAP_YEAR_HABASH_AL_HASIB;
538                default:
539                    return this;
540            }
541        }
542    }
543}