]>
git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/gregoimp.cpp
2 **********************************************************************
3 * Copyright (c) 2003-2008, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
7 * Created: September 2 2003
9 **********************************************************************
14 #if !UCONFIG_NO_FORMATTING
16 #include "unicode/ucal.h"
21 #if defined(U_DEBUG_CALDATA)
27 int32_t ClockMath::floorDivide(int32_t numerator
, int32_t denominator
) {
28 return (numerator
>= 0) ?
29 numerator
/ denominator
: ((numerator
+ 1) / denominator
) - 1;
32 int32_t ClockMath::floorDivide(double numerator
, int32_t denominator
,
35 quotient
= uprv_floor(numerator
/ denominator
);
36 remainder
= (int32_t) (numerator
- (quotient
* denominator
));
37 return (int32_t) quotient
;
40 double ClockMath::floorDivide(double dividend
, double divisor
,
42 // Only designed to work for positive divisors
43 U_ASSERT(divisor
> 0);
44 double quotient
= floorDivide(dividend
, divisor
);
45 remainder
= dividend
- (quotient
* divisor
);
46 // N.B. For certain large dividends, on certain platforms, there
47 // is a bug such that the quotient is off by one. If you doubt
48 // this to be true, set a breakpoint below and run cintltst.
49 if (remainder
< 0 || remainder
>= divisor
) {
50 // E.g. 6.7317038241449352e+022 / 86400000.0 is wrong on my
51 // machine (too high by one). 4.1792057231752762e+024 /
52 // 86400000.0 is wrong the other way (too low).
54 quotient
+= (remainder
< 0) ? -1 : +1;
56 // For quotients > ~2^53, we won't be able to add or
57 // subtract one, since the LSB of the mantissa will be >
58 // 2^0; that is, the exponent (base 2) will be larger than
59 // the length, in bits, of the mantissa. In that case, we
60 // can't give a correct answer, so we set the remainder to
61 // zero. This has the desired effect of making extreme
62 // values give back an approximate answer rather than
63 // crashing. For example, UDate values above a ~10^25
64 // might all have a time of midnight.
67 remainder
= dividend
- (quotient
* divisor
);
70 U_ASSERT(0 <= remainder
&& remainder
< divisor
);
74 const int32_t JULIAN_1_CE
= 1721426; // January 1, 1 CE Gregorian
75 const int32_t JULIAN_1970_CE
= 2440588; // January 1, 1970 CE Gregorian
77 const int16_t Grego::DAYS_BEFORE
[24] =
78 {0,31,59,90,120,151,181,212,243,273,304,334,
79 0,31,60,91,121,152,182,213,244,274,305,335};
81 const int8_t Grego::MONTH_LENGTH
[24] =
82 {31,28,31,30,31,30,31,31,30,31,30,31,
83 31,29,31,30,31,30,31,31,30,31,30,31};
85 double Grego::fieldsToDay(int32_t year
, int32_t month
, int32_t dom
) {
89 double julian
= 365 * y
+ ClockMath::floorDivide(y
, 4) + (JULIAN_1_CE
- 3) + // Julian cal
90 ClockMath::floorDivide(y
, 400) - ClockMath::floorDivide(y
, 100) + 2 + // => Gregorian cal
91 DAYS_BEFORE
[month
+ (isLeapYear(year
) ? 12 : 0)] + dom
; // => month/dom
93 return julian
- JULIAN_1970_CE
; // JD => epoch day
96 void Grego::dayToFields(double day
, int32_t& year
, int32_t& month
,
97 int32_t& dom
, int32_t& dow
, int32_t& doy
) {
99 // Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
100 day
+= JULIAN_1970_CE
- JULIAN_1_CE
;
102 // Convert from the day number to the multiple radix
103 // representation. We use 400-year, 100-year, and 4-year cycles.
104 // For example, the 4-year cycle has 4 years + 1 leap day; giving
105 // 1461 == 365*4 + 1 days.
106 int32_t n400
= ClockMath::floorDivide(day
, 146097, doy
); // 400-year cycle length
107 int32_t n100
= ClockMath::floorDivide(doy
, 36524, doy
); // 100-year cycle length
108 int32_t n4
= ClockMath::floorDivide(doy
, 1461, doy
); // 4-year cycle length
109 int32_t n1
= ClockMath::floorDivide(doy
, 365, doy
);
110 year
= 400*n400
+ 100*n100
+ 4*n4
+ n1
;
111 if (n100
== 4 || n1
== 4) {
112 doy
= 365; // Dec 31 at end of 4- or 400-year cycle
117 UBool isLeap
= isLeapYear(year
);
119 // Gregorian day zero is a Monday.
120 dow
= (int32_t) uprv_fmod(day
+ 1, 7);
121 dow
+= (dow
< 0) ? (UCAL_SUNDAY
+ 7) : UCAL_SUNDAY
;
123 // Common Julian/Gregorian calculation
124 int32_t correction
= 0;
125 int32_t march1
= isLeap
? 60 : 59; // zero-based DOY for March 1
127 correction
= isLeap
? 1 : 2;
129 month
= (12 * (doy
+ correction
) + 6) / 367; // zero-based month
130 dom
= doy
- DAYS_BEFORE
[month
+ (isLeap
? 12 : 0)] + 1; // one-based DOM
131 doy
++; // one-based doy
134 void Grego::timeToFields(UDate time
, int32_t& year
, int32_t& month
,
135 int32_t& dom
, int32_t& dow
, int32_t& doy
, int32_t& mid
) {
137 double day
= ClockMath::floorDivide((double)time
, (double)U_MILLIS_PER_DAY
, millisInDay
);
138 mid
= (int32_t)millisInDay
;
139 dayToFields(day
, year
, month
, dom
, dow
, doy
);
142 int32_t Grego::dayOfWeek(double day
) {
144 ClockMath::floorDivide(day
+ UCAL_THURSDAY
, 7, dow
);
145 return (dow
== 0) ? UCAL_SATURDAY
: dow
;
148 int32_t Grego::dayOfWeekInMonth(int32_t year
, int32_t month
, int32_t dom
) {
149 int32_t weekInMonth
= (dom
+ 6)/7;
150 if (weekInMonth
== 4) {
151 if (dom
+ 7 > monthLength(year
, month
)) {
154 } else if (weekInMonth
== 5) {
160 /* ---- CalendarData ------ */
162 #define U_CALENDAR_KEY "calendar"
163 #define U_GREGORIAN_KEY "gregorian"
164 #define U_FORMAT_KEY "format"
165 #define U_DEFAULT_KEY "default"
166 #define U_CALENDAR_DATA ((char*)0)
169 // CalendarData::CalendarData(const Locale& loc, UErrorCode& status)
170 // : fFillin(NULL), fBundle(NULL), fFallback(NULL) {
171 // initData(loc.getBaseName(), (char*) "???", status);
174 CalendarData::CalendarData(const Locale
& loc
, const char *type
, UErrorCode
& status
)
175 : fFillin(NULL
), fOtherFillin(NULL
), fBundle(NULL
), fFallback(NULL
) {
176 initData(loc
.getBaseName(), type
, status
);
179 void CalendarData::initData(const char *locale
, const char *type
, UErrorCode
& status
) {
180 fOtherFillin
= ures_open(U_CALENDAR_DATA
, locale
, &status
);
181 fFillin
= ures_getByKey(fOtherFillin
, U_CALENDAR_KEY
, fFillin
, &status
);
185 (uprv_strcmp(type
, U_GREGORIAN_KEY
)))
187 fBundle
= ures_getByKeyWithFallback(fFillin
, type
, NULL
, &status
);
188 fFallback
= ures_getByKeyWithFallback(fFillin
, U_GREGORIAN_KEY
, NULL
, &status
);
190 #if defined (U_DEBUG_CALDATA)
191 fprintf(stderr
, "%p: CalendarData(%s, %s, %s) -> main(%p, %s)=%s, fallback(%p, %s)=%s\n",
192 this, locale
, type
, u_errorName(status
), fBundle
, type
, fBundle
?ures_getLocale(fBundle
, &status
):"",
193 fFallback
, U_GREGORIAN_KEY
, fFallback
?ures_getLocale(fFallback
, &status
):"");
197 fBundle
= ures_getByKeyWithFallback(fFillin
, U_GREGORIAN_KEY
, NULL
, &status
);
198 #if defined (U_DEBUG_CALDATA)
199 fprintf(stderr
, "%p: CalendarData(%s, %s, %s) -> main(%p, %s)=%s, fallback = NULL\n",
200 this, locale
, type
, u_errorName(status
), fBundle
, U_GREGORIAN_KEY
, fBundle
?ures_getLocale(fBundle
, &status
):"" );
205 CalendarData::~CalendarData() {
208 ures_close(fFallback
);
209 ures_close(fOtherFillin
);
213 CalendarData::getByKey(const char *key
, UErrorCode
& status
) {
214 if(U_FAILURE(status
)) {
219 fFillin
= ures_getByKeyWithFallback(fBundle
, key
, fFillin
, &status
);
220 #if defined (U_DEBUG_CALDATA)
221 fprintf(stderr
, "%p: get %s -> %s - from MAIN %s\n",this, key
, u_errorName(status
), ures_getLocale(fFillin
, &status
));
224 if(fFallback
&& (status
== U_MISSING_RESOURCE_ERROR
)) {
225 status
= U_ZERO_ERROR
; // retry with fallback (gregorian)
226 fFillin
= ures_getByKeyWithFallback(fFallback
, key
, fFillin
, &status
);
227 #if defined (U_DEBUG_CALDATA)
228 fprintf(stderr
, "%p: get %s -> %s - from FALLBACK %s\n",this, key
, u_errorName(status
), ures_getLocale(fFillin
, &status
));
234 UResourceBundle
* CalendarData::getByKey2(const char *key
, const char *subKey
, UErrorCode
& status
) {
235 if(U_FAILURE(status
)) {
240 #if defined (U_DEBUG_CALDATA)
241 fprintf(stderr
, "%p: //\n");
243 fFillin
= ures_getByKeyWithFallback(fBundle
, key
, fFillin
, &status
);
244 fOtherFillin
= ures_getByKeyWithFallback(fFillin
, U_FORMAT_KEY
, fOtherFillin
, &status
);
245 fFillin
= ures_getByKeyWithFallback(fOtherFillin
, subKey
, fFillin
, &status
);
246 #if defined (U_DEBUG_CALDATA)
247 fprintf(stderr
, "%p: get %s/format/%s -> %s - from MAIN %s\n", this, key
, subKey
, u_errorName(status
), ures_getLocale(fFillin
, &status
));
250 if(fFallback
&& (status
== U_MISSING_RESOURCE_ERROR
)) {
251 status
= U_ZERO_ERROR
; // retry with fallback (gregorian)
252 fFillin
= ures_getByKeyWithFallback(fFallback
, key
, fFillin
, &status
);
253 fOtherFillin
= ures_getByKeyWithFallback(fFillin
, U_FORMAT_KEY
, fOtherFillin
, &status
);
254 fFillin
= ures_getByKeyWithFallback(fOtherFillin
, subKey
, fFillin
, &status
);
255 #if defined (U_DEBUG_CALDATA)
256 fprintf(stderr
, "%p: get %s/format/%s -> %s - from FALLBACK %s\n",this, key
, subKey
, u_errorName(status
), ures_getLocale(fFillin
,&status
));
260 //// handling of 'default' keyword on failure: Commented out for 3.0.
261 // if((status == U_MISSING_RESOURCE_ERROR) &&
262 // uprv_strcmp(subKey,U_DEFAULT_KEY)) { // avoid recursion
263 // #if defined (U_DEBUG_CALDATA)
264 // fprintf(stderr, "%p: - attempting fallback -\n", this);
267 // UErrorCode subStatus = U_ZERO_ERROR;
269 // char kwBuf[128] = "";
271 // /* fFillin = */ getByKey2(key, U_DEFAULT_KEY, subStatus);
272 // kw = ures_getString(fFillin, &len, &subStatus);
273 // if(len>126) { // too big
276 // if(U_SUCCESS(subStatus) && (len>0)) {
277 // u_UCharsToChars(kw, kwBuf, len+1);
278 // if(*kwBuf && uprv_strcmp(kwBuf,subKey)) {
279 // #if defined (U_DEBUG_CALDATA)
280 // fprintf(stderr, "%p: trying %s/format/default -> \"%s\"\n",this, key, kwBuf);
282 // // now try again with the default
283 // status = U_ZERO_ERROR;
284 // /* fFillin = */ getByKey2(key, kwBuf, status);
286 // #if defined (U_DEBUG_CALDATA)
288 // fprintf(stderr, "%p: could not load %s/format/default - fail out (%s)\n",this, key, kwBuf, u_errorName(status));
296 UResourceBundle
* CalendarData::getByKey3(const char *key
, const char *contextKey
, const char *subKey
, UErrorCode
& status
) {
297 if(U_FAILURE(status
)) {
302 #if defined (U_DEBUG_CALDATA)
303 fprintf(stderr
, "%p: //\n");
305 fFillin
= ures_getByKeyWithFallback(fBundle
, key
, fFillin
, &status
);
306 fOtherFillin
= ures_getByKeyWithFallback(fFillin
, contextKey
, fOtherFillin
, &status
);
307 fFillin
= ures_getByKeyWithFallback(fOtherFillin
, subKey
, fFillin
, &status
);
308 #if defined (U_DEBUG_CALDATA)
309 fprintf(stderr
, "%p: get %s/%s/%s -> %s - from MAIN %s\n", this, key
, contextKey
, subKey
, u_errorName(status
), ures_getLocale(fFillin
, &status
));
312 if(fFallback
&& (status
== U_MISSING_RESOURCE_ERROR
)) {
313 status
= U_ZERO_ERROR
; // retry with fallback (gregorian)
314 fFillin
= ures_getByKeyWithFallback(fFallback
, key
, fFillin
, &status
);
315 fOtherFillin
= ures_getByKeyWithFallback(fFillin
, contextKey
, fOtherFillin
, &status
);
316 fFillin
= ures_getByKeyWithFallback(fOtherFillin
, subKey
, fFillin
, &status
);
317 #if defined (U_DEBUG_CALDATA)
318 fprintf(stderr
, "%p: get %s/%s/%s -> %s - from FALLBACK %s\n",this, key
, contextKey
, subKey
, u_errorName(status
), ures_getLocale(fFillin
,&status
));