tor-browser

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

indiancal.cpp (9683B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 * Copyright (C) 2003-2014, International Business Machines Corporation
      5 * and others. All Rights Reserved.
      6 ******************************************************************************
      7 *
      8 * File INDIANCAL.CPP
      9 *****************************************************************************
     10 */
     11 
     12 #include "indiancal.h"
     13 #include <stdlib.h>
     14 #if !UCONFIG_NO_FORMATTING
     15 
     16 #include "mutex.h"
     17 #include <float.h>
     18 #include "gregoimp.h" // Math
     19 #include "uhash.h"
     20 
     21 // Debugging
     22 #ifdef U_DEBUG_INDIANCAL
     23 #include <stdio.h>
     24 #include <stdarg.h>
     25 
     26 #endif
     27 
     28 U_NAMESPACE_BEGIN
     29 
     30 // Implementation of the IndianCalendar class
     31 
     32 //-------------------------------------------------------------------------
     33 // Constructors...
     34 //-------------------------------------------------------------------------
     35 
     36 
     37 IndianCalendar* IndianCalendar::clone() const {
     38  return new IndianCalendar(*this);
     39 }
     40 
     41 IndianCalendar::IndianCalendar(const Locale& aLocale, UErrorCode& success)
     42  :   Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
     43 {
     44 }
     45 
     46 IndianCalendar::IndianCalendar(const IndianCalendar& other) : Calendar(other) {
     47 }
     48 
     49 IndianCalendar::~IndianCalendar()
     50 {
     51 }
     52 const char *IndianCalendar::getType() const { 
     53   return "indian";
     54 }
     55  
     56 static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
     57    // Minimum  Greatest     Least   Maximum
     58    //           Minimum   Maximum
     59    {        0,        0,        0,        0}, // ERA
     60    { -5000000, -5000000,  5000000,  5000000}, // YEAR
     61    {        0,        0,       11,       11}, // MONTH
     62    {        1,        1,       52,       53}, // WEEK_OF_YEAR
     63    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
     64    {        1,        1,       30,       31}, // DAY_OF_MONTH
     65    {        1,        1,      365,      366}, // DAY_OF_YEAR
     66    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
     67    {       -1,       -1,        5,        5}, // DAY_OF_WEEK_IN_MONTH
     68    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
     69    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
     70    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
     71    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
     72    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
     73    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
     74    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
     75    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
     76    { -5000000, -5000000,  5000000,  5000000}, // YEAR_WOY
     77    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
     78    { -5000000, -5000000,  5000000,  5000000}, // EXTENDED_YEAR
     79    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
     80    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
     81    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
     82    {        0,        0,       11,       11}, // ORDINAL_MONTH
     83 };
     84 
     85 static const int32_t INDIAN_ERA_START  = 78;
     86 static const int32_t INDIAN_YEAR_START = 80;
     87 
     88 int32_t IndianCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
     89  return LIMITS[field][limitType];
     90 }
     91 
     92 /*
     93 * Determine whether the given gregorian year is a Leap year 
     94 */
     95 static UBool isGregorianLeap(int32_t year)
     96 {
     97    return Grego::isLeapYear(year);
     98 }
     99  
    100 //----------------------------------------------------------------------
    101 // Calendar framework
    102 //----------------------------------------------------------------------
    103 
    104 /*
    105 * Return the length (in days) of the given month.
    106 *
    107 * @param eyear  The year in Saka Era
    108 * @param month  The month(0-based) in Indian calendar
    109 */
    110 int32_t IndianCalendar::handleGetMonthLength(int32_t eyear, int32_t month, UErrorCode& /* status */) const {
    111   if (month < 0 || month > 11) {
    112      eyear += ClockMath::floorDivide(month, 12, &month);
    113   }
    114 
    115   if (isGregorianLeap(eyear + INDIAN_ERA_START) && month == 0) {
    116       return 31;
    117   }
    118 
    119   if (month >= 1 && month <= 5) {
    120       return 31;
    121   }
    122 
    123   return 30;
    124 }
    125 
    126 /*
    127 * Return the number of days in the given Indian year
    128 *
    129 * @param eyear The year in Saka Era.
    130 */
    131 int32_t IndianCalendar::handleGetYearLength(int32_t eyear, UErrorCode& status) const {
    132    if (U_FAILURE(status)) return 0;
    133    return isGregorianLeap(eyear + INDIAN_ERA_START) ? 366 : 365;
    134 }
    135 /*
    136 * Returns the Julian Day corresponding to gregorian date
    137 *
    138 * @param year The Gregorian year
    139 * @param month The month in Gregorian Year, 0 based.
    140 * @param date The date in Gregorian day in month
    141 */
    142 static double gregorianToJD(int32_t year, int32_t month, int32_t date) {
    143   return Grego::fieldsToDay(year, month, date) + kEpochStartAsJulianDay - 0.5;
    144 }
    145 
    146   
    147 //-------------------------------------------------------------------------
    148 // Functions for converting from field values to milliseconds....
    149 //-------------------------------------------------------------------------
    150 static double IndianToJD(int32_t year, int32_t month, int32_t date) {
    151   int32_t leapMonth, gyear, m;
    152   double start, jd;
    153 
    154   gyear = year + INDIAN_ERA_START;
    155 
    156 
    157   if(isGregorianLeap(gyear)) {
    158      leapMonth = 31;
    159      start = gregorianToJD(gyear, 2 /* The third month in 0 based month */, 21);
    160   } 
    161   else {
    162      leapMonth = 30;
    163      start = gregorianToJD(gyear, 2 /* The third month in 0 based month */, 22);
    164   }
    165 
    166   if (month == 1) {
    167      jd = start + (date - 1);
    168   } else {
    169      jd = start + leapMonth;
    170      m = month - 2;
    171 
    172      //m = Math.min(m, 5);
    173      if (m > 5) {
    174          m = 5;
    175      }
    176 
    177      jd += m * 31;
    178 
    179      if (month >= 8) {
    180         m = month - 7;
    181         jd += m * 30;
    182      }
    183      jd += date - 1;
    184   }
    185 
    186   return jd;
    187 }
    188 
    189 /*
    190 * Return JD of start of given month/year of Indian Calendar
    191 * @param eyear The year in Indian Calendar measured from Saka Era (78 AD).
    192 * @param month The month in Indian calendar
    193 */
    194 int64_t IndianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool /* useMonth */, UErrorCode& status) const {
    195   if (U_FAILURE(status)) {
    196       return 0;
    197   }
    198 
    199   //month is 0 based; converting it to 1-based 
    200   int32_t imonth;
    201 
    202    // If the month is out of range, adjust it into range, and adjust the extended year accordingly
    203   if (month < 0 || month > 11) {
    204      if (uprv_add32_overflow(eyear, ClockMath::floorDivide(month, 12, &month), &eyear)) {
    205          status = U_ILLEGAL_ARGUMENT_ERROR;
    206          return 0;
    207      }
    208   }
    209 
    210   if(month == 12){
    211       imonth = 1;
    212   } else {
    213       imonth = month + 1; 
    214   }
    215   
    216   int64_t jd = IndianToJD(eyear ,imonth, 1);
    217 
    218   return jd;
    219 }
    220 
    221 //-------------------------------------------------------------------------
    222 // Functions for converting from milliseconds to field values
    223 //-------------------------------------------------------------------------
    224 
    225 int32_t IndianCalendar::handleGetExtendedYear(UErrorCode& status) {
    226    if (U_FAILURE(status)) {
    227        return 0;
    228    }
    229    int32_t year;
    230 
    231    if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
    232        year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
    233    } else {
    234        year = internalGet(UCAL_YEAR, 1); // Default to year 1
    235    }
    236 
    237    return year;
    238 }
    239 
    240 /*
    241 * Override Calendar to compute several fields specific to the Indian
    242 * calendar system.  These are:
    243 *
    244 * <ul><li>ERA
    245 * <li>YEAR
    246 * <li>MONTH
    247 * <li>DAY_OF_MONTH
    248 * <li>EXTENDED_YEAR</ul>
    249 * 
    250 * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
    251 * method is called. The getGregorianXxx() methods return Gregorian
    252 * calendar equivalents for the given Julian day.
    253 */
    254 void IndianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& /* status */) {
    255    double jdAtStartOfGregYear;
    256    int32_t leapMonth, IndianYear, yday, IndianMonth, IndianDayOfMonth, mday;
    257    // Stores gregorian date corresponding to Julian day;
    258    int32_t gregorianYear = getGregorianYear();
    259 
    260    IndianYear = gregorianYear - INDIAN_ERA_START;            // Year in Saka era
    261    jdAtStartOfGregYear = gregorianToJD(gregorianYear, 0, 1); // JD at start of Gregorian year
    262    yday = static_cast<int32_t>(julianDay - jdAtStartOfGregYear); // Day number in Gregorian year (starting from 0)
    263 
    264    if (yday < INDIAN_YEAR_START) {
    265        // Day is at the end of the preceding Saka year
    266        IndianYear -= 1;
    267        leapMonth = isGregorianLeap(gregorianYear - 1) ? 31 : 30; // Days in leapMonth this year, previous Gregorian year
    268        yday += leapMonth + (31 * 5) + (30 * 3) + 10;
    269    } else {
    270        leapMonth = isGregorianLeap(gregorianYear) ? 31 : 30; // Days in leapMonth this year
    271        yday -= INDIAN_YEAR_START;
    272    }
    273 
    274    if (yday < leapMonth) {
    275        IndianMonth = 0;
    276        IndianDayOfMonth = yday + 1;
    277    } else {
    278        mday = yday - leapMonth;
    279        if (mday < (31 * 5)) {
    280            IndianMonth = static_cast<int32_t>(uprv_floor(mday / 31)) + 1;
    281            IndianDayOfMonth = (mday % 31) + 1;
    282        } else {
    283            mday -= 31 * 5;
    284            IndianMonth = static_cast<int32_t>(uprv_floor(mday / 30)) + 6;
    285            IndianDayOfMonth = (mday % 30) + 1;
    286        }
    287   }
    288 
    289   internalSet(UCAL_ERA, 0);
    290   internalSet(UCAL_EXTENDED_YEAR, IndianYear);
    291   internalSet(UCAL_YEAR, IndianYear);
    292   internalSet(UCAL_MONTH, IndianMonth);
    293   internalSet(UCAL_ORDINAL_MONTH, IndianMonth);
    294   internalSet(UCAL_DAY_OF_MONTH, IndianDayOfMonth);
    295   internalSet(UCAL_DAY_OF_YEAR, yday + 1); // yday is 0-based
    296 }
    297 
    298 IMPL_SYSTEM_DEFAULT_CENTURY(IndianCalendar, "@calendar=indian")
    299 
    300 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndianCalendar)
    301 
    302 int32_t IndianCalendar::getRelatedYearDifference() const {
    303    constexpr int32_t kIndianCalendarRelatedYearDifference = 79;
    304    return kIndianCalendarRelatedYearDifference;
    305 }
    306 
    307 U_NAMESPACE_END
    308 
    309 #endif