001    /*
002     *  Copyright 2001-2005 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.gj;
017    
018    /**
019     * A reference Gregorian chronology implementation, intended for testing
020     * purposes only. Correctness is favored over performance. The key functions
021     * for date calculations are based on ones provided in "Calendrical
022     * Calculations", ISBN 0-521-77752-6.
023     *
024     * @author Brian S O'Neill
025     */
026    public final class TestGregorianChronology extends TestGJChronology {
027        /**
028         * Constructs with an epoch of 1970-01-01.
029         */
030        public TestGregorianChronology() {
031            super(1970, 1, 1);
032        }
033    
034        public TestGregorianChronology(int epochYear, int epochMonth, int epochDay) {
035            super(epochYear, epochMonth, epochDay);
036        }
037    
038        public String toString() {
039            return "TestGregorianChronology";
040        }
041    
042        long millisPerYear() {
043            return (long)(365.2425 * MILLIS_PER_DAY);
044        }
045    
046        long millisPerMonth() {
047            return (long)(365.2425 * MILLIS_PER_DAY / 12);
048        }
049    
050        boolean isLeapYear(int year) {
051            if (mod(year, 4) == 0) {
052                int t = (int)mod(year, 400);
053                if (t != 100 && t != 200 && t != 300) {
054                    return true;
055                }
056            }
057            return false;
058        }
059    
060        /**
061         * @return days from 0001-01-01
062         */
063        long fixedFromGJ(int year, int monthOfYear, int dayOfMonth) {
064            long year_m1 = year - 1;
065            long f = 365 * year_m1 + div(year_m1, 4) - div(year_m1, 100)
066                + div(year_m1, 400) + div(367 * monthOfYear - 362, 12) + dayOfMonth;
067            if (monthOfYear > 2) {
068                f += isLeapYear(year) ? -1 : -2;
069            }
070            return f;
071        }
072    
073        /**
074         * @param date days from 0001-01-01
075         * @return gj year
076         */
077        int gjYearFromFixed(long date) {
078            long d0 = date - 1;
079            long n400 = div(d0, 146097);
080            long d1 = mod(d0, 146097);
081            long n100 = div(d1, 36524);
082            long d2 = mod(d1, 36524);
083            long n4 = div(d2, 1461);
084            long d3 = mod(d2, 1461);
085            long n1 = div(d3, 365);
086            long year = 400 * n400 + 100 * n100 + 4 * n4 + n1;
087            if (!(n100 == 4 || n1 == 4)) {
088                year += 1;
089            }
090    
091            int year_i = (int)year;
092            if (year_i == year) {
093                return year_i;
094            } else {
095                throw new RuntimeException("year cannot be cast to an int: " + year);
096            }
097        }
098    
099        /**
100         * @param date days from 0001-01-01
101         * @return gj year, monthOfYear, dayOfMonth
102         */
103        int[] gjFromFixed(long date) {
104            int year = gjYearFromFixed(date);
105            long priorDays = date - fixedFromGJ(year, 1, 1);
106            long correction;
107            if (date < fixedFromGJ(year, 3, 1)) {
108                correction = 0;
109            } else if (isLeapYear(year)) {
110                correction = 1;
111            } else {
112                correction = 2;
113            }
114            int monthOfYear = (int)div(12 * (priorDays + correction) + 373, 367);
115            int day = (int)(date - fixedFromGJ(year, monthOfYear, 1) + 1);
116    
117            return new int[]{year, monthOfYear, day};
118        }
119    
120        long fixedFromISO(int weekyear, int weekOfWeekyear, int dayOfWeek) {
121            return nthWeekday(weekOfWeekyear, 0, weekyear - 1, 12, 28) + dayOfWeek;
122        }
123    
124        /**
125         * @param date days from 0001-01-01
126         * @return iso weekyear, weekOfWeekyear, dayOfWeek (1=Monday to 7)
127         */
128        int[] isoFromFixed(long date) {
129            int weekyear = gjYearFromFixed(date - 3);
130            if (date >= fixedFromISO(weekyear + 1, 1, 1)) {
131                weekyear += 1;
132            }
133            int weekOfWeekyear = (int)(div(date - fixedFromISO(weekyear, 1, 1), 7) + 1);
134            int dayOfWeek = (int)amod(date, 7);
135            return new int[]{weekyear, weekOfWeekyear, dayOfWeek};
136        }
137    }