KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > joda > time > chrono > EthiopicChronology


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 java.util.HashMap JavaDoc;
19 import java.util.Map JavaDoc;
20
21 import org.joda.time.Chronology;
22 import org.joda.time.DateTime;
23 import org.joda.time.DateTimeConstants;
24 import org.joda.time.DateTimeField;
25 import org.joda.time.DateTimeZone;
26 import org.joda.time.field.SkipDateTimeField;
27
28 /**
29  * Implements the Ethiopic calendar system, which defines every fourth year as
30  * leap, much like the Julian calendar. The year is broken down into 12 months,
31  * each 30 days in length. An extra period at the end of the year is either 5
32  * or 6 days in length. In this implementation, it is considered a 13th month.
33  * <p>
34  * Year 1 in the Ethiopic calendar began on August 29, 8 CE (Julian), thus
35  * Ethiopic years do not begin at the same time as Julian years. This chronology
36  * is not proleptic, as it does not allow dates before the first Ethiopic year.
37  * <p>
38  * This implementation defines a day as midnight to midnight exactly as per
39  * the ISO chronology. Some references indicate that a coptic day starts at
40  * sunset on the previous ISO day, but this has not been confirmed and is not
41  * implemented.
42  * <p>
43  * EthiopicChronology is thread-safe and immutable.
44  *
45  * @see <a HREF="http://en.wikipedia.org/wiki/Ethiopian_calendar">Wikipedia</a>
46  *
47  * @author Brian S O'Neill
48  * @author Stephen Colebourne
49  * @since 1.2
50  */

51 public final class EthiopicChronology extends BasicFixedMonthChronology {
52
53     /** Serialization lock */
54     private static final long serialVersionUID = -5972804258688333942L;
55
56     /**
57      * Constant value for 'Ethiopean Era', equivalent
58      * to the value returned for AD/CE.
59      */

60     public static final int EE = DateTimeConstants.CE;
61
62     /** A singleton era field. */
63     private static final DateTimeField ERA_FIELD = new BasicSingleEraDateTimeField("EE");
64
65     /** The lowest year that can be fully supported. */
66     private static final int MIN_YEAR = -292269337;
67
68     /** The highest year that can be fully supported. */
69     private static final int MAX_YEAR = 292272984;
70
71     /** Cache of zone to chronology arrays */
72     private static final Map JavaDoc cCache = new HashMap JavaDoc();
73
74     /** Singleton instance of a UTC EthiopicChronology */
75     private static final EthiopicChronology INSTANCE_UTC;
76     static {
77         // init after static fields
78
INSTANCE_UTC = getInstance(DateTimeZone.UTC);
79     }
80
81     //-----------------------------------------------------------------------
82
/**
83      * Gets an instance of the EthiopicChronology.
84      * The time zone of the returned instance is UTC.
85      *
86      * @return a singleton UTC instance of the chronology
87      */

88     public static EthiopicChronology getInstanceUTC() {
89         return INSTANCE_UTC;
90     }
91
92     /**
93      * Gets an instance of the EthiopicChronology in the default time zone.
94      *
95      * @return a chronology in the default time zone
96      */

97     public static EthiopicChronology getInstance() {
98         return getInstance(DateTimeZone.getDefault(), 4);
99     }
100
101     /**
102      * Gets an instance of the EthiopicChronology in the given time zone.
103      *
104      * @param zone the time zone to get the chronology in, null is default
105      * @return a chronology in the specified time zone
106      */

107     public static EthiopicChronology getInstance(DateTimeZone zone) {
108         return getInstance(zone, 4);
109     }
110
111     /**
112      * Gets an instance of the EthiopicChronology in the given time zone.
113      *
114      * @param zone the time zone to get the chronology in, null is default
115      * @param minDaysInFirstWeek minimum number of days in first week of the year; default is 4
116      * @return a chronology in the specified time zone
117      */

118     public static EthiopicChronology getInstance(DateTimeZone zone, int minDaysInFirstWeek) {
119         if (zone == null) {
120             zone = DateTimeZone.getDefault();
121         }
122         EthiopicChronology chrono;
123         synchronized (cCache) {
124             EthiopicChronology[] chronos = (EthiopicChronology[]) cCache.get(zone);
125             if (chronos == null) {
126                 chronos = new EthiopicChronology[7];
127                 cCache.put(zone, chronos);
128             }
129             try {
130                 chrono = chronos[minDaysInFirstWeek - 1];
131             } catch (ArrayIndexOutOfBoundsException JavaDoc e) {
132                 throw new IllegalArgumentException JavaDoc
133                     ("Invalid min days in first week: " + minDaysInFirstWeek);
134             }
135             if (chrono == null) {
136                 if (zone == DateTimeZone.UTC) {
137                     // First create without a lower limit.
138
chrono = new EthiopicChronology(null, null, minDaysInFirstWeek);
139                     // Impose lower limit and make another EthiopicChronology.
140
DateTime lowerLimit = new DateTime(1, 1, 1, 0, 0, 0, 0, chrono);
141                     chrono = new EthiopicChronology
142                         (LimitChronology.getInstance(chrono, lowerLimit, null),
143                          null, minDaysInFirstWeek);
144                 } else {
145                     chrono = getInstance(DateTimeZone.UTC, minDaysInFirstWeek);
146                     chrono = new EthiopicChronology
147                         (ZonedChronology.getInstance(chrono, zone), null, minDaysInFirstWeek);
148                 }
149                 chronos[minDaysInFirstWeek - 1] = chrono;
150             }
151         }
152         return chrono;
153     }
154
155     // Constructors and instance variables
156
//-----------------------------------------------------------------------
157
/**
158      * Restricted constructor.
159      */

160     EthiopicChronology(Chronology base, Object JavaDoc param, int minDaysInFirstWeek) {
161         super(base, param, minDaysInFirstWeek);
162     }
163
164     /**
165      * Serialization singleton.
166      */

167     private Object JavaDoc readResolve() {
168         Chronology base = getBase();
169         return base == null ?
170                 getInstance(DateTimeZone.UTC, getMinimumDaysInFirstWeek()) :
171                     getInstance(base.getZone(), getMinimumDaysInFirstWeek());
172     }
173
174     // Conversion
175
//-----------------------------------------------------------------------
176
/**
177      * Gets the Chronology in the UTC time zone.
178      *
179      * @return the chronology in UTC
180      */

181     public Chronology withUTC() {
182         return INSTANCE_UTC;
183     }
184
185     /**
186      * Gets the Chronology in a specific time zone.
187      *
188      * @param zone the zone to get the chronology in, null is default
189      * @return the chronology
190      */

191     public Chronology withZone(DateTimeZone zone) {
192         if (zone == null) {
193             zone = DateTimeZone.getDefault();
194         }
195         if (zone == getZone()) {
196             return this;
197         }
198         return getInstance(zone);
199     }
200
201     //-----------------------------------------------------------------------
202
long calculateFirstDayOfYearMillis(int year) {
203         // Java epoch is 1970-01-01 Gregorian which is 1962-04-23 Ethiopic.
204
// Calculate relative to the nearest leap year and account for the
205
// difference later.
206

207         int relativeYear = year - 1963;
208         int leapYears;
209         if (relativeYear <= 0) {
210             // Add 3 before shifting right since /4 and >>2 behave differently
211
// on negative numbers.
212
leapYears = (relativeYear + 3) >> 2;
213         } else {
214             leapYears = relativeYear >> 2;
215             // For post 1963 an adjustment is needed as jan1st is before leap day
216
if (!isLeapYear(year)) {
217                 leapYears++;
218             }
219         }
220         
221         long millis = (relativeYear * 365L + leapYears)
222             * (long)DateTimeConstants.MILLIS_PER_DAY;
223
224         // Adjust to account for difference between 1963-01-01 and 1962-04-23.
225

226         return millis + (365L - 112) * DateTimeConstants.MILLIS_PER_DAY;
227     }
228
229     //-----------------------------------------------------------------------
230
int getMinYear() {
231         return MIN_YEAR;
232     }
233
234     //-----------------------------------------------------------------------
235
int getMaxYear() {
236         return MAX_YEAR;
237     }
238
239     //-----------------------------------------------------------------------
240
long getApproxMillisAtEpochDividedByTwo() {
241         return (1962L * MILLIS_PER_YEAR + 112L * DateTimeConstants.MILLIS_PER_DAY) / 2;
242     }
243
244     //-----------------------------------------------------------------------
245
protected void assemble(Fields fields) {
246         if (getBase() == null) {
247             super.assemble(fields);
248
249             // Ethiopic, like Julian, has no year zero.
250
fields.year = new SkipDateTimeField(this, fields.year);
251             fields.weekyear = new SkipDateTimeField(this, fields.weekyear);
252             
253             fields.era = ERA_FIELD;
254             fields.monthOfYear = new BasicMonthOfYearDateTimeField(this, 13);
255             fields.months = fields.monthOfYear.getDurationField();
256         }
257     }
258
259 }
260
Popular Tags