Home | History | Annotate | Download | only in i18n
      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