]>
git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/gregoimp.cpp
2 **********************************************************************
3 * Copyright (c) 2003-2004, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
7 * Created: September 2 2003
9 **********************************************************************
13 #if !UCONFIG_NO_FORMATTING
15 #include "unicode/ucal.h"
20 int32_t Math::floorDivide(int32_t numerator
, int32_t denominator
) {
21 return (numerator
>= 0) ?
22 numerator
/ denominator
: ((numerator
+ 1) / denominator
) - 1;
25 int32_t Math::floorDivide(double numerator
, int32_t denominator
,
28 quotient
= uprv_floor(numerator
/ denominator
);
29 remainder
= (int32_t) (numerator
- (quotient
* denominator
));
30 return (int32_t) quotient
;
33 double Math::floorDivide(double dividend
, double divisor
,
35 // Only designed to work for positive divisors
36 U_ASSERT(divisor
> 0);
37 double quotient
= floorDivide(dividend
, divisor
);
38 remainder
= dividend
- (quotient
* divisor
);
39 // N.B. For certain large dividends, on certain platforms, there
40 // is a bug such that the quotient is off by one. If you doubt
41 // this to be true, set a breakpoint below and run cintltst.
42 if (remainder
< 0 || remainder
>= divisor
) {
43 // E.g. 6.7317038241449352e+022 / 86400000.0 is wrong on my
44 // machine (too high by one). 4.1792057231752762e+024 /
45 // 86400000.0 is wrong the other way (too low).
47 quotient
+= (remainder
< 0) ? -1 : +1;
49 // For quotients > ~2^53, we won't be able to add or
50 // subtract one, since the LSB of the mantissa will be >
51 // 2^0; that is, the exponent (base 2) will be larger than
52 // the length, in bits, of the mantissa. In that case, we
53 // can't give a correct answer, so we set the remainder to
54 // zero. This has the desired effect of making extreme
55 // values give back an approximate answer rather than
56 // crashing. For example, UDate values above a ~10^25
57 // might all have a time of midnight.
60 remainder
= dividend
- (quotient
* divisor
);
63 U_ASSERT(0 <= remainder
&& remainder
< divisor
);
67 const int32_t JULIAN_1_CE
= 1721426; // January 1, 1 CE Gregorian
68 const int32_t JULIAN_1970_CE
= 2440588; // January 1, 1970 CE Gregorian
70 const int16_t Grego::DAYS_BEFORE
[24] =
71 {0,31,59,90,120,151,181,212,243,273,304,334,
72 0,31,60,91,121,152,182,213,244,274,305,335};
74 const int8_t Grego::MONTH_LENGTH
[24] =
75 {31,28,31,30,31,30,31,31,30,31,30,31,
76 31,29,31,30,31,30,31,31,30,31,30,31};
78 double Grego::fieldsToDay(int32_t year
, int32_t month
, int32_t dom
) {
82 double julian
= 365 * y
+ Math::floorDivide(y
, 4) + (JULIAN_1_CE
- 3) + // Julian cal
83 Math::floorDivide(y
, 400) - Math::floorDivide(y
, 100) + 2 + // => Gregorian cal
84 DAYS_BEFORE
[month
+ (isLeapYear(year
) ? 12 : 0)] + dom
; // => month/dom
86 return julian
- JULIAN_1970_CE
; // JD => epoch day
89 void Grego::dayToFields(double day
, int32_t& year
, int32_t& month
,
90 int32_t& dom
, int32_t& dow
, int32_t& doy
) {
92 // Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
93 day
+= JULIAN_1970_CE
- JULIAN_1_CE
;
95 // Convert from the day number to the multiple radix
96 // representation. We use 400-year, 100-year, and 4-year cycles.
97 // For example, the 4-year cycle has 4 years + 1 leap day; giving
98 // 1461 == 365*4 + 1 days.
99 int32_t n400
= Math::floorDivide(day
, 146097, doy
); // 400-year cycle length
100 int32_t n100
= Math::floorDivide(doy
, 36524, doy
); // 100-year cycle length
101 int32_t n4
= Math::floorDivide(doy
, 1461, doy
); // 4-year cycle length
102 int32_t n1
= Math::floorDivide(doy
, 365, doy
);
103 year
= 400*n400
+ 100*n100
+ 4*n4
+ n1
;
104 if (n100
== 4 || n1
== 4) {
105 doy
= 365; // Dec 31 at end of 4- or 400-year cycle
110 UBool isLeap
= isLeapYear(year
);
112 // Gregorian day zero is a Monday.
113 dow
= (int32_t) uprv_fmod(day
+ 1, 7);
114 dow
+= (dow
< 0) ? (UCAL_SUNDAY
+ 7) : UCAL_SUNDAY
;
116 // Common Julian/Gregorian calculation
117 int32_t correction
= 0;
118 int32_t march1
= isLeap
? 60 : 59; // zero-based DOY for March 1
120 correction
= isLeap
? 1 : 2;
122 month
= (12 * (doy
+ correction
) + 6) / 367; // zero-based month
123 dom
= doy
- DAYS_BEFORE
[month
+ (isLeap
? 12 : 0)] + 1; // one-based DOM
124 doy
++; // one-based doy
127 /* ---- CalendarData ------ */
129 #define U_CALENDAR_KEY "calendar"
130 #define U_GREGORIAN_KEY "gregorian"
131 #define U_FORMAT_KEY "format"
132 #define U_DEFAULT_KEY "default"
133 #define U_CALENDAR_DATA ((char*)0)
136 #if defined( U_DEBUG_CALDATA)
140 // CalendarData::CalendarData(const Locale& loc, UErrorCode& status)
141 // : fFillin(NULL), fBundle(NULL), fFallback(NULL) {
142 // initData(loc.getBaseName(), (char*) "???", status);
145 CalendarData::CalendarData(const Locale
& loc
, const char *type
, UErrorCode
& status
)
146 : fFillin(NULL
), fOtherFillin(NULL
), fBundle(NULL
), fFallback(NULL
) {
147 initData(loc
.getBaseName(), type
, status
);
150 void CalendarData::initData(const char *locale
, const char *type
, UErrorCode
& status
) {
151 fOtherFillin
= ures_open(U_CALENDAR_DATA
, locale
, &status
);
152 fFillin
= ures_getByKey(fOtherFillin
, U_CALENDAR_KEY
, fFillin
, &status
);
156 (uprv_strcmp(type
, U_GREGORIAN_KEY
)))
158 fBundle
= ures_getByKeyWithFallback(fFillin
, type
, NULL
, &status
);
159 fFallback
= ures_getByKeyWithFallback(fFillin
, U_GREGORIAN_KEY
, NULL
, &status
);
161 #if defined (U_DEBUG_CALDATA)
162 fprintf(stderr
, "%p: CalendarData(%s, %s, %s) -> main(%p, %s)=%s, fallback(%p, %s)=%s\n",
163 this, locale
, type
, u_errorName(status
), fBundle
, type
, fBundle
?ures_getLocale(fBundle
, &status
):"",
164 fFallback
, U_GREGORIAN_KEY
, fFallback
?ures_getLocale(fFallback
, &status
):"");
168 fBundle
= ures_getByKeyWithFallback(fFillin
, U_GREGORIAN_KEY
, NULL
, &status
);
169 #if defined (U_DEBUG_CALDATA)
170 fprintf(stderr
, "%p: CalendarData(%s, %s, %s) -> main(%p, %s)=%s, fallback = NULL\n",
171 this, locale
, type
, u_errorName(status
), fBundle
, U_GREGORIAN_KEY
, fBundle
?ures_getLocale(fBundle
, &status
):"" );
176 CalendarData::~CalendarData() {
179 ures_close(fFallback
);
180 ures_close(fOtherFillin
);
184 CalendarData::getByKey(const char *key
, UErrorCode
& status
) {
185 if(U_FAILURE(status
)) {
190 fFillin
= ures_getByKeyWithFallback(fBundle
, key
, fFillin
, &status
);
191 #if defined (U_DEBUG_CALDATA)
192 fprintf(stderr
, "%p: get %s -> %s - from MAIN %s\n",this, key
, u_errorName(status
), ures_getLocale(fFillin
, &status
));
195 if(fFallback
&& (status
== U_MISSING_RESOURCE_ERROR
)) {
196 status
= U_ZERO_ERROR
; // retry with fallback (gregorian)
197 fFillin
= ures_getByKeyWithFallback(fFallback
, key
, fFillin
, &status
);
198 #if defined (U_DEBUG_CALDATA)
199 fprintf(stderr
, "%p: get %s -> %s - from FALLBACK %s\n",this, key
, u_errorName(status
), ures_getLocale(fFillin
, &status
));
205 UResourceBundle
* CalendarData::getByKey2(const char *key
, const char *subKey
, UErrorCode
& status
) {
206 if(U_FAILURE(status
)) {
211 #if defined (U_DEBUG_CALDATA)
212 fprintf(stderr
, "%p: //\n");
214 fFillin
= ures_getByKeyWithFallback(fBundle
, key
, fFillin
, &status
);
215 fOtherFillin
= ures_getByKeyWithFallback(fFillin
, U_FORMAT_KEY
, fOtherFillin
, &status
);
216 fFillin
= ures_getByKeyWithFallback(fOtherFillin
, subKey
, fFillin
, &status
);
217 #if defined (U_DEBUG_CALDATA)
218 fprintf(stderr
, "%p: get %s/format/%s -> %s - from MAIN %s\n", this, key
, subKey
, u_errorName(status
), ures_getLocale(fFillin
, &status
));
221 if(fFallback
&& (status
== U_MISSING_RESOURCE_ERROR
)) {
222 status
= U_ZERO_ERROR
; // retry with fallback (gregorian)
223 fFillin
= ures_getByKeyWithFallback(fFallback
, key
, fFillin
, &status
);
224 fOtherFillin
= ures_getByKeyWithFallback(fFillin
, U_FORMAT_KEY
, fOtherFillin
, &status
);
225 fFillin
= ures_getByKeyWithFallback(fOtherFillin
, subKey
, fFillin
, &status
);
226 #if defined (U_DEBUG_CALDATA)
227 fprintf(stderr
, "%p: get %s/format/%s -> %s - from FALLBACK %s\n",this, key
, subKey
, u_errorName(status
), ures_getLocale(fFillin
,&status
));
231 //// handling of 'default' keyword on failure: Commented out for 3.0.
232 // if((status == U_MISSING_RESOURCE_ERROR) &&
233 // uprv_strcmp(subKey,U_DEFAULT_KEY)) { // avoid recursion
234 // #if defined (U_DEBUG_CALDATA)
235 // fprintf(stderr, "%p: - attempting fallback -\n", this);
238 // UErrorCode subStatus = U_ZERO_ERROR;
240 // char kwBuf[128] = "";
242 // /* fFillin = */ getByKey2(key, U_DEFAULT_KEY, subStatus);
243 // kw = ures_getString(fFillin, &len, &subStatus);
244 // if(len>126) { // too big
247 // if(U_SUCCESS(subStatus) && (len>0)) {
248 // u_UCharsToChars(kw, kwBuf, len+1);
249 // if(*kwBuf && uprv_strcmp(kwBuf,subKey)) {
250 // #if defined (U_DEBUG_CALDATA)
251 // fprintf(stderr, "%p: trying %s/format/default -> \"%s\"\n",this, key, kwBuf);
253 // // now try again with the default
254 // status = U_ZERO_ERROR;
255 // /* fFillin = */ getByKey2(key, kwBuf, status);
257 // #if defined (U_DEBUG_CALDATA)
259 // fprintf(stderr, "%p: could not load %s/format/default - fail out (%s)\n",this, key, kwBuf, u_errorName(status));
267 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CalendarData
);