View Javadoc

1   /*
2    *  Copyright 2001-2005 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.time.chrono;
17  
18  import org.joda.time.Chronology;
19  import org.joda.time.DateTimeConstants;
20  
21  /**
22   * Abstract Chronology for implementing chronologies based on Gregorian/Julian formulae.
23   * Most of the utility methods required by subclasses are package-private,
24   * reflecting the intention that they be defined in the same package.
25   * <p>
26   * BasicGJChronology is thread-safe and immutable, and all subclasses must
27   * be as well.
28   *
29   * @author Stephen Colebourne
30   * @author Brian S O'Neill
31   * @author Guy Allard
32   * @since 1.2, refactored from CommonGJChronology
33   */
34  abstract class BasicGJChronology extends BasicChronology {
35  
36      /** Serialization lock */
37      private static final long serialVersionUID = 538276888268L;
38  
39      // These arrays are NOT public. We trust ourselves not to alter the array.
40      // They use zero-based array indexes so the that valid range of months is
41      // automatically checked.
42      private static final int[] MIN_DAYS_PER_MONTH_ARRAY = {
43          31,28,31,30,31,30,31,31,30,31,30,31
44      };
45      private static final int[] MAX_DAYS_PER_MONTH_ARRAY = {
46          31,29,31,30,31,30,31,31,30,31,30,31
47      };
48      private static final long[] MIN_TOTAL_MILLIS_BY_MONTH_ARRAY;
49      private static final long[] MAX_TOTAL_MILLIS_BY_MONTH_ARRAY;
50      private static final long FEB_29 = (31L + 29 - 1) * DateTimeConstants.MILLIS_PER_DAY;
51  
52      static {
53          MIN_TOTAL_MILLIS_BY_MONTH_ARRAY = new long[12];
54          MAX_TOTAL_MILLIS_BY_MONTH_ARRAY = new long[12];
55  
56          long minSum = 0;
57          long maxSum = 0;
58          for (int i = 0; i < 11; i++) {
59              long millis = MIN_DAYS_PER_MONTH_ARRAY[i]
60                  * (long)DateTimeConstants.MILLIS_PER_DAY;
61              minSum += millis;
62              MIN_TOTAL_MILLIS_BY_MONTH_ARRAY[i + 1] = minSum;
63  
64              millis = MAX_DAYS_PER_MONTH_ARRAY[i]
65                  * (long)DateTimeConstants.MILLIS_PER_DAY;
66              maxSum += millis;
67              MAX_TOTAL_MILLIS_BY_MONTH_ARRAY[i + 1] = maxSum;
68          }
69      }
70  
71      /**
72       * Constructor.
73       */
74      BasicGJChronology(Chronology base, Object param, int minDaysInFirstWeek) {
75          super(base, param, minDaysInFirstWeek);
76      }
77  
78      //-----------------------------------------------------------------------
79      int getMonthOfYear(long millis, int year) {
80          // Perform a binary search to get the month. To make it go even faster,
81          // compare using ints instead of longs. The number of milliseconds per
82          // year exceeds the limit of a 32-bit int's capacity, so divide by
83          // 1024. No precision is lost (except time of day) since the number of
84          // milliseconds per day contains 1024 as a factor. After the division,
85          // the instant isn't measured in milliseconds, but in units of
86          // (128/125)seconds.
87  
88          int i = (int)((millis - getYearMillis(year)) >> 10);
89  
90          // There are 86400000 milliseconds per day, but divided by 1024 is
91          // 84375. There are 84375 (128/125)seconds per day.
92  
93          return
94              (isLeapYear(year))
95              ? ((i < 182 * 84375)
96                 ? ((i < 91 * 84375)
97                    ? ((i < 31 * 84375) ? 1 : (i < 60 * 84375) ? 2 : 3)
98                    : ((i < 121 * 84375) ? 4 : (i < 152 * 84375) ? 5 : 6))
99                 : ((i < 274 * 84375)
100                   ? ((i < 213 * 84375) ? 7 : (i < 244 * 84375) ? 8 : 9)
101                   : ((i < 305 * 84375) ? 10 : (i < 335 * 84375) ? 11 : 12)))
102             : ((i < 181 * 84375)
103                ? ((i < 90 * 84375)
104                   ? ((i < 31 * 84375) ? 1 : (i < 59 * 84375) ? 2 : 3)
105                   : ((i < 120 * 84375) ? 4 : (i < 151 * 84375) ? 5 : 6))
106                : ((i < 273 * 84375)
107                   ? ((i < 212 * 84375) ? 7 : (i < 243 * 84375) ? 8 : 9)
108                   : ((i < 304 * 84375) ? 10 : (i < 334 * 84375) ? 11 : 12)));
109     }
110 
111     //-----------------------------------------------------------------------
112     /**
113      * Gets the number of days in the specified month and year.
114      * 
115      * @param year  the year
116      * @param month  the month
117      * @return the number of days
118      */
119     int getDaysInYearMonth(int year, int month) {
120         if (isLeapYear(year)) {
121             return MAX_DAYS_PER_MONTH_ARRAY[month - 1];
122         } else {
123             return MIN_DAYS_PER_MONTH_ARRAY[month - 1];
124         }
125     }
126 
127     //-----------------------------------------------------------------------
128     int getDaysInMonthMax(int month) {
129         return MAX_DAYS_PER_MONTH_ARRAY[month - 1];
130     }
131 
132     //-----------------------------------------------------------------------
133     int getDaysInMonthMaxForSet(long instant, int value) {
134         return ((value > 28 || value < 1) ? getDaysInMonthMax(instant) : 28);
135     }
136 
137     //-----------------------------------------------------------------------
138     long getTotalMillisByYearMonth(int year, int month) {
139         if (isLeapYear(year)) {
140             return MAX_TOTAL_MILLIS_BY_MONTH_ARRAY[month - 1];
141         } else {
142             return MIN_TOTAL_MILLIS_BY_MONTH_ARRAY[month - 1];
143         }
144     }
145 
146     //-----------------------------------------------------------------------
147     long getYearDifference(long minuendInstant, long subtrahendInstant) {
148         int minuendYear = getYear(minuendInstant);
149         int subtrahendYear = getYear(subtrahendInstant);
150     
151         // Inlined remainder method to avoid duplicate calls to get.
152         long minuendRem = minuendInstant - getYearMillis(minuendYear);
153         long subtrahendRem = subtrahendInstant - getYearMillis(subtrahendYear);
154     
155         // Balance leap year differences on remainders.
156         if (subtrahendRem >= FEB_29) {
157             if (isLeapYear(subtrahendYear)) {
158                 if (!isLeapYear(minuendYear)) {
159                     subtrahendRem -= DateTimeConstants.MILLIS_PER_DAY;
160                 }
161             } else if (minuendRem >= FEB_29 && isLeapYear(minuendYear)) {
162                 minuendRem -= DateTimeConstants.MILLIS_PER_DAY;
163             }
164         }
165     
166         int difference = minuendYear - subtrahendYear;
167         if (minuendRem < subtrahendRem) {
168             difference--;
169         }
170         return difference;
171     }
172 
173     //-----------------------------------------------------------------------
174     long setYear(long instant, int year) {
175         int thisYear = getYear(instant);
176         int dayOfYear = getDayOfYear(instant, thisYear);
177         int millisOfDay = getMillisOfDay(instant);
178 
179         if (dayOfYear > (31 + 28)) { // after Feb 28
180             if (isLeapYear(thisYear)) {
181                 // Current date is Feb 29 or later.
182                 if (!isLeapYear(year)) {
183                     // Moving to a non-leap year, Feb 29 does not exist.
184                     dayOfYear--;
185                 }
186             } else {
187                 // Current date is Mar 01 or later.
188                 if (isLeapYear(year)) {
189                     // Moving to a leap year, account for Feb 29.
190                     dayOfYear++;
191                 }
192             }
193         }
194 
195         instant = getYearMonthDayMillis(year, 1, dayOfYear);
196         instant += millisOfDay;
197 
198         return instant;
199     }
200 
201 }