1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.joda.time.chrono;
17
18 import java.util.HashMap;
19 import java.util.Map;
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public final class CopticChronology extends BasicFixedMonthChronology {
52
53
54 private static final long serialVersionUID = -5972804258688333942L;
55
56
57
58
59
60 public static final int AM = DateTimeConstants.CE;
61
62
63 private static final DateTimeField ERA_FIELD = new BasicSingleEraDateTimeField("AM");
64
65
66 private static final int MIN_YEAR = -292269337;
67
68
69 private static final int MAX_YEAR = 292272708;
70
71
72 private static final Map<DateTimeZone, CopticChronology[]> cCache = new HashMap<DateTimeZone, CopticChronology[]>();
73
74
75 private static final CopticChronology INSTANCE_UTC;
76 static {
77
78 INSTANCE_UTC = getInstance(DateTimeZone.UTC);
79 }
80
81
82
83
84
85
86
87
88 public static CopticChronology getInstanceUTC() {
89 return INSTANCE_UTC;
90 }
91
92
93
94
95
96
97 public static CopticChronology getInstance() {
98 return getInstance(DateTimeZone.getDefault(), 4);
99 }
100
101
102
103
104
105
106
107 public static CopticChronology getInstance(DateTimeZone zone) {
108 return getInstance(zone, 4);
109 }
110
111
112
113
114
115
116
117
118 public static CopticChronology getInstance(DateTimeZone zone, int minDaysInFirstWeek) {
119 if (zone == null) {
120 zone = DateTimeZone.getDefault();
121 }
122 CopticChronology chrono;
123 synchronized (cCache) {
124 CopticChronology[] chronos = cCache.get(zone);
125 if (chronos == null) {
126 chronos = new CopticChronology[7];
127 cCache.put(zone, chronos);
128 }
129 try {
130 chrono = chronos[minDaysInFirstWeek - 1];
131 } catch (ArrayIndexOutOfBoundsException e) {
132 throw new IllegalArgumentException
133 ("Invalid min days in first week: " + minDaysInFirstWeek);
134 }
135 if (chrono == null) {
136 if (zone == DateTimeZone.UTC) {
137
138 chrono = new CopticChronology(null, null, minDaysInFirstWeek);
139
140 DateTime lowerLimit = new DateTime(1, 1, 1, 0, 0, 0, 0, chrono);
141 chrono = new CopticChronology
142 (LimitChronology.getInstance(chrono, lowerLimit, null),
143 null, minDaysInFirstWeek);
144 } else {
145 chrono = getInstance(DateTimeZone.UTC, minDaysInFirstWeek);
146 chrono = new CopticChronology
147 (ZonedChronology.getInstance(chrono, zone), null, minDaysInFirstWeek);
148 }
149 chronos[minDaysInFirstWeek - 1] = chrono;
150 }
151 }
152 return chrono;
153 }
154
155
156
157
158
159
160 CopticChronology(Chronology base, Object param, int minDaysInFirstWeek) {
161 super(base, param, minDaysInFirstWeek);
162 }
163
164
165
166
167 private Object readResolve() {
168 Chronology base = getBase();
169 int minDays = getMinimumDaysInFirstWeek();
170 minDays = (minDays == 0 ? 4 : minDays);
171 return base == null ?
172 getInstance(DateTimeZone.UTC, minDays) :
173 getInstance(base.getZone(), minDays);
174 }
175
176
177
178
179
180
181
182
183 public Chronology withUTC() {
184 return INSTANCE_UTC;
185 }
186
187
188
189
190
191
192
193 public Chronology withZone(DateTimeZone zone) {
194 if (zone == null) {
195 zone = DateTimeZone.getDefault();
196 }
197 if (zone == getZone()) {
198 return this;
199 }
200 return getInstance(zone);
201 }
202
203
204 long calculateFirstDayOfYearMillis(int year) {
205
206
207
208
209 int relativeYear = year - 1687;
210 int leapYears;
211 if (relativeYear <= 0) {
212
213
214 leapYears = (relativeYear + 3) >> 2;
215 } else {
216 leapYears = relativeYear >> 2;
217
218 if (!isLeapYear(year)) {
219 leapYears++;
220 }
221 }
222
223 long millis = (relativeYear * 365L + leapYears)
224 * (long)DateTimeConstants.MILLIS_PER_DAY;
225
226
227
228 return millis + (365L - 112) * DateTimeConstants.MILLIS_PER_DAY;
229 }
230
231
232 int getMinYear() {
233 return MIN_YEAR;
234 }
235
236
237 int getMaxYear() {
238 return MAX_YEAR;
239 }
240
241
242 long getApproxMillisAtEpochDividedByTwo() {
243 return (1686L * MILLIS_PER_YEAR + 112L * DateTimeConstants.MILLIS_PER_DAY) / 2;
244 }
245
246
247 protected void assemble(Fields fields) {
248 if (getBase() == null) {
249 super.assemble(fields);
250
251
252 fields.year = new SkipDateTimeField(this, fields.year);
253 fields.weekyear = new SkipDateTimeField(this, fields.weekyear);
254
255 fields.era = ERA_FIELD;
256 fields.monthOfYear = new BasicMonthOfYearDateTimeField(this, 13);
257 fields.months = fields.monthOfYear.getDurationField();
258 }
259 }
260
261 }