intl/icu/source/i18n/gregoimp.cpp

changeset 0
6474c204b198
     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

mercurial