]>
Commit | Line | Data |
---|---|---|
374ca955 | 1 | /* |
46f4442e | 2 | ****************************************************************************** |
4388f060 | 3 | * Copyright (C) 2003-2011, International Business Machines Corporation |
46f4442e A |
4 | * and others. All Rights Reserved. |
5 | ****************************************************************************** | |
6 | * | |
7 | * File ISLAMCAL.H | |
8 | * | |
9 | * Modification History: | |
10 | * | |
11 | * Date Name Description | |
12 | * 10/14/2003 srl ported from java IslamicCalendar | |
13 | ***************************************************************************** | |
14 | */ | |
374ca955 A |
15 | |
16 | #include "islamcal.h" | |
17 | ||
18 | #if !UCONFIG_NO_FORMATTING | |
19 | ||
46f4442e | 20 | #include "umutex.h" |
374ca955 A |
21 | #include <float.h> |
22 | #include "gregoimp.h" // Math | |
23 | #include "astro.h" // CalendarAstronomer | |
24 | #include "uhash.h" | |
25 | #include "ucln_in.h" | |
26 | ||
27 | static const UDate HIJRA_MILLIS = -42521587200000.0; // 7/16/622 AD 00:00 | |
28 | ||
29 | // Debugging | |
30 | #ifdef U_DEBUG_ISLAMCAL | |
31 | # include <stdio.h> | |
32 | # include <stdarg.h> | |
33 | static void debug_islamcal_loc(const char *f, int32_t l) | |
34 | { | |
46f4442e | 35 | fprintf(stderr, "%s:%d: ", f, l); |
374ca955 A |
36 | } |
37 | ||
38 | static void debug_islamcal_msg(const char *pat, ...) | |
39 | { | |
46f4442e A |
40 | va_list ap; |
41 | va_start(ap, pat); | |
42 | vfprintf(stderr, pat, ap); | |
43 | fflush(stderr); | |
374ca955 A |
44 | } |
45 | // must use double parens, i.e.: U_DEBUG_ISLAMCAL_MSG(("four is: %d",4)); | |
46 | #define U_DEBUG_ISLAMCAL_MSG(x) {debug_islamcal_loc(__FILE__,__LINE__);debug_islamcal_msg x;} | |
47 | #else | |
48 | #define U_DEBUG_ISLAMCAL_MSG(x) | |
49 | #endif | |
50 | ||
51 | ||
52 | // --- The cache -- | |
53 | // cache of months | |
54 | static UMTX astroLock = 0; // pod bay door lock | |
4388f060 A |
55 | static icu::CalendarCache *gMonthCache = NULL; |
56 | static icu::CalendarAstronomer *gIslamicCalendarAstro = NULL; | |
374ca955 A |
57 | |
58 | U_CDECL_BEGIN | |
59 | static UBool calendar_islamic_cleanup(void) { | |
60 | if (gMonthCache) { | |
61 | delete gMonthCache; | |
62 | gMonthCache = NULL; | |
63 | } | |
64 | if (gIslamicCalendarAstro) { | |
65 | delete gIslamicCalendarAstro; | |
66 | gIslamicCalendarAstro = NULL; | |
67 | } | |
68 | umtx_destroy(&astroLock); | |
69 | return TRUE; | |
70 | } | |
71 | U_CDECL_END | |
72 | ||
73 | U_NAMESPACE_BEGIN | |
74 | ||
75 | // Implementation of the IslamicCalendar class | |
76 | ||
77 | //------------------------------------------------------------------------- | |
78 | // Constructors... | |
79 | //------------------------------------------------------------------------- | |
80 | ||
81 | const char *IslamicCalendar::getType() const { | |
46f4442e A |
82 | if(civil==CIVIL) { |
83 | return "islamic-civil"; | |
84 | } else { | |
85 | return "islamic"; | |
86 | } | |
374ca955 A |
87 | } |
88 | ||
89 | Calendar* IslamicCalendar::clone() const { | |
46f4442e | 90 | return new IslamicCalendar(*this); |
374ca955 A |
91 | } |
92 | ||
93 | IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success, ECivil beCivil) | |
46f4442e A |
94 | : Calendar(TimeZone::createDefault(), aLocale, success), |
95 | civil(beCivil) | |
374ca955 | 96 | { |
46f4442e | 97 | setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly. |
374ca955 A |
98 | } |
99 | ||
100 | IslamicCalendar::IslamicCalendar(const IslamicCalendar& other) : Calendar(other), civil(other.civil) { | |
101 | } | |
102 | ||
103 | IslamicCalendar::~IslamicCalendar() | |
104 | { | |
105 | } | |
106 | ||
107 | /** | |
46f4442e A |
108 | * Determines whether this object uses the fixed-cycle Islamic civil calendar |
109 | * or an approximation of the religious, astronomical calendar. | |
110 | * | |
111 | * @param beCivil <code>true</code> to use the civil calendar, | |
112 | * <code>false</code> to use the astronomical calendar. | |
113 | * @draft ICU 2.4 | |
114 | */ | |
374ca955 A |
115 | void IslamicCalendar::setCivil(ECivil beCivil, UErrorCode &status) |
116 | { | |
46f4442e A |
117 | if (civil != beCivil) { |
118 | // The fields of the calendar will become invalid, because the calendar | |
119 | // rules are different | |
120 | UDate m = getTimeInMillis(status); | |
121 | civil = beCivil; | |
122 | clear(); | |
123 | setTimeInMillis(m, status); | |
124 | } | |
374ca955 | 125 | } |
46f4442e | 126 | |
374ca955 | 127 | /** |
46f4442e A |
128 | * Returns <code>true</code> if this object is using the fixed-cycle civil |
129 | * calendar, or <code>false</code> if using the religious, astronomical | |
130 | * calendar. | |
131 | * @draft ICU 2.4 | |
132 | */ | |
374ca955 | 133 | UBool IslamicCalendar::isCivil() { |
46f4442e | 134 | return (civil == CIVIL); |
374ca955 | 135 | } |
46f4442e | 136 | |
374ca955 A |
137 | //------------------------------------------------------------------------- |
138 | // Minimum / Maximum access functions | |
139 | //------------------------------------------------------------------------- | |
140 | ||
46f4442e A |
141 | // Note: Current IslamicCalendar implementation does not work |
142 | // well with negative years. | |
143 | ||
4388f060 A |
144 | // TODO: In some cases the current ICU Islamic calendar implementation shows |
145 | // a month as having 31 days. Since date parsing now uses range checks based | |
146 | // on the table below, we need to change the range for last day of month to | |
147 | // include 31 as a workaround until the implementation is fixed. | |
374ca955 | 148 | static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = { |
46f4442e A |
149 | // Minimum Greatest Least Maximum |
150 | // Minimum Maximum | |
151 | { 0, 0, 0, 0}, // ERA | |
152 | { 1, 1, 5000000, 5000000}, // YEAR | |
153 | { 0, 0, 11, 11}, // MONTH | |
154 | { 1, 1, 50, 51}, // WEEK_OF_YEAR | |
155 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH | |
4388f060 | 156 | { 1, 1, 29, 31}, // DAY_OF_MONTH - 31 to workaround for cal implementation bug, should be 30 |
46f4442e A |
157 | { 1, 1, 354, 355}, // DAY_OF_YEAR |
158 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK | |
159 | { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH | |
160 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM | |
161 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR | |
162 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY | |
163 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE | |
164 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND | |
165 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND | |
166 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET | |
167 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET | |
168 | { 1, 1, 5000000, 5000000}, // YEAR_WOY | |
169 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL | |
170 | { 1, 1, 5000000, 5000000}, // EXTENDED_YEAR | |
171 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY | |
172 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY | |
173 | {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH | |
374ca955 A |
174 | }; |
175 | ||
176 | /** | |
46f4442e A |
177 | * @draft ICU 2.4 |
178 | */ | |
374ca955 | 179 | int32_t IslamicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const { |
46f4442e | 180 | return LIMITS[field][limitType]; |
374ca955 A |
181 | } |
182 | ||
183 | //------------------------------------------------------------------------- | |
184 | // Assorted calculation utilities | |
185 | // | |
186 | ||
187 | /** | |
46f4442e A |
188 | * Determine whether a year is a leap year in the Islamic civil calendar |
189 | */ | |
374ca955 A |
190 | UBool IslamicCalendar::civilLeapYear(int32_t year) |
191 | { | |
46f4442e | 192 | return (14 + 11 * year) % 30 < 11; |
374ca955 | 193 | } |
46f4442e | 194 | |
374ca955 | 195 | /** |
46f4442e A |
196 | * Return the day # on which the given year starts. Days are counted |
197 | * from the Hijri epoch, origin 0. | |
198 | */ | |
374ca955 | 199 | int32_t IslamicCalendar::yearStart(int32_t year) { |
46f4442e | 200 | if (civil == CIVIL) { |
729e4ab9 | 201 | return (year-1)*354 + ClockMath::floorDivide((3+11*year),30); |
46f4442e A |
202 | } else { |
203 | return trueMonthStart(12*(year-1)); | |
204 | } | |
374ca955 | 205 | } |
46f4442e | 206 | |
374ca955 | 207 | /** |
46f4442e A |
208 | * Return the day # on which the given month starts. Days are counted |
209 | * from the Hijri epoch, origin 0. | |
210 | * | |
211 | * @param year The hijri year | |
212 | * @param year The hijri month, 0-based | |
213 | */ | |
374ca955 | 214 | int32_t IslamicCalendar::monthStart(int32_t year, int32_t month) const { |
46f4442e A |
215 | if (civil == CIVIL) { |
216 | return (int32_t)uprv_ceil(29.5*month) | |
729e4ab9 | 217 | + (year-1)*354 + (int32_t)ClockMath::floorDivide((3+11*year),30); |
46f4442e A |
218 | } else { |
219 | return trueMonthStart(12*(year-1) + month); | |
220 | } | |
374ca955 | 221 | } |
46f4442e | 222 | |
374ca955 | 223 | /** |
46f4442e A |
224 | * Find the day number on which a particular month of the true/lunar |
225 | * Islamic calendar starts. | |
226 | * | |
227 | * @param month The month in question, origin 0 from the Hijri epoch | |
228 | * | |
229 | * @return The day number on which the given month starts. | |
230 | */ | |
374ca955 A |
231 | int32_t IslamicCalendar::trueMonthStart(int32_t month) const |
232 | { | |
46f4442e A |
233 | UErrorCode status = U_ZERO_ERROR; |
234 | int32_t start = CalendarCache::get(&gMonthCache, month, status); | |
235 | ||
236 | if (start==0) { | |
237 | // Make a guess at when the month started, using the average length | |
238 | UDate origin = HIJRA_MILLIS | |
729e4ab9 | 239 | + uprv_floor(month * CalendarAstronomer::SYNODIC_MONTH) * kOneDay; |
46f4442e A |
240 | |
241 | // moonAge will fail due to memory allocation error | |
242 | double age = moonAge(origin, status); | |
243 | if (U_FAILURE(status)) { | |
244 | goto trueMonthStartEnd; | |
245 | } | |
246 | ||
247 | if (age >= 0) { | |
248 | // The month has already started | |
249 | do { | |
250 | origin -= kOneDay; | |
251 | age = moonAge(origin, status); | |
252 | if (U_FAILURE(status)) { | |
253 | goto trueMonthStartEnd; | |
254 | } | |
255 | } while (age >= 0); | |
256 | } | |
257 | else { | |
258 | // Preceding month has not ended yet. | |
259 | do { | |
260 | origin += kOneDay; | |
261 | age = moonAge(origin, status); | |
262 | if (U_FAILURE(status)) { | |
263 | goto trueMonthStartEnd; | |
264 | } | |
265 | } while (age < 0); | |
266 | } | |
729e4ab9 | 267 | start = (int32_t)ClockMath::floorDivide((origin - HIJRA_MILLIS), (double)kOneDay) + 1; |
46f4442e | 268 | CalendarCache::put(&gMonthCache, month, start, status); |
374ca955 | 269 | } |
46f4442e A |
270 | trueMonthStartEnd : |
271 | if(U_FAILURE(status)) { | |
272 | start = 0; | |
374ca955 | 273 | } |
46f4442e | 274 | return start; |
374ca955 A |
275 | } |
276 | ||
277 | /** | |
46f4442e A |
278 | * Return the "age" of the moon at the given time; this is the difference |
279 | * in ecliptic latitude between the moon and the sun. This method simply | |
280 | * calls CalendarAstronomer.moonAge, converts to degrees, | |
281 | * and adjusts the result to be in the range [-180, 180]. | |
282 | * | |
283 | * @param time The time at which the moon's age is desired, | |
284 | * in millis since 1/1/1970. | |
285 | */ | |
286 | double IslamicCalendar::moonAge(UDate time, UErrorCode &status) | |
374ca955 | 287 | { |
46f4442e A |
288 | double age = 0; |
289 | ||
290 | umtx_lock(&astroLock); | |
291 | if(gIslamicCalendarAstro == NULL) { | |
292 | gIslamicCalendarAstro = new CalendarAstronomer(); | |
293 | if (gIslamicCalendarAstro == NULL) { | |
294 | status = U_MEMORY_ALLOCATION_ERROR; | |
295 | return age; | |
296 | } | |
297 | ucln_i18n_registerCleanup(UCLN_I18N_ISLAMIC_CALENDAR, calendar_islamic_cleanup); | |
298 | } | |
299 | gIslamicCalendarAstro->setTime(time); | |
300 | age = gIslamicCalendarAstro->getMoonAge(); | |
301 | umtx_unlock(&astroLock); | |
302 | ||
303 | // Convert to degrees and normalize... | |
304 | age = age * 180 / CalendarAstronomer::PI; | |
305 | if (age > 180) { | |
306 | age = age - 360; | |
307 | } | |
308 | ||
309 | return age; | |
374ca955 A |
310 | } |
311 | ||
312 | //---------------------------------------------------------------------- | |
313 | // Calendar framework | |
314 | //---------------------------------------------------------------------- | |
315 | ||
316 | /** | |
46f4442e A |
317 | * Return the length (in days) of the given month. |
318 | * | |
319 | * @param year The hijri year | |
320 | * @param year The hijri month, 0-based | |
321 | * @draft ICU 2.4 | |
322 | */ | |
374ca955 A |
323 | int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const { |
324 | ||
46f4442e A |
325 | int32_t length = 0; |
326 | ||
327 | if (civil == CIVIL) { | |
328 | length = 29 + (month+1) % 2; | |
329 | if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) { | |
330 | length++; | |
331 | } | |
332 | } else { | |
333 | month = 12*(extendedYear-1) + month; | |
334 | length = trueMonthStart(month+1) - trueMonthStart(month) ; | |
374ca955 | 335 | } |
46f4442e | 336 | return length; |
374ca955 A |
337 | } |
338 | ||
339 | /** | |
46f4442e A |
340 | * Return the number of days in the given Islamic year |
341 | * @draft ICU 2.4 | |
342 | */ | |
374ca955 | 343 | int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear) const { |
46f4442e A |
344 | if (civil == CIVIL) { |
345 | return 354 + (civilLeapYear(extendedYear) ? 1 : 0); | |
346 | } else { | |
347 | int32_t month = 12*(extendedYear-1); | |
348 | return (trueMonthStart(month + 12) - trueMonthStart(month)); | |
349 | } | |
374ca955 | 350 | } |
46f4442e | 351 | |
374ca955 A |
352 | //------------------------------------------------------------------------- |
353 | // Functions for converting from field values to milliseconds.... | |
354 | //------------------------------------------------------------------------- | |
355 | ||
356 | // Return JD of start of given month/year | |
357 | /** | |
46f4442e A |
358 | * @draft ICU 2.4 |
359 | */ | |
374ca955 | 360 | int32_t IslamicCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool /* useMonth */) const { |
46f4442e | 361 | return monthStart(eyear, month) + 1948439; |
374ca955 A |
362 | } |
363 | ||
364 | //------------------------------------------------------------------------- | |
365 | // Functions for converting from milliseconds to field values | |
366 | //------------------------------------------------------------------------- | |
367 | ||
46f4442e A |
368 | /** |
369 | * @draft ICU 2.4 | |
370 | */ | |
374ca955 A |
371 | int32_t IslamicCalendar::handleGetExtendedYear() { |
372 | int32_t year; | |
373 | if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) { | |
374 | year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1 | |
375 | } else { | |
376 | year = internalGet(UCAL_YEAR, 1); // Default to year 1 | |
377 | } | |
378 | return year; | |
379 | } | |
380 | ||
381 | /** | |
46f4442e A |
382 | * Override Calendar to compute several fields specific to the Islamic |
383 | * calendar system. These are: | |
384 | * | |
385 | * <ul><li>ERA | |
386 | * <li>YEAR | |
387 | * <li>MONTH | |
388 | * <li>DAY_OF_MONTH | |
389 | * <li>DAY_OF_YEAR | |
390 | * <li>EXTENDED_YEAR</ul> | |
391 | * | |
392 | * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this | |
393 | * method is called. The getGregorianXxx() methods return Gregorian | |
394 | * calendar equivalents for the given Julian day. | |
395 | * @draft ICU 2.4 | |
396 | */ | |
397 | void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) { | |
374ca955 A |
398 | int32_t year, month, dayOfMonth, dayOfYear; |
399 | UDate startDate; | |
400 | int32_t days = julianDay - 1948440; | |
46f4442e | 401 | |
374ca955 A |
402 | if (civil == CIVIL) { |
403 | // Use the civil calendar approximation, which is just arithmetic | |
729e4ab9 | 404 | year = (int)ClockMath::floorDivide( (double)(30 * days + 10646) , 10631.0 ); |
374ca955 A |
405 | month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 ); |
406 | month = month<11?month:11; | |
407 | startDate = monthStart(year, month); | |
408 | } else { | |
409 | // Guess at the number of elapsed full months since the epoch | |
410 | int32_t months = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH); | |
411 | ||
729e4ab9 | 412 | startDate = uprv_floor(months * CalendarAstronomer::SYNODIC_MONTH); |
374ca955 | 413 | |
46f4442e A |
414 | double age = moonAge(internalGetTime(), status); |
415 | if (U_FAILURE(status)) { | |
416 | status = U_MEMORY_ALLOCATION_ERROR; | |
417 | return; | |
418 | } | |
729e4ab9 | 419 | if ( days - startDate >= 25 && age > 0) { |
374ca955 A |
420 | // If we're near the end of the month, assume next month and search backwards |
421 | months++; | |
422 | } | |
423 | ||
424 | // Find out the last time that the new moon was actually visible at this longitude | |
425 | // This returns midnight the night that the moon was visible at sunset. | |
426 | while ((startDate = trueMonthStart(months)) > days) { | |
427 | // If it was after the date in question, back up a month and try again | |
428 | months--; | |
429 | } | |
46f4442e | 430 | |
374ca955 A |
431 | year = months / 12 + 1; |
432 | month = months % 12; | |
433 | } | |
46f4442e | 434 | |
374ca955 A |
435 | dayOfMonth = (days - monthStart(year, month)) + 1; |
436 | ||
437 | // Now figure out the day of the year. | |
438 | dayOfYear = (days - monthStart(year, 0) + 1); | |
439 | ||
440 | internalSet(UCAL_ERA, 0); | |
441 | internalSet(UCAL_YEAR, year); | |
442 | internalSet(UCAL_EXTENDED_YEAR, year); | |
443 | internalSet(UCAL_MONTH, month); | |
444 | internalSet(UCAL_DAY_OF_MONTH, dayOfMonth); | |
445 | internalSet(UCAL_DAY_OF_YEAR, dayOfYear); | |
446 | } | |
447 | ||
448 | UBool | |
449 | IslamicCalendar::inDaylightTime(UErrorCode& status) const | |
450 | { | |
46f4442e A |
451 | // copied from GregorianCalendar |
452 | if (U_FAILURE(status) || (&(getTimeZone()) == NULL && !getTimeZone().useDaylightTime())) | |
453 | return FALSE; | |
374ca955 A |
454 | |
455 | // Force an update of the state of the Calendar. | |
46f4442e | 456 | ((IslamicCalendar*)this)->complete(status); // cast away const |
374ca955 | 457 | |
46f4442e | 458 | return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE); |
374ca955 A |
459 | } |
460 | ||
461 | // default century | |
462 | const UDate IslamicCalendar::fgSystemDefaultCentury = DBL_MIN; | |
463 | const int32_t IslamicCalendar::fgSystemDefaultCenturyYear = -1; | |
464 | ||
465 | UDate IslamicCalendar::fgSystemDefaultCenturyStart = DBL_MIN; | |
466 | int32_t IslamicCalendar::fgSystemDefaultCenturyStartYear = -1; | |
467 | ||
468 | ||
469 | UBool IslamicCalendar::haveDefaultCentury() const | |
470 | { | |
46f4442e | 471 | return TRUE; |
374ca955 A |
472 | } |
473 | ||
474 | UDate IslamicCalendar::defaultCenturyStart() const | |
475 | { | |
46f4442e | 476 | return internalGetDefaultCenturyStart(); |
374ca955 A |
477 | } |
478 | ||
479 | int32_t IslamicCalendar::defaultCenturyStartYear() const | |
480 | { | |
46f4442e | 481 | return internalGetDefaultCenturyStartYear(); |
374ca955 A |
482 | } |
483 | ||
484 | UDate | |
485 | IslamicCalendar::internalGetDefaultCenturyStart() const | |
486 | { | |
46f4442e A |
487 | // lazy-evaluate systemDefaultCenturyStart |
488 | UBool needsUpdate; | |
489 | UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); | |
490 | ||
491 | if (needsUpdate) { | |
492 | initializeSystemDefaultCentury(); | |
493 | } | |
494 | ||
495 | // use defaultCenturyStart unless it's the flag value; | |
496 | // then use systemDefaultCenturyStart | |
497 | ||
498 | return fgSystemDefaultCenturyStart; | |
374ca955 A |
499 | } |
500 | ||
501 | int32_t | |
502 | IslamicCalendar::internalGetDefaultCenturyStartYear() const | |
503 | { | |
46f4442e A |
504 | // lazy-evaluate systemDefaultCenturyStartYear |
505 | UBool needsUpdate; | |
506 | UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); | |
507 | ||
508 | if (needsUpdate) { | |
509 | initializeSystemDefaultCentury(); | |
510 | } | |
511 | ||
512 | // use defaultCenturyStart unless it's the flag value; | |
513 | // then use systemDefaultCenturyStartYear | |
514 | ||
515 | return fgSystemDefaultCenturyStartYear; | |
374ca955 A |
516 | } |
517 | ||
518 | void | |
519 | IslamicCalendar::initializeSystemDefaultCentury() | |
520 | { | |
46f4442e A |
521 | // initialize systemDefaultCentury and systemDefaultCenturyYear based |
522 | // on the current time. They'll be set to 80 years before | |
523 | // the current time. | |
729e4ab9 A |
524 | UErrorCode status = U_ZERO_ERROR; |
525 | IslamicCalendar calendar(Locale("@calendar=islamic-civil"),status); | |
526 | if (U_SUCCESS(status)) | |
374ca955 | 527 | { |
729e4ab9 A |
528 | calendar.setTime(Calendar::getNow(), status); |
529 | calendar.add(UCAL_YEAR, -80, status); | |
530 | UDate newStart = calendar.getTime(status); | |
531 | int32_t newYear = calendar.get(UCAL_YEAR, status); | |
532 | umtx_lock(NULL); | |
533 | if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) | |
46f4442e | 534 | { |
729e4ab9 A |
535 | fgSystemDefaultCenturyStartYear = newYear; |
536 | fgSystemDefaultCenturyStart = newStart; | |
46f4442e | 537 | } |
729e4ab9 | 538 | umtx_unlock(NULL); |
374ca955 | 539 | } |
729e4ab9 A |
540 | // We have no recourse upon failure unless we want to propagate the failure |
541 | // out. | |
374ca955 A |
542 | } |
543 | ||
544 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar) | |
545 | ||
546 | U_NAMESPACE_END | |
547 | ||
548 | #endif | |
549 |