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 by julian day -1e17 101 102 #define kLatestViableMillis 185753453990400000.0 // max representable by julian 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& mid); 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, (double)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 calendar. 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 char *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 365