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     */
016    package org.joda.time.chrono;
017    
018    import java.io.Serializable;
019    import java.util.HashMap;
020    import java.util.Map;
021    
022    import org.joda.time.Chronology;
023    import org.joda.time.DateTime;
024    import org.joda.time.DateTimeConstants;
025    import org.joda.time.DateTimeField;
026    import 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     */
066    public 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    }