OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ********************************************************************** |
| 3 * Copyright (c) 2003-2008, International Business Machines |
| 4 * Corporation and others. All Rights Reserved. |
| 5 ********************************************************************** |
| 6 * Author: Alan Liu |
| 7 * Created: September 2 2003 |
| 8 * Since: ICU 2.8 |
| 9 ********************************************************************** |
| 10 */ |
| 11 |
| 12 #ifndef GREGOIMP_H |
| 13 #define GREGOIMP_H |
| 14 #include "unicode/utypes.h" |
| 15 #if !UCONFIG_NO_FORMATTING |
| 16 |
| 17 #include "unicode/ures.h" |
| 18 #include "unicode/locid.h" |
| 19 #include "putilimp.h" |
| 20 |
| 21 U_NAMESPACE_BEGIN |
| 22 |
| 23 /** |
| 24 * A utility class providing mathematical functions used by time zone |
| 25 * and calendar code. Do not instantiate. Formerly just named 'Math'. |
| 26 * @internal |
| 27 */ |
| 28 class ClockMath { |
| 29 public: |
| 30 /** |
| 31 * Divide two integers, returning the floor of the quotient. |
| 32 * Unlike the built-in division, this is mathematically |
| 33 * well-behaved. E.g., <code>-1/4</code> => 0 but |
| 34 * <code>floorDivide(-1,4)</code> => -1. |
| 35 * @param numerator the numerator |
| 36 * @param denominator a divisor which must be != 0 |
| 37 * @return the floor of the quotient |
| 38 */ |
| 39 static int32_t floorDivide(int32_t numerator, int32_t denominator); |
| 40 |
| 41 /** |
| 42 * Divide two numbers, returning the floor of the quotient. |
| 43 * Unlike the built-in division, this is mathematically |
| 44 * well-behaved. E.g., <code>-1/4</code> => 0 but |
| 45 * <code>floorDivide(-1,4)</code> => -1. |
| 46 * @param numerator the numerator |
| 47 * @param denominator a divisor which must be != 0 |
| 48 * @return the floor of the quotient |
| 49 */ |
| 50 static inline double floorDivide(double numerator, double denominator); |
| 51 |
| 52 /** |
| 53 * Divide two numbers, returning the floor of the quotient and |
| 54 * the modulus remainder. Unlike the built-in division, this is |
| 55 * mathematically well-behaved. E.g., <code>-1/4</code> => 0 and |
| 56 * <code>-1%4</code> => -1, but <code>floorDivide(-1,4)</code> => |
| 57 * -1 with <code>remainder</code> => 3. NOTE: If numerator is |
| 58 * too large, the returned quotient may overflow. |
| 59 * @param numerator the numerator |
| 60 * @param denominator a divisor which must be != 0 |
| 61 * @param remainder output parameter to receive the |
| 62 * remainder. Unlike <code>numerator % denominator</code>, this |
| 63 * will always be non-negative, in the half-open range <code>[0, |
| 64 * |denominator|)</code>. |
| 65 * @return the floor of the quotient |
| 66 */ |
| 67 static int32_t floorDivide(double numerator, int32_t denominator, |
| 68 int32_t& remainder); |
| 69 |
| 70 /** |
| 71 * For a positive divisor, return the quotient and remainder |
| 72 * such that dividend = quotient*divisor + remainder and |
| 73 * 0 <= remainder < divisor. |
| 74 * |
| 75 * Works around edge-case bugs. Handles pathological input |
| 76 * (divident >> divisor) reasonably. |
| 77 * |
| 78 * Calling with a divisor <= 0 is disallowed. |
| 79 */ |
| 80 static double floorDivide(double dividend, double divisor, |
| 81 double& remainder); |
| 82 }; |
| 83 |
| 84 // Useful millisecond constants |
| 85 #define kOneDay (1.0 * U_MILLIS_PER_DAY) // 86,400,000 |
| 86 #define kOneHour (60*60*1000) |
| 87 #define kOneMinute 60000 |
| 88 #define kOneSecond 1000 |
| 89 #define kOneMillisecond 1 |
| 90 #define kOneWeek (7.0 * kOneDay) // 604,800,000 |
| 91 |
| 92 // Epoch constants |
| 93 #define kJan1_1JulianDay 1721426 // January 1, year 1 (Gregorian) |
| 94 |
| 95 #define kEpochStartAsJulianDay 2440588 // January 1, 1970 (Gregorian) |
| 96 |
| 97 #define kEpochYear 1970 |
| 98 |
| 99 |
| 100 #define kEarliestViableMillis -185331720384000000.0 // minimum representable b
y julian day -1e17 |
| 101 |
| 102 #define kLatestViableMillis 185753453990400000.0 // max representable by ju
lian day +1e17 |
| 103 |
| 104 /** |
| 105 * The minimum supported Julian day. This value is equivalent to |
| 106 * MIN_MILLIS. |
| 107 */ |
| 108 #define MIN_JULIAN (-0x7F000000) |
| 109 |
| 110 /** |
| 111 * The minimum supported epoch milliseconds. This value is equivalent |
| 112 * to MIN_JULIAN. |
| 113 */ |
| 114 #define MIN_MILLIS ((MIN_JULIAN - kEpochStartAsJulianDay) * kOneDay) |
| 115 |
| 116 /** |
| 117 * The maximum supported Julian day. This value is equivalent to |
| 118 * MAX_MILLIS. |
| 119 */ |
| 120 #define MAX_JULIAN (+0x7F000000) |
| 121 |
| 122 /** |
| 123 * The maximum supported epoch milliseconds. This value is equivalent |
| 124 * to MAX_JULIAN. |
| 125 */ |
| 126 #define MAX_MILLIS ((MAX_JULIAN - kEpochStartAsJulianDay) * kOneDay) |
| 127 |
| 128 /** |
| 129 * A utility class providing proleptic Gregorian calendar functions |
| 130 * used by time zone and calendar code. Do not instantiate. |
| 131 * |
| 132 * Note: Unlike GregorianCalendar, all computations performed by this |
| 133 * class occur in the pure proleptic GregorianCalendar. |
| 134 */ |
| 135 class Grego { |
| 136 public: |
| 137 /** |
| 138 * Return TRUE if the given year is a leap year. |
| 139 * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc. |
| 140 * @return TRUE if the year is a leap year |
| 141 */ |
| 142 static inline UBool isLeapYear(int32_t year); |
| 143 |
| 144 /** |
| 145 * Return the number of days in the given month. |
| 146 * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc. |
| 147 * @param month 0-based month, with 0==Jan |
| 148 * @return the number of days in the given month |
| 149 */ |
| 150 static inline int8_t monthLength(int32_t year, int32_t month); |
| 151 |
| 152 /** |
| 153 * Return the length of a previous month of the Gregorian calendar. |
| 154 * @param y the extended year |
| 155 * @param m the 0-based month number |
| 156 * @return the number of days in the month previous to the given month |
| 157 */ |
| 158 static inline int8_t previousMonthLength(int y, int m); |
| 159 |
| 160 /** |
| 161 * Convert a year, month, and day-of-month, given in the proleptic |
| 162 * Gregorian calendar, to 1970 epoch days. |
| 163 * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc. |
| 164 * @param month 0-based month, with 0==Jan |
| 165 * @param dom 1-based day of month |
| 166 * @return the day number, with day 0 == Jan 1 1970 |
| 167 */ |
| 168 static double fieldsToDay(int32_t year, int32_t month, int32_t dom); |
| 169 |
| 170 /** |
| 171 * Convert a 1970-epoch day number to proleptic Gregorian year, |
| 172 * month, day-of-month, and day-of-week. |
| 173 * @param day 1970-epoch day (integral value) |
| 174 * @param year output parameter to receive year |
| 175 * @param month output parameter to receive month (0-based, 0==Jan) |
| 176 * @param dom output parameter to receive day-of-month (1-based) |
| 177 * @param dow output parameter to receive day-of-week (1-based, 1==Sun) |
| 178 * @param doy output parameter to receive day-of-year (1-based) |
| 179 */ |
| 180 static void dayToFields(double day, int32_t& year, int32_t& month, |
| 181 int32_t& dom, int32_t& dow, int32_t& doy); |
| 182 |
| 183 /** |
| 184 * Convert a 1970-epoch day number to proleptic Gregorian year, |
| 185 * month, day-of-month, and day-of-week. |
| 186 * @param day 1970-epoch day (integral value) |
| 187 * @param year output parameter to receive year |
| 188 * @param month output parameter to receive month (0-based, 0==Jan) |
| 189 * @param dom output parameter to receive day-of-month (1-based) |
| 190 * @param dow output parameter to receive day-of-week (1-based, 1==Sun) |
| 191 */ |
| 192 static inline void dayToFields(double day, int32_t& year, int32_t& month, |
| 193 int32_t& dom, int32_t& dow); |
| 194 |
| 195 /** |
| 196 * Convert a 1970-epoch milliseconds to proleptic Gregorian year, |
| 197 * month, day-of-month, and day-of-week, day of year and millis-in-day. |
| 198 * @param time 1970-epoch milliseconds |
| 199 * @param year output parameter to receive year |
| 200 * @param month output parameter to receive month (0-based, 0==Jan) |
| 201 * @param dom output parameter to receive day-of-month (1-based) |
| 202 * @param dow output parameter to receive day-of-week (1-based, 1==Sun) |
| 203 * @param doy output parameter to receive day-of-year (1-based) |
| 204 * @param mid output parameter to recieve millis-in-day |
| 205 */ |
| 206 static void timeToFields(UDate time, int32_t& year, int32_t& month, |
| 207 int32_t& dom, int32_t& dow, int32_t& doy, int32_t& m
id); |
| 208 |
| 209 /** |
| 210 * Return the day of week on the 1970-epoch day |
| 211 * @param day the 1970-epoch day (integral value) |
| 212 * @return the day of week |
| 213 */ |
| 214 static int32_t dayOfWeek(double day); |
| 215 |
| 216 /** |
| 217 * Returns the ordinal number for the specified day of week within the month
. |
| 218 * The valid return value is 1, 2, 3, 4 or -1. |
| 219 * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc. |
| 220 * @param month 0-based month, with 0==Jan |
| 221 * @param dom 1-based day of month |
| 222 * @return The ordinal number for the specified day of week within the month |
| 223 */ |
| 224 static int32_t dayOfWeekInMonth(int32_t year, int32_t month, int32_t dom); |
| 225 |
| 226 /** |
| 227 * Converts Julian day to time as milliseconds. |
| 228 * @param julian the given Julian day number. |
| 229 * @return time as milliseconds. |
| 230 * @internal |
| 231 */ |
| 232 static inline double julianDayToMillis(int32_t julian); |
| 233 |
| 234 /** |
| 235 * Converts time as milliseconds to Julian day. |
| 236 * @param millis the given milliseconds. |
| 237 * @return the Julian day number. |
| 238 * @internal |
| 239 */ |
| 240 static inline int32_t millisToJulianDay(double millis); |
| 241 |
| 242 /** |
| 243 * Calculates the Gregorian day shift value for an extended year. |
| 244 * @param eyear Extended year |
| 245 * @returns number of days to ADD to Julian in order to convert from J->G |
| 246 */ |
| 247 static inline int32_t gregorianShift(int32_t eyear); |
| 248 |
| 249 private: |
| 250 static const int16_t DAYS_BEFORE[24]; |
| 251 static const int8_t MONTH_LENGTH[24]; |
| 252 }; |
| 253 |
| 254 inline double ClockMath::floorDivide(double numerator, double denominator) { |
| 255 return uprv_floor(numerator / denominator); |
| 256 } |
| 257 |
| 258 inline UBool Grego::isLeapYear(int32_t year) { |
| 259 // year&0x3 == year%4 |
| 260 return ((year&0x3) == 0) && ((year%100 != 0) || (year%400 == 0)); |
| 261 } |
| 262 |
| 263 inline int8_t |
| 264 Grego::monthLength(int32_t year, int32_t month) { |
| 265 return MONTH_LENGTH[month + (isLeapYear(year) ? 12 : 0)]; |
| 266 } |
| 267 |
| 268 inline int8_t |
| 269 Grego::previousMonthLength(int y, int m) { |
| 270 return (m > 0) ? monthLength(y, m-1) : 31; |
| 271 } |
| 272 |
| 273 inline void Grego::dayToFields(double day, int32_t& year, int32_t& month, |
| 274 int32_t& dom, int32_t& dow) { |
| 275 int32_t doy_unused; |
| 276 dayToFields(day,year,month,dom,dow,doy_unused); |
| 277 } |
| 278 |
| 279 inline double Grego::julianDayToMillis(int32_t julian) |
| 280 { |
| 281 return (julian - kEpochStartAsJulianDay) * kOneDay; |
| 282 } |
| 283 |
| 284 inline int32_t Grego::millisToJulianDay(double millis) { |
| 285 return (int32_t) (kEpochStartAsJulianDay + ClockMath::floorDivide(millis, (dou
ble)kOneDay)); |
| 286 } |
| 287 |
| 288 inline int32_t Grego::gregorianShift(int32_t eyear) { |
| 289 int32_t y = eyear-1; |
| 290 int32_t gregShift = ClockMath::floorDivide(y, 400) - ClockMath::floorDivide(y,
100) + 2; |
| 291 return gregShift; |
| 292 } |
| 293 |
| 294 /** |
| 295 * This utility class provides convenient access to the data needed for a calend
ar. |
| 296 * @internal ICU 3.0 |
| 297 */ |
| 298 class CalendarData : public UMemory { |
| 299 public: |
| 300 /** |
| 301 * Construct a CalendarData from the given locale. |
| 302 * @param loc locale to use. The 'calendar' keyword will be ignored. |
| 303 * @param type calendar type. NULL indicates the gregorian calendar. |
| 304 * No default lookup is done. |
| 305 * @param status error code |
| 306 */ |
| 307 CalendarData(const Locale& loc, const char *type, UErrorCode& status); |
| 308 |
| 309 /** |
| 310 * Load data for calendar. Note, this object owns the resources, do NOT call
ures_close()! |
| 311 * The ResourceBundle C++ API should NOT be used because it is too slow for
a low level API. |
| 312 * |
| 313 * @param key Resource key to data |
| 314 * @param status Error Status |
| 315 * @internal |
| 316 */ |
| 317 UResourceBundle* getByKey(const char *key, UErrorCode& status); |
| 318 |
| 319 /** |
| 320 * Load data for calendar. Note, this object owns the resources, do NOT call
ures_close()! |
| 321 * There is an implicit key of 'format' |
| 322 * data is located in: "calendar/key/format/subKey" |
| 323 * for example, calendar/dayNames/format/abbreviated |
| 324 * The ResourceBundle C++ API should NOT be used because it is too slow for
a low level API. |
| 325 * |
| 326 * @param key Resource key to data |
| 327 * @param subKey Resource key to data |
| 328 * @param status Error Status |
| 329 * @internal |
| 330 */ |
| 331 UResourceBundle* getByKey2(const char *key, const char *subKey, UErrorCode&
status); |
| 332 |
| 333 /** |
| 334 * Load data for calendar. Note, this object owns the resources, do NOT call
ures_close()! |
| 335 * data is located in: "calendar/key/contextKey/subKey" |
| 336 * for example, calendar/dayNames/standalone/narrow |
| 337 * The ResourceBundle C++ API should NOT be used because it is too slow for
a low level API. |
| 338 * |
| 339 * @param key Resource key to data |
| 340 * @param contextKey Resource key to data |
| 341 * @param subKey Resource key to data |
| 342 * @param status Error Status |
| 343 * @internal |
| 344 */ |
| 345 UResourceBundle* getByKey3(const char *key, const char *contextKey, const ch
ar *subKey, UErrorCode& status); |
| 346 |
| 347 ~CalendarData(); |
| 348 |
| 349 private: |
| 350 void initData(const char *locale, const char *type, UErrorCode& status); |
| 351 |
| 352 UResourceBundle *fFillin; |
| 353 UResourceBundle *fOtherFillin; |
| 354 UResourceBundle *fBundle; |
| 355 UResourceBundle *fFallback; |
| 356 CalendarData(); // Not implemented. |
| 357 }; |
| 358 |
| 359 U_NAMESPACE_END |
| 360 |
| 361 #endif // !UCONFIG_NO_FORMATTING |
| 362 #endif // GREGOIMP_H |
| 363 |
| 364 //eof |
OLD | NEW |