tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gregoimp.h (15351B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 **********************************************************************
      5 * Copyright (c) 2003-2008, International Business Machines
      6 * Corporation and others.  All Rights Reserved.
      7 **********************************************************************
      8 * Author: Alan Liu
      9 * Created: September 2 2003
     10 * Since: ICU 2.8
     11 **********************************************************************
     12 */
     13 
     14 #ifndef GREGOIMP_H
     15 #define GREGOIMP_H
     16 #include "unicode/utypes.h"
     17 #include "unicode/calendar.h"
     18 #if !UCONFIG_NO_FORMATTING
     19 
     20 #include "unicode/ures.h"
     21 #include "unicode/locid.h"
     22 #include "putilimp.h"
     23 
     24 U_NAMESPACE_BEGIN
     25 
     26 /**
     27 * A utility class providing mathematical functions used by time zone
     28 * and calendar code.  Do not instantiate.  Formerly just named 'Math'.
     29 * @internal
     30 */
     31 class ClockMath {
     32 public:
     33    /**
     34     * Divide two integers, returning the floor of the quotient.
     35     * Unlike the built-in division, this is mathematically
     36     * well-behaved.  E.g., <code>-1/4</code> => 0 but
     37     * <code>floorDivide(-1,4)</code> => -1.
     38     * @param numerator the numerator
     39     * @param denominator a divisor which must be != 0
     40     * @return the floor of the quotient
     41     */
     42    static int32_t floorDivide(int32_t numerator, int32_t denominator);
     43 
     44    /**
     45     * Divide two integers, returning the floor of the quotient.
     46     * Unlike the built-in division, this is mathematically
     47     * well-behaved.  E.g., <code>-1/4</code> => 0 but
     48     * <code>floorDivide(-1,4)</code> => -1.
     49     * @param numerator the numerator
     50     * @param denominator a divisor which must be != 0
     51     * @return the floor of the quotient
     52     */
     53    static int64_t floorDivideInt64(int64_t numerator, int64_t denominator);
     54 
     55    /**
     56     * Divide two numbers, returning the floor of the quotient.
     57     * Unlike the built-in division, this is mathematically
     58     * well-behaved.  E.g., <code>-1/4</code> => 0 but
     59     * <code>floorDivide(-1,4)</code> => -1.
     60     * @param numerator the numerator
     61     * @param denominator a divisor which must be != 0
     62     * @return the floor of the quotient
     63     */
     64    static inline double floorDivide(double numerator, double denominator);
     65 
     66    /**
     67     * Divide two numbers, returning the floor of the quotient and
     68     * the modulus remainder.  Unlike the built-in division, this is
     69     * mathematically well-behaved.  E.g., <code>-1/4</code> => 0 and
     70     * <code>-1%4</code> => -1, but <code>floorDivide(-1,4)</code> =>
     71     * -1 with <code>remainder</code> => 3.  NOTE: If numerator is
     72     * too large, the returned quotient may overflow.
     73     * @param numerator the numerator
     74     * @param denominator a divisor which must be != 0
     75     * @param remainder output parameter to receive the
     76     * remainder. Unlike <code>numerator % denominator</code>, this
     77     * will always be non-negative, in the half-open range <code>[0,
     78     * |denominator|)</code>.
     79     * @return the floor of the quotient
     80     */
     81    static int32_t floorDivide(int32_t numerator, int32_t denominator,
     82                               int32_t* remainder);
     83 
     84    /**
     85     * Divide two numbers, returning the floor of the quotient and
     86     * the modulus remainder.  Unlike the built-in division, this is
     87     * mathematically well-behaved.  E.g., <code>-1/4</code> => 0 and
     88     * <code>-1%4</code> => -1, but <code>floorDivide(-1,4)</code> =>
     89     * -1 with <code>remainder</code> => 3.  NOTE: If numerator is
     90     * too large, the returned quotient may overflow.
     91     * @param numerator the numerator
     92     * @param denominator a divisor which must be != 0
     93     * @param remainder output parameter to receive the
     94     * remainder. Unlike <code>numerator % denominator</code>, this
     95     * will always be non-negative, in the half-open range <code>[0,
     96     * |denominator|)</code>.
     97     * @return the floor of the quotient
     98     */
     99    static double floorDivide(double numerator, int32_t denominator,
    100                               int32_t* remainder);
    101 
    102    /**
    103     * For a positive divisor, return the quotient and remainder
    104     * such that dividend = quotient*divisor + remainder and
    105     * 0 <= remainder < divisor.
    106     *
    107     * Works around edge-case bugs.  Handles pathological input
    108     * (dividend >> divisor) reasonably.
    109     *
    110     * Calling with a divisor <= 0 is disallowed.
    111     */
    112    static double floorDivide(double dividend, double divisor,
    113                              double* remainder);
    114 };
    115 
    116 // Useful millisecond constants
    117 #define kOneDay    (1.0 * U_MILLIS_PER_DAY)       //  86,400,000
    118 #define kOneHour   (60*60*1000)
    119 #define kOneMinute 60000
    120 #define kOneSecond 1000
    121 #define kOneMillisecond  1
    122 #define kOneWeek   (7.0 * kOneDay) // 604,800,000
    123 
    124 // Epoch constants
    125 #define kJan1_1JulianDay  1721426 // January 1, year 1 (Gregorian)
    126 
    127 #define kEpochStartAsJulianDay  2440588 // January 1, 1970 (Gregorian)
    128 
    129 #define kEpochYear              1970
    130 
    131 
    132 #define kEarliestViableMillis  -185331720384000000.0  // minimum representable by julian day  -1e17
    133 
    134 #define kLatestViableMillis     185753453990400000.0  // max representable by julian day      +1e17
    135 
    136 /**
    137 * The minimum supported Julian day.  This value is equivalent to
    138 * MIN_MILLIS.
    139 */
    140 #define MIN_JULIAN (-0x7F000000)
    141 
    142 /**
    143 * The minimum supported epoch milliseconds.  This value is equivalent
    144 * to MIN_JULIAN.
    145 */
    146 #define MIN_MILLIS ((MIN_JULIAN - kEpochStartAsJulianDay) * kOneDay)
    147 
    148 /**
    149 * The maximum supported Julian day.  This value is equivalent to
    150 * MAX_MILLIS.
    151 */
    152 #define MAX_JULIAN (+0x7F000000)
    153 
    154 /**
    155 * The maximum supported epoch milliseconds.  This value is equivalent
    156 * to MAX_JULIAN.
    157 */
    158 #define MAX_MILLIS ((MAX_JULIAN - kEpochStartAsJulianDay) * kOneDay)
    159 
    160 /**
    161 * A utility class providing proleptic Gregorian calendar functions
    162 * used by time zone and calendar code.  Do not instantiate.
    163 *
    164 * Note:  Unlike GregorianCalendar, all computations performed by this
    165 * class occur in the pure proleptic GregorianCalendar.
    166 */
    167 class Grego {
    168 public:
    169    /**
    170     * Return true if the given year is a leap year.
    171     * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
    172     * @return true if the year is a leap year
    173     */
    174    static inline UBool isLeapYear(int32_t year);
    175 
    176    /**
    177     * Return the number of days in the given month.
    178     * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
    179     * @param month 0-based month, with 0==Jan
    180     * @return the number of days in the given month
    181     */
    182    static inline int8_t monthLength(int32_t year, int32_t month);
    183 
    184    /**
    185     * Return the length of a previous month of the Gregorian calendar.
    186     * @param y the extended year
    187     * @param m the 0-based month number
    188     * @return the number of days in the month previous to the given month
    189     */
    190    static inline int8_t previousMonthLength(int y, int m);
    191 
    192    /**
    193     * Convert a year, month, and day-of-month, given in the proleptic
    194     * Gregorian calendar, to 1970 epoch days.
    195     * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
    196     * @param month 0-based month, with 0==Jan
    197     * @param dom 1-based day of month
    198     * @return the day number, with day 0 == Jan 1 1970
    199     */
    200    static int64_t fieldsToDay(int32_t year, int32_t month, int32_t dom);
    201    
    202    /**
    203     * Convert a 1970-epoch day number to proleptic Gregorian year,
    204     * month, day-of-month, and day-of-week.
    205     * @param day 1970-epoch day
    206     * @param year output parameter to receive year
    207     * @param month output parameter to receive month (0-based, 0==Jan)
    208     * @param dom output parameter to receive day-of-month (1-based)
    209     * @param dow output parameter to receive day-of-week (1-based, 1==Sun)
    210     * @param doy output parameter to receive day-of-year (1-based)
    211     * @param status error code.
    212     */
    213    static void dayToFields(int32_t day, int32_t& year, int8_t& month,
    214                            int8_t& dom, int8_t& dow, int16_t& doy, UErrorCode& status);
    215 
    216    /**
    217     * Convert a 1970-epoch day number to proleptic Gregorian year.
    218     * @param day 1970-epoch day
    219     * @param status error code.
    220     * @return year.
    221     */
    222    static int32_t dayToYear(int32_t day, UErrorCode& status);
    223    /**
    224     * Convert a 1970-epoch day number to proleptic Gregorian year.
    225     * @param day 1970-epoch day
    226     * @param doy output parameter to receive day-of-year (1-based)
    227     * @param status error code.
    228     * @return year.
    229     */
    230    static int32_t dayToYear(int32_t day, int16_t& doy, UErrorCode& status);
    231 
    232    /**
    233     * Convert a 1970-epoch milliseconds to proleptic Gregorian year,
    234     * month, day-of-month, and day-of-week, day of year and millis-in-day.
    235     * @param time 1970-epoch milliseconds
    236     * @param year output parameter to receive year
    237     * @param month output parameter to receive month (0-based, 0==Jan)
    238     * @param dom output parameter to receive day-of-month (1-based)
    239     * @param dow output parameter to receive day-of-week (1-based, 1==Sun)
    240     * @param doy output parameter to receive day-of-year (1-based)
    241     * @param mid output parameter to receive millis-in-day
    242     * @param status error code.
    243     */
    244    static void timeToFields(UDate time, int32_t& year, int8_t& month,
    245                            int8_t& dom, int8_t& dow, int16_t& doy, int32_t& mid, UErrorCode& status);
    246 
    247    /**
    248     * Convert a 1970-epoch milliseconds to proleptic Gregorian year,
    249     * month, day-of-month, and day-of-week, day of year and millis-in-day.
    250     * @param time 1970-epoch milliseconds
    251     * @param year output parameter to receive year
    252     * @param month output parameter to receive month (0-based, 0==Jan)
    253     * @param dom output parameter to receive day-of-month (1-based)
    254     * @param dow output parameter to receive day-of-week (1-based, 1==Sun)
    255     * @param mid output parameter to receive millis-in-day
    256     * @param status error code.
    257     */
    258    static void timeToFields(UDate time, int32_t& year, int8_t& month,
    259                            int8_t& dom, int8_t& dow, int32_t& mid, UErrorCode& status);
    260 
    261    /**
    262     * Convert a 1970-epoch milliseconds to proleptic Gregorian year,
    263     * month, day-of-month, and day-of-week, day of year and millis-in-day.
    264     * @param time 1970-epoch milliseconds
    265     * @param year output parameter to receive year
    266     * @param month output parameter to receive month (0-based, 0==Jan)
    267     * @param dom output parameter to receive day-of-month (1-based)
    268     * @param mid output parameter to receive millis-in-day
    269     * @param status error code.
    270     */
    271    static void timeToFields(UDate time, int32_t& year, int8_t& month,
    272                            int8_t& dom, int32_t& mid, UErrorCode& status);
    273 
    274    /**
    275     * Convert a 1970-epoch milliseconds to proleptic Gregorian year.
    276     * @param time 1970-epoch milliseconds
    277     * @param status error code.
    278     * @return year.
    279     */
    280    static int32_t timeToYear(UDate time, UErrorCode& status);
    281 
    282    /**
    283     * Return the day of week on the 1970-epoch day
    284     * @param day the 1970-epoch day
    285     * @return the day of week
    286     */
    287    static int32_t dayOfWeek(int32_t day);
    288 
    289    /**
    290     * Returns the ordinal number for the specified day of week within the month.
    291     * The valid return value is 1, 2, 3, 4 or -1.
    292     * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
    293     * @param month 0-based month, with 0==Jan
    294     * @param dom 1-based day of month
    295     * @return The ordinal number for the specified day of week within the month
    296     */
    297    static int32_t dayOfWeekInMonth(int32_t year, int32_t month, int32_t dom);
    298 
    299    /**
    300     * Converts Julian day to time as milliseconds.
    301     * @param julian the given Julian day number.
    302     * @return time as milliseconds.
    303     * @internal
    304     */
    305    static inline double julianDayToMillis(int32_t julian);
    306 
    307    /**
    308     * Converts time as milliseconds to Julian day.
    309     * @param millis the given milliseconds.
    310     * @return the Julian day number.
    311     * @internal
    312     */
    313    static inline int32_t millisToJulianDay(double millis);
    314 
    315    /** 
    316     * Calculates the Gregorian day shift value for an extended year.
    317     * @param eyear Extended year 
    318     * @returns number of days to ADD to Julian in order to convert from J->G
    319     */
    320    static inline int32_t gregorianShift(int32_t eyear);
    321 
    322 private:
    323    static const int16_t DAYS_BEFORE[24];
    324    static const int8_t MONTH_LENGTH[24];
    325 };
    326 
    327 inline double ClockMath::floorDivide(double numerator, double denominator) {
    328    return uprv_floor(numerator / denominator);
    329 }
    330 
    331 inline UBool Grego::isLeapYear(int32_t year) {
    332    // year&0x3 == year%4
    333    return ((year&0x3) == 0) && ((year%100 != 0) || (year%400 == 0));
    334 }
    335 
    336 inline int8_t
    337 Grego::monthLength(int32_t year, int32_t month) {
    338    return MONTH_LENGTH[month + (isLeapYear(year) ? 12 : 0)];
    339 }
    340 
    341 inline int8_t
    342 Grego::previousMonthLength(int y, int m) {
    343  return (m > 0) ? monthLength(y, m-1) : 31;
    344 }
    345 
    346 inline double Grego::julianDayToMillis(int32_t julian)
    347 {
    348  return (static_cast<double>(julian) - kEpochStartAsJulianDay) * kOneDay;
    349 }
    350 
    351 inline int32_t Grego::millisToJulianDay(double millis) {
    352  return static_cast<int32_t>(kEpochStartAsJulianDay + ClockMath::floorDivide(millis, kOneDay));
    353 }
    354 
    355 inline int32_t Grego::gregorianShift(int32_t eyear) {
    356  int64_t y = static_cast<int64_t>(eyear) - 1;
    357  int64_t gregShift = ClockMath::floorDivideInt64(y, 400LL) - ClockMath::floorDivideInt64(y, 100LL) + 2;
    358  return static_cast<int32_t>(gregShift);
    359 }
    360 
    361 #define IMPL_SYSTEM_DEFAULT_CENTURY(T, U) \
    362  /** \
    363   * The system maintains a static default century start date and Year.  They \
    364   * are initialized the first time they are used.  Once the system default \
    365   * century date and year are set, they do not change \
    366   */ \
    367  namespace { \
    368  static UDate           gSystemDefaultCenturyStart       = DBL_MIN; \
    369  static int32_t         gSystemDefaultCenturyStartYear   = -1; \
    370  static icu::UInitOnce  gSystemDefaultCenturyInit        {}; \
    371  static void U_CALLCONV \
    372  initializeSystemDefaultCentury() { \
    373      UErrorCode status = U_ZERO_ERROR; \
    374      T calendar(U, status); \
    375      /* initialize systemDefaultCentury and systemDefaultCenturyYear based */ \
    376      /* on the current time.  They'll be set to 80 years before */ \
    377      /* the current time. */ \
    378      if (U_FAILURE(status)) { \
    379          return; \
    380      } \
    381      calendar.setTime(Calendar::getNow(), status); \
    382      calendar.add(UCAL_YEAR, -80, status); \
    383      gSystemDefaultCenturyStart = calendar.getTime(status); \
    384      gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status); \
    385      /* We have no recourse upon failure unless we want to propagate the */ \
    386      /* failure out. */ \
    387  } \
    388  }  /* namespace */ \
    389  UDate T::defaultCenturyStart() const { \
    390      /* lazy-evaluate systemDefaultCenturyStart */ \
    391      umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); \
    392      return gSystemDefaultCenturyStart; \
    393  }   \
    394  int32_t T::defaultCenturyStartYear() const { \
    395      /* lazy-evaluate systemDefaultCenturyStart */ \
    396      umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); \
    397      return gSystemDefaultCenturyStartYear; \
    398  } \
    399  UBool T::haveDefaultCentury() const { return true; }
    400 
    401 U_NAMESPACE_END
    402 
    403 #endif // !UCONFIG_NO_FORMATTING
    404 #endif // GREGOIMP_H
    405 
    406 //eof