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 }