1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/gregoimp.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,328 @@ 1.4 +/* 1.5 + ********************************************************************** 1.6 + * Copyright (c) 2003-2008, International Business Machines 1.7 + * Corporation and others. All Rights Reserved. 1.8 + ********************************************************************** 1.9 + * Author: Alan Liu 1.10 + * Created: September 2 2003 1.11 + * Since: ICU 2.8 1.12 + ********************************************************************** 1.13 + */ 1.14 + 1.15 +#include "gregoimp.h" 1.16 + 1.17 +#if !UCONFIG_NO_FORMATTING 1.18 + 1.19 +#include "unicode/ucal.h" 1.20 +#include "uresimp.h" 1.21 +#include "cstring.h" 1.22 +#include "uassert.h" 1.23 + 1.24 +#if defined(U_DEBUG_CALDATA) 1.25 +#include <stdio.h> 1.26 +#endif 1.27 + 1.28 +U_NAMESPACE_BEGIN 1.29 + 1.30 +int32_t ClockMath::floorDivide(int32_t numerator, int32_t denominator) { 1.31 + return (numerator >= 0) ? 1.32 + numerator / denominator : ((numerator + 1) / denominator) - 1; 1.33 +} 1.34 + 1.35 +int32_t ClockMath::floorDivide(double numerator, int32_t denominator, 1.36 + int32_t& remainder) { 1.37 + double quotient; 1.38 + quotient = uprv_floor(numerator / denominator); 1.39 + remainder = (int32_t) (numerator - (quotient * denominator)); 1.40 + return (int32_t) quotient; 1.41 +} 1.42 + 1.43 +double ClockMath::floorDivide(double dividend, double divisor, 1.44 + double& remainder) { 1.45 + // Only designed to work for positive divisors 1.46 + U_ASSERT(divisor > 0); 1.47 + double quotient = floorDivide(dividend, divisor); 1.48 + remainder = dividend - (quotient * divisor); 1.49 + // N.B. For certain large dividends, on certain platforms, there 1.50 + // is a bug such that the quotient is off by one. If you doubt 1.51 + // this to be true, set a breakpoint below and run cintltst. 1.52 + if (remainder < 0 || remainder >= divisor) { 1.53 + // E.g. 6.7317038241449352e+022 / 86400000.0 is wrong on my 1.54 + // machine (too high by one). 4.1792057231752762e+024 / 1.55 + // 86400000.0 is wrong the other way (too low). 1.56 + double q = quotient; 1.57 + quotient += (remainder < 0) ? -1 : +1; 1.58 + if (q == quotient) { 1.59 + // For quotients > ~2^53, we won't be able to add or 1.60 + // subtract one, since the LSB of the mantissa will be > 1.61 + // 2^0; that is, the exponent (base 2) will be larger than 1.62 + // the length, in bits, of the mantissa. In that case, we 1.63 + // can't give a correct answer, so we set the remainder to 1.64 + // zero. This has the desired effect of making extreme 1.65 + // values give back an approximate answer rather than 1.66 + // crashing. For example, UDate values above a ~10^25 1.67 + // might all have a time of midnight. 1.68 + remainder = 0; 1.69 + } else { 1.70 + remainder = dividend - (quotient * divisor); 1.71 + } 1.72 + } 1.73 + U_ASSERT(0 <= remainder && remainder < divisor); 1.74 + return quotient; 1.75 +} 1.76 + 1.77 +const int32_t JULIAN_1_CE = 1721426; // January 1, 1 CE Gregorian 1.78 +const int32_t JULIAN_1970_CE = 2440588; // January 1, 1970 CE Gregorian 1.79 + 1.80 +const int16_t Grego::DAYS_BEFORE[24] = 1.81 + {0,31,59,90,120,151,181,212,243,273,304,334, 1.82 + 0,31,60,91,121,152,182,213,244,274,305,335}; 1.83 + 1.84 +const int8_t Grego::MONTH_LENGTH[24] = 1.85 + {31,28,31,30,31,30,31,31,30,31,30,31, 1.86 + 31,29,31,30,31,30,31,31,30,31,30,31}; 1.87 + 1.88 +double Grego::fieldsToDay(int32_t year, int32_t month, int32_t dom) { 1.89 + 1.90 + int32_t y = year - 1; 1.91 + 1.92 + double julian = 365 * y + ClockMath::floorDivide(y, 4) + (JULIAN_1_CE - 3) + // Julian cal 1.93 + ClockMath::floorDivide(y, 400) - ClockMath::floorDivide(y, 100) + 2 + // => Gregorian cal 1.94 + DAYS_BEFORE[month + (isLeapYear(year) ? 12 : 0)] + dom; // => month/dom 1.95 + 1.96 + return julian - JULIAN_1970_CE; // JD => epoch day 1.97 +} 1.98 + 1.99 +void Grego::dayToFields(double day, int32_t& year, int32_t& month, 1.100 + int32_t& dom, int32_t& dow, int32_t& doy) { 1.101 + 1.102 + // Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar) 1.103 + day += JULIAN_1970_CE - JULIAN_1_CE; 1.104 + 1.105 + // Convert from the day number to the multiple radix 1.106 + // representation. We use 400-year, 100-year, and 4-year cycles. 1.107 + // For example, the 4-year cycle has 4 years + 1 leap day; giving 1.108 + // 1461 == 365*4 + 1 days. 1.109 + int32_t n400 = ClockMath::floorDivide(day, 146097, doy); // 400-year cycle length 1.110 + int32_t n100 = ClockMath::floorDivide(doy, 36524, doy); // 100-year cycle length 1.111 + int32_t n4 = ClockMath::floorDivide(doy, 1461, doy); // 4-year cycle length 1.112 + int32_t n1 = ClockMath::floorDivide(doy, 365, doy); 1.113 + year = 400*n400 + 100*n100 + 4*n4 + n1; 1.114 + if (n100 == 4 || n1 == 4) { 1.115 + doy = 365; // Dec 31 at end of 4- or 400-year cycle 1.116 + } else { 1.117 + ++year; 1.118 + } 1.119 + 1.120 + UBool isLeap = isLeapYear(year); 1.121 + 1.122 + // Gregorian day zero is a Monday. 1.123 + dow = (int32_t) uprv_fmod(day + 1, 7); 1.124 + dow += (dow < 0) ? (UCAL_SUNDAY + 7) : UCAL_SUNDAY; 1.125 + 1.126 + // Common Julian/Gregorian calculation 1.127 + int32_t correction = 0; 1.128 + int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1 1.129 + if (doy >= march1) { 1.130 + correction = isLeap ? 1 : 2; 1.131 + } 1.132 + month = (12 * (doy + correction) + 6) / 367; // zero-based month 1.133 + dom = doy - DAYS_BEFORE[month + (isLeap ? 12 : 0)] + 1; // one-based DOM 1.134 + doy++; // one-based doy 1.135 +} 1.136 + 1.137 +void Grego::timeToFields(UDate time, int32_t& year, int32_t& month, 1.138 + int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid) { 1.139 + double millisInDay; 1.140 + double day = ClockMath::floorDivide((double)time, (double)U_MILLIS_PER_DAY, millisInDay); 1.141 + mid = (int32_t)millisInDay; 1.142 + dayToFields(day, year, month, dom, dow, doy); 1.143 +} 1.144 + 1.145 +int32_t Grego::dayOfWeek(double day) { 1.146 + int32_t dow; 1.147 + ClockMath::floorDivide(day + UCAL_THURSDAY, 7, dow); 1.148 + return (dow == 0) ? UCAL_SATURDAY : dow; 1.149 +} 1.150 + 1.151 +int32_t Grego::dayOfWeekInMonth(int32_t year, int32_t month, int32_t dom) { 1.152 + int32_t weekInMonth = (dom + 6)/7; 1.153 + if (weekInMonth == 4) { 1.154 + if (dom + 7 > monthLength(year, month)) { 1.155 + weekInMonth = -1; 1.156 + } 1.157 + } else if (weekInMonth == 5) { 1.158 + weekInMonth = -1; 1.159 + } 1.160 + return weekInMonth; 1.161 +} 1.162 + 1.163 +/* ---- CalendarData ------ */ 1.164 + 1.165 +#define U_CALENDAR_KEY "calendar" 1.166 +#define U_GREGORIAN_KEY "gregorian" 1.167 +#define U_FORMAT_KEY "format" 1.168 +#define U_DEFAULT_KEY "default" 1.169 +#define U_CALENDAR_DATA ((char*)0) 1.170 + 1.171 + 1.172 +// CalendarData::CalendarData(const Locale& loc, UErrorCode& status) 1.173 +// : fFillin(NULL), fBundle(NULL), fFallback(NULL) { 1.174 +// initData(loc.getBaseName(), (char*) "???", status); 1.175 +// } 1.176 + 1.177 +CalendarData::CalendarData(const Locale& loc, const char *type, UErrorCode& status) 1.178 + : fFillin(NULL), fOtherFillin(NULL), fBundle(NULL), fFallback(NULL) { 1.179 + initData(loc.getBaseName(), type, status); 1.180 +} 1.181 + 1.182 +void CalendarData::initData(const char *locale, const char *type, UErrorCode& status) { 1.183 + fOtherFillin = ures_open(U_CALENDAR_DATA, locale, &status); 1.184 + fFillin = ures_getByKey(fOtherFillin, U_CALENDAR_KEY, fFillin, &status); 1.185 + 1.186 + if((type != NULL) && 1.187 + (*type != '\0') && 1.188 + (uprv_strcmp(type, U_GREGORIAN_KEY))) 1.189 + { 1.190 + fBundle = ures_getByKeyWithFallback(fFillin, type, NULL, &status); 1.191 + fFallback = ures_getByKeyWithFallback(fFillin, U_GREGORIAN_KEY, NULL, &status); 1.192 + 1.193 +#if defined (U_DEBUG_CALDATA) 1.194 + fprintf(stderr, "%p: CalendarData(%s, %s, %s) -> main(%p, %s)=%s, fallback(%p, %s)=%s\n", 1.195 + this, locale, type, u_errorName(status), fBundle, type, fBundle?ures_getLocale(fBundle, &status):"", 1.196 + fFallback, U_GREGORIAN_KEY, fFallback?ures_getLocale(fFallback, &status):""); 1.197 +#endif 1.198 + 1.199 + } else { 1.200 + fBundle = ures_getByKeyWithFallback(fFillin, U_GREGORIAN_KEY, NULL, &status); 1.201 +#if defined (U_DEBUG_CALDATA) 1.202 + fprintf(stderr, "%p: CalendarData(%s, %s, %s) -> main(%p, %s)=%s, fallback = NULL\n", 1.203 + this, locale, type, u_errorName(status), fBundle, U_GREGORIAN_KEY, fBundle?ures_getLocale(fBundle, &status):"" ); 1.204 +#endif 1.205 + } 1.206 +} 1.207 + 1.208 +CalendarData::~CalendarData() { 1.209 + ures_close(fFillin); 1.210 + ures_close(fBundle); 1.211 + ures_close(fFallback); 1.212 + ures_close(fOtherFillin); 1.213 +} 1.214 + 1.215 +UResourceBundle* 1.216 +CalendarData::getByKey(const char *key, UErrorCode& status) { 1.217 + if(U_FAILURE(status)) { 1.218 + return NULL; 1.219 + } 1.220 + 1.221 + if(fBundle) { 1.222 + fFillin = ures_getByKeyWithFallback(fBundle, key, fFillin, &status); 1.223 +#if defined (U_DEBUG_CALDATA) 1.224 + fprintf(stderr, "%p: get %s -> %s - from MAIN %s\n",this, key, u_errorName(status), ures_getLocale(fFillin, &status)); 1.225 +#endif 1.226 + } 1.227 + if(fFallback && (status == U_MISSING_RESOURCE_ERROR)) { 1.228 + status = U_ZERO_ERROR; // retry with fallback (gregorian) 1.229 + fFillin = ures_getByKeyWithFallback(fFallback, key, fFillin, &status); 1.230 +#if defined (U_DEBUG_CALDATA) 1.231 + fprintf(stderr, "%p: get %s -> %s - from FALLBACK %s\n",this, key, u_errorName(status), ures_getLocale(fFillin, &status)); 1.232 +#endif 1.233 + } 1.234 + return fFillin; 1.235 +} 1.236 + 1.237 +UResourceBundle* CalendarData::getByKey2(const char *key, const char *subKey, UErrorCode& status) { 1.238 + if(U_FAILURE(status)) { 1.239 + return NULL; 1.240 + } 1.241 + 1.242 + if(fBundle) { 1.243 +#if defined (U_DEBUG_CALDATA) 1.244 + fprintf(stderr, "%p: //\n"); 1.245 +#endif 1.246 + fFillin = ures_getByKeyWithFallback(fBundle, key, fFillin, &status); 1.247 + fOtherFillin = ures_getByKeyWithFallback(fFillin, U_FORMAT_KEY, fOtherFillin, &status); 1.248 + fFillin = ures_getByKeyWithFallback(fOtherFillin, subKey, fFillin, &status); 1.249 +#if defined (U_DEBUG_CALDATA) 1.250 + fprintf(stderr, "%p: get %s/format/%s -> %s - from MAIN %s\n", this, key, subKey, u_errorName(status), ures_getLocale(fFillin, &status)); 1.251 +#endif 1.252 + } 1.253 + if(fFallback && (status == U_MISSING_RESOURCE_ERROR)) { 1.254 + status = U_ZERO_ERROR; // retry with fallback (gregorian) 1.255 + fFillin = ures_getByKeyWithFallback(fFallback, key, fFillin, &status); 1.256 + fOtherFillin = ures_getByKeyWithFallback(fFillin, U_FORMAT_KEY, fOtherFillin, &status); 1.257 + fFillin = ures_getByKeyWithFallback(fOtherFillin, subKey, fFillin, &status); 1.258 +#if defined (U_DEBUG_CALDATA) 1.259 + fprintf(stderr, "%p: get %s/format/%s -> %s - from FALLBACK %s\n",this, key, subKey, u_errorName(status), ures_getLocale(fFillin,&status)); 1.260 +#endif 1.261 + } 1.262 + 1.263 +//// handling of 'default' keyword on failure: Commented out for 3.0. 1.264 +// if((status == U_MISSING_RESOURCE_ERROR) && 1.265 +// uprv_strcmp(subKey,U_DEFAULT_KEY)) { // avoid recursion 1.266 +// #if defined (U_DEBUG_CALDATA) 1.267 +// fprintf(stderr, "%p: - attempting fallback -\n", this); 1.268 +// fflush(stderr); 1.269 +// #endif 1.270 +// UErrorCode subStatus = U_ZERO_ERROR; 1.271 +// int32_t len; 1.272 +// char kwBuf[128] = ""; 1.273 +// const UChar *kw; 1.274 +// /* fFillin = */ getByKey2(key, U_DEFAULT_KEY, subStatus); 1.275 +// kw = ures_getString(fFillin, &len, &subStatus); 1.276 +// if(len>126) { // too big 1.277 +// len = 0; 1.278 +// } 1.279 +// if(U_SUCCESS(subStatus) && (len>0)) { 1.280 +// u_UCharsToChars(kw, kwBuf, len+1); 1.281 +// if(*kwBuf && uprv_strcmp(kwBuf,subKey)) { 1.282 +// #if defined (U_DEBUG_CALDATA) 1.283 +// fprintf(stderr, "%p: trying %s/format/default -> \"%s\"\n",this, key, kwBuf); 1.284 +// #endif 1.285 +// // now try again with the default 1.286 +// status = U_ZERO_ERROR; 1.287 +// /* fFillin = */ getByKey2(key, kwBuf, status); 1.288 +// } 1.289 +// #if defined (U_DEBUG_CALDATA) 1.290 +// } else { 1.291 +// fprintf(stderr, "%p: could not load %s/format/default - fail out (%s)\n",this, key, kwBuf, u_errorName(status)); 1.292 +// #endif 1.293 +// } 1.294 +// } 1.295 + 1.296 + return fFillin; 1.297 +} 1.298 + 1.299 +UResourceBundle* CalendarData::getByKey3(const char *key, const char *contextKey, const char *subKey, UErrorCode& status) { 1.300 + if(U_FAILURE(status)) { 1.301 + return NULL; 1.302 + } 1.303 + 1.304 + if(fBundle) { 1.305 +#if defined (U_DEBUG_CALDATA) 1.306 + fprintf(stderr, "%p: //\n"); 1.307 +#endif 1.308 + fFillin = ures_getByKeyWithFallback(fBundle, key, fFillin, &status); 1.309 + fOtherFillin = ures_getByKeyWithFallback(fFillin, contextKey, fOtherFillin, &status); 1.310 + fFillin = ures_getByKeyWithFallback(fOtherFillin, subKey, fFillin, &status); 1.311 +#if defined (U_DEBUG_CALDATA) 1.312 + fprintf(stderr, "%p: get %s/%s/%s -> %s - from MAIN %s\n", this, key, contextKey, subKey, u_errorName(status), ures_getLocale(fFillin, &status)); 1.313 +#endif 1.314 + } 1.315 + if(fFallback && (status == U_MISSING_RESOURCE_ERROR)) { 1.316 + status = U_ZERO_ERROR; // retry with fallback (gregorian) 1.317 + fFillin = ures_getByKeyWithFallback(fFallback, key, fFillin, &status); 1.318 + fOtherFillin = ures_getByKeyWithFallback(fFillin, contextKey, fOtherFillin, &status); 1.319 + fFillin = ures_getByKeyWithFallback(fOtherFillin, subKey, fFillin, &status); 1.320 +#if defined (U_DEBUG_CALDATA) 1.321 + fprintf(stderr, "%p: get %s/%s/%s -> %s - from FALLBACK %s\n",this, key, contextKey, subKey, u_errorName(status), ures_getLocale(fFillin,&status)); 1.322 +#endif 1.323 + } 1.324 + 1.325 + return fFillin; 1.326 +} 1.327 + 1.328 +U_NAMESPACE_END 1.329 + 1.330 +#endif 1.331 +//eof