intl/icu/source/i18n/gregoimp.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial