LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - hebrwcal.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 194 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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-2016, International Business Machines Corporation
       6             : * and others. All Rights Reserved.
       7             : ******************************************************************************
       8             : *
       9             : * File HEBRWCAL.CPP
      10             : *
      11             : * Modification History:
      12             : *
      13             : *   Date        Name        Description
      14             : *   12/03/2003  srl         ported from java HebrewCalendar
      15             : *****************************************************************************
      16             : */
      17             : 
      18             : #include "hebrwcal.h"
      19             : 
      20             : #if !UCONFIG_NO_FORMATTING
      21             : 
      22             : #include "cmemory.h"
      23             : #include "umutex.h"
      24             : #include <float.h>
      25             : #include "gregoimp.h" // Math
      26             : #include "astro.h" // CalendarAstronomer
      27             : #include "uhash.h"
      28             : #include "ucln_in.h"
      29             : 
      30             : // Hebrew Calendar implementation
      31             : 
      32             : /**
      33             : * The absolute date, in milliseconds since 1/1/1970 AD, Gregorian,
      34             : * of the start of the Hebrew calendar.  In order to keep this calendar's
      35             : * time of day in sync with that of the Gregorian calendar, we use
      36             : * midnight, rather than sunset the day before.
      37             : */
      38             : //static const double EPOCH_MILLIS = -180799862400000.; // 1/1/1 HY
      39             : 
      40             : static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
      41             :     // Minimum  Greatest    Least  Maximum
      42             :     //           Minimum  Maximum
      43             :     {        0,        0,        0,        0}, // ERA
      44             :     { -5000000, -5000000,  5000000,  5000000}, // YEAR
      45             :     {        0,        0,       12,       12}, // MONTH
      46             :     {        1,        1,       51,       56}, // WEEK_OF_YEAR
      47             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
      48             :     {        1,        1,       29,       30}, // DAY_OF_MONTH
      49             :     {        1,        1,      353,      385}, // DAY_OF_YEAR
      50             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
      51             :     {       -1,       -1,        5,        5}, // DAY_OF_WEEK_IN_MONTH
      52             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
      53             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
      54             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
      55             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
      56             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
      57             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
      58             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
      59             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
      60             :     { -5000000, -5000000,  5000000,  5000000}, // YEAR_WOY
      61             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
      62             :     { -5000000, -5000000,  5000000,  5000000}, // EXTENDED_YEAR
      63             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
      64             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
      65             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
      66             : };
      67             : 
      68             : /**
      69             : * The lengths of the Hebrew months.  This is complicated, because there
      70             : * are three different types of years, or six if you count leap years.
      71             : * Due to the rules for postponing the start of the year to avoid having
      72             : * certain holidays fall on the sabbath, the year can end up being three
      73             : * different lengths, called "deficient", "normal", and "complete".
      74             : */
      75             : static const int8_t MONTH_LENGTH[][3] = {
      76             :     // Deficient  Normal     Complete
      77             :     {   30,         30,         30     },           //Tishri
      78             :     {   29,         29,         30     },           //Heshvan
      79             :     {   29,         30,         30     },           //Kislev
      80             :     {   29,         29,         29     },           //Tevet
      81             :     {   30,         30,         30     },           //Shevat
      82             :     {   30,         30,         30     },           //Adar I (leap years only)
      83             :     {   29,         29,         29     },           //Adar
      84             :     {   30,         30,         30     },           //Nisan
      85             :     {   29,         29,         29     },           //Iyar
      86             :     {   30,         30,         30     },           //Sivan
      87             :     {   29,         29,         29     },           //Tammuz
      88             :     {   30,         30,         30     },           //Av
      89             :     {   29,         29,         29     },           //Elul
      90             : };
      91             : 
      92             : /**
      93             : * The cumulative # of days to the end of each month in a non-leap year
      94             : * Although this can be calculated from the MONTH_LENGTH table,
      95             : * keeping it around separately makes some calculations a lot faster
      96             : */
      97             : 
      98             : static const int16_t MONTH_START[][3] = {
      99             :     // Deficient  Normal     Complete
     100             :     {    0,          0,          0  },          // (placeholder)
     101             :     {   30,         30,         30  },          // Tishri
     102             :     {   59,         59,         60  },          // Heshvan
     103             :     {   88,         89,         90  },          // Kislev
     104             :     {  117,        118,        119  },          // Tevet
     105             :     {  147,        148,        149  },          // Shevat
     106             :     {  147,        148,        149  },          // (Adar I placeholder)
     107             :     {  176,        177,        178  },          // Adar
     108             :     {  206,        207,        208  },          // Nisan
     109             :     {  235,        236,        237  },          // Iyar
     110             :     {  265,        266,        267  },          // Sivan
     111             :     {  294,        295,        296  },          // Tammuz
     112             :     {  324,        325,        326  },          // Av
     113             :     {  353,        354,        355  },          // Elul
     114             : };
     115             : 
     116             : /**
     117             : * The cumulative # of days to the end of each month in a leap year
     118             : */
     119             : static const int16_t  LEAP_MONTH_START[][3] = {
     120             :     // Deficient  Normal     Complete
     121             :     {    0,          0,          0  },          // (placeholder)
     122             :     {   30,         30,         30  },          // Tishri
     123             :     {   59,         59,         60  },          // Heshvan
     124             :     {   88,         89,         90  },          // Kislev
     125             :     {  117,        118,        119  },          // Tevet
     126             :     {  147,        148,        149  },          // Shevat
     127             :     {  177,        178,        179  },          // Adar I
     128             :     {  206,        207,        208  },          // Adar II
     129             :     {  236,        237,        238  },          // Nisan
     130             :     {  265,        266,        267  },          // Iyar
     131             :     {  295,        296,        297  },          // Sivan
     132             :     {  324,        325,        326  },          // Tammuz
     133             :     {  354,        355,        356  },          // Av
     134             :     {  383,        384,        385  },          // Elul
     135             : };
     136             : 
     137             : static icu::CalendarCache *gCache =  NULL;
     138             : 
     139             : U_CDECL_BEGIN
     140           0 : static UBool calendar_hebrew_cleanup(void) {
     141           0 :     delete gCache;
     142           0 :     gCache = NULL;
     143           0 :     return TRUE;
     144             : }
     145             : U_CDECL_END
     146             : 
     147             : U_NAMESPACE_BEGIN
     148             : //-------------------------------------------------------------------------
     149             : // Constructors...
     150             : //-------------------------------------------------------------------------
     151             : 
     152             : /**
     153             : * Constructs a default <code>HebrewCalendar</code> using the current time
     154             : * in the default time zone with the default locale.
     155             : * @internal
     156             : */
     157           0 : HebrewCalendar::HebrewCalendar(const Locale& aLocale, UErrorCode& success)
     158           0 : :   Calendar(TimeZone::createDefault(), aLocale, success)
     159             : 
     160             : {
     161           0 :     setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
     162           0 : }
     163             : 
     164             : 
     165           0 : HebrewCalendar::~HebrewCalendar() {
     166           0 : }
     167             : 
     168           0 : const char *HebrewCalendar::getType() const {
     169           0 :     return "hebrew";
     170             : }
     171             : 
     172           0 : Calendar* HebrewCalendar::clone() const {
     173           0 :     return new HebrewCalendar(*this);
     174             : }
     175             : 
     176           0 : HebrewCalendar::HebrewCalendar(const HebrewCalendar& other) : Calendar(other) {
     177           0 : }
     178             : 
     179             : 
     180             : //-------------------------------------------------------------------------
     181             : // Rolling and adding functions overridden from Calendar
     182             : //
     183             : // These methods call through to the default implementation in IBMCalendar
     184             : // for most of the fields and only handle the unusual ones themselves.
     185             : //-------------------------------------------------------------------------
     186             : 
     187             : /**
     188             : * Add a signed amount to a specified field, using this calendar's rules.
     189             : * For example, to add three days to the current date, you can call
     190             : * <code>add(Calendar.DATE, 3)</code>. 
     191             : * <p>
     192             : * When adding to certain fields, the values of other fields may conflict and
     193             : * need to be changed.  For example, when adding one to the {@link #MONTH MONTH} field
     194             : * for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
     195             : * must be adjusted so that the result is "29 Elul 5758" rather than the invalid
     196             : * "30 Elul 5758".
     197             : * <p>
     198             : * This method is able to add to
     199             : * all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
     200             : * and {@link #ZONE_OFFSET ZONE_OFFSET}.
     201             : * <p>
     202             : * <b>Note:</b> You should always use {@link #roll roll} and add rather
     203             : * than attempting to perform arithmetic operations directly on the fields
     204             : * of a <tt>HebrewCalendar</tt>.  Since the {@link #MONTH MONTH} field behaves
     205             : * discontinuously in non-leap years, simple arithmetic can give invalid results.
     206             : * <p>
     207             : * @param field     the time field.
     208             : * @param amount    the amount to add to the field.
     209             : *
     210             : * @exception   IllegalArgumentException if the field is invalid or refers
     211             : *              to a field that cannot be handled by this method.
     212             : * @internal
     213             : */
     214           0 : void HebrewCalendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status)
     215             : {
     216           0 :     if(U_FAILURE(status)) {
     217           0 :         return;
     218             :     }
     219           0 :     switch (field) {
     220             :   case UCAL_MONTH: 
     221             :       {
     222             :           // We can't just do a set(MONTH, get(MONTH) + amount).  The
     223             :           // reason is ADAR_1.  Suppose amount is +2 and we land in
     224             :           // ADAR_1 -- then we have to bump to ADAR_2 aka ADAR.  But
     225             :           // if amount is -2 and we land in ADAR_1, then we have to
     226             :           // bump the other way -- down to SHEVAT.  - Alan 11/00
     227           0 :           int32_t month = get(UCAL_MONTH, status);
     228           0 :           int32_t year = get(UCAL_YEAR, status);
     229             :           UBool acrossAdar1;
     230           0 :           if (amount > 0) {
     231           0 :               acrossAdar1 = (month < ADAR_1); // started before ADAR_1?
     232           0 :               month += amount;
     233             :               for (;;) {
     234           0 :                   if (acrossAdar1 && month>=ADAR_1 && !isLeapYear(year)) {
     235           0 :                       ++month;
     236             :                   }
     237           0 :                   if (month <= ELUL) {
     238           0 :                       break;
     239             :                   }
     240           0 :                   month -= ELUL+1;
     241           0 :                   ++year;
     242           0 :                   acrossAdar1 = TRUE;
     243             :               }
     244             :           } else {
     245           0 :               acrossAdar1 = (month > ADAR_1); // started after ADAR_1?
     246           0 :               month += amount;
     247             :               for (;;) {
     248           0 :                   if (acrossAdar1 && month<=ADAR_1 && !isLeapYear(year)) {
     249           0 :                       --month;
     250             :                   }
     251           0 :                   if (month >= 0) {
     252           0 :                       break;
     253             :                   }
     254           0 :                   month += ELUL+1;
     255           0 :                   --year;
     256           0 :                   acrossAdar1 = TRUE;
     257             :               }
     258             :           }
     259           0 :           set(UCAL_MONTH, month);
     260           0 :           set(UCAL_YEAR, year);
     261           0 :           pinField(UCAL_DAY_OF_MONTH, status);
     262           0 :           break;
     263             :       }
     264             : 
     265             :   default:
     266           0 :       Calendar::add(field, amount, status);
     267           0 :       break;
     268             :     }
     269             : }
     270             : 
     271             : /**
     272             : * @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
     273             : */
     274           0 : void HebrewCalendar::add(EDateFields field, int32_t amount, UErrorCode& status)
     275             : {
     276           0 :     add((UCalendarDateFields)field, amount, status);
     277           0 : }
     278             : 
     279             : /**
     280             : * Rolls (up/down) a specified amount time on the given field.  For
     281             : * example, to roll the current date up by three days, you can call
     282             : * <code>roll(Calendar.DATE, 3)</code>.  If the
     283             : * field is rolled past its maximum allowable value, it will "wrap" back
     284             : * to its minimum and continue rolling.  
     285             : * For example, calling <code>roll(Calendar.DATE, 10)</code>
     286             : * on a Hebrew calendar set to "25 Av 5758" will result in the date "5 Av 5758".
     287             : * <p>
     288             : * When rolling certain fields, the values of other fields may conflict and
     289             : * need to be changed.  For example, when rolling the {@link #MONTH MONTH} field
     290             : * upward by one for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
     291             : * must be adjusted so that the result is "29 Elul 5758" rather than the invalid
     292             : * "30 Elul".
     293             : * <p>
     294             : * This method is able to roll
     295             : * all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
     296             : * and {@link #ZONE_OFFSET ZONE_OFFSET}.  Subclasses may, of course, add support for
     297             : * additional fields in their overrides of <code>roll</code>.
     298             : * <p>
     299             : * <b>Note:</b> You should always use roll and {@link #add add} rather
     300             : * than attempting to perform arithmetic operations directly on the fields
     301             : * of a <tt>HebrewCalendar</tt>.  Since the {@link #MONTH MONTH} field behaves
     302             : * discontinuously in non-leap years, simple arithmetic can give invalid results.
     303             : * <p>
     304             : * @param field     the time field.
     305             : * @param amount    the amount by which the field should be rolled.
     306             : *
     307             : * @exception   IllegalArgumentException if the field is invalid or refers
     308             : *              to a field that cannot be handled by this method.
     309             : * @internal
     310             : */
     311           0 : void HebrewCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)
     312             : {
     313           0 :     if(U_FAILURE(status)) {
     314           0 :         return;
     315             :     }
     316           0 :     switch (field) {
     317             :   case UCAL_MONTH:
     318             :       {
     319           0 :           int32_t month = get(UCAL_MONTH, status);
     320           0 :           int32_t year = get(UCAL_YEAR, status);
     321             : 
     322           0 :           UBool leapYear = isLeapYear(year);
     323           0 :           int32_t yearLength = monthsInYear(year);
     324           0 :           int32_t newMonth = month + (amount % yearLength);
     325             :           //
     326             :           // If it's not a leap year and we're rolling past the missing month
     327             :           // of ADAR_1, we need to roll an extra month to make up for it.
     328             :           //
     329           0 :           if (!leapYear) {
     330           0 :               if (amount > 0 && month < ADAR_1 && newMonth >= ADAR_1) {
     331           0 :                   newMonth++;
     332           0 :               } else if (amount < 0 && month > ADAR_1 && newMonth <= ADAR_1) {
     333           0 :                   newMonth--;
     334             :               }
     335             :           }
     336           0 :           set(UCAL_MONTH, (newMonth + 13) % 13);
     337           0 :           pinField(UCAL_DAY_OF_MONTH, status);
     338           0 :           return;
     339             :       }
     340             :   default:
     341           0 :       Calendar::roll(field, amount, status);
     342             :     }
     343             : }
     344             : 
     345           0 : void HebrewCalendar::roll(EDateFields field, int32_t amount, UErrorCode& status) {
     346           0 :     roll((UCalendarDateFields)field, amount, status);
     347           0 : }
     348             : 
     349             : //-------------------------------------------------------------------------
     350             : // Support methods
     351             : //-------------------------------------------------------------------------
     352             : 
     353             : // Hebrew date calculations are performed in terms of days, hours, and
     354             : // "parts" (or halakim), which are 1/1080 of an hour, or 3 1/3 seconds.
     355             : static const int32_t HOUR_PARTS = 1080;
     356             : static const int32_t DAY_PARTS  = 24*HOUR_PARTS;
     357             : 
     358             : // An approximate value for the length of a lunar month.
     359             : // It is used to calculate the approximate year and month of a given
     360             : // absolute date.
     361             : static const int32_t  MONTH_DAYS = 29;
     362             : static const int32_t MONTH_FRACT = 12*HOUR_PARTS + 793;
     363             : static const int32_t MONTH_PARTS = MONTH_DAYS*DAY_PARTS + MONTH_FRACT;
     364             : 
     365             : // The time of the new moon (in parts) on 1 Tishri, year 1 (the epoch)
     366             : // counting from noon on the day before.  BAHARAD is an abbreviation of
     367             : // Bet (Monday), Hey (5 hours from sunset), Resh-Daled (204).
     368             : static const int32_t BAHARAD = 11*HOUR_PARTS + 204;
     369             : 
     370             : /**
     371             : * Finds the day # of the first day in the given Hebrew year.
     372             : * To do this, we want to calculate the time of the Tishri 1 new moon
     373             : * in that year.
     374             : * <p>
     375             : * The algorithm here is similar to ones described in a number of
     376             : * references, including:
     377             : * <ul>
     378             : * <li>"Calendrical Calculations", by Nachum Dershowitz & Edward Reingold,
     379             : *     Cambridge University Press, 1997, pages 85-91.
     380             : *
     381             : * <li>Hebrew Calendar Science and Myths,
     382             : *     <a href="http://www.geocities.com/Athens/1584/">
     383             : *     http://www.geocities.com/Athens/1584/</a>
     384             : *
     385             : * <li>The Calendar FAQ,
     386             : *      <a href="http://www.faqs.org/faqs/calendars/faq/">
     387             : *      http://www.faqs.org/faqs/calendars/faq/</a>
     388             : * </ul>
     389             : */
     390           0 : int32_t HebrewCalendar::startOfYear(int32_t year, UErrorCode &status)
     391             : {
     392           0 :     ucln_i18n_registerCleanup(UCLN_I18N_HEBREW_CALENDAR, calendar_hebrew_cleanup);
     393           0 :     int32_t day = CalendarCache::get(&gCache, year, status);
     394             : 
     395           0 :     if (day == 0) {
     396           0 :         int32_t months = (235 * year - 234) / 19;           // # of months before year
     397             : 
     398           0 :         int64_t frac = (int64_t)months * MONTH_FRACT + BAHARAD;  // Fractional part of day #
     399           0 :         day  = months * 29 + (int32_t)(frac / DAY_PARTS);        // Whole # part of calculation
     400           0 :         frac = frac % DAY_PARTS;                        // Time of day
     401             : 
     402           0 :         int32_t wd = (day % 7);                        // Day of week (0 == Monday)
     403             : 
     404           0 :         if (wd == 2 || wd == 4 || wd == 6) {
     405             :             // If the 1st is on Sun, Wed, or Fri, postpone to the next day
     406           0 :             day += 1;
     407           0 :             wd = (day % 7);
     408             :         }
     409           0 :         if (wd == 1 && frac > 15*HOUR_PARTS+204 && !isLeapYear(year) ) {
     410             :             // If the new moon falls after 3:11:20am (15h204p from the previous noon)
     411             :             // on a Tuesday and it is not a leap year, postpone by 2 days.
     412             :             // This prevents 356-day years.
     413           0 :             day += 2;
     414             :         }
     415           0 :         else if (wd == 0 && frac > 21*HOUR_PARTS+589 && isLeapYear(year-1) ) {
     416             :             // If the new moon falls after 9:32:43 1/3am (21h589p from yesterday noon)
     417             :             // on a Monday and *last* year was a leap year, postpone by 1 day.
     418             :             // Prevents 382-day years.
     419           0 :             day += 1;
     420             :         }
     421           0 :         CalendarCache::put(&gCache, year, day, status);
     422             :     }
     423           0 :     return day;
     424             : }
     425             : 
     426             : /**
     427             : * Find the day of the week for a given day
     428             : *
     429             : * @param day   The # of days since the start of the Hebrew calendar,
     430             : *              1-based (i.e. 1/1/1 AM is day 1).
     431             : */
     432           0 : int32_t HebrewCalendar::absoluteDayToDayOfWeek(int32_t day)
     433             : {
     434             :     // We know that 1/1/1 AM is a Monday, which makes the math easy...
     435           0 :     return (day % 7) + 1;
     436             : }
     437             : 
     438             : /**
     439             : * Returns the the type of a given year.
     440             : *  0   "Deficient" year with 353 or 383 days
     441             : *  1   "Normal"    year with 354 or 384 days
     442             : *  2   "Complete"  year with 355 or 385 days
     443             : */
     444           0 : int32_t HebrewCalendar::yearType(int32_t year) const
     445             : {
     446           0 :     int32_t yearLength = handleGetYearLength(year);
     447             : 
     448           0 :     if (yearLength > 380) {
     449           0 :         yearLength -= 30;        // Subtract length of leap month.
     450             :     }
     451             : 
     452           0 :     int type = 0;
     453             : 
     454           0 :     switch (yearLength) {
     455             :   case 353:
     456           0 :       type = 0; break;
     457             :   case 354:
     458           0 :       type = 1; break;
     459             :   case 355:
     460           0 :       type = 2; break;
     461             :   default:
     462             :       //throw new RuntimeException("Illegal year length " + yearLength + " in year " + year);
     463           0 :       type = 1;
     464             :     }
     465           0 :     return type;
     466             : }
     467             : 
     468             : /**
     469             : * Determine whether a given Hebrew year is a leap year
     470             : *
     471             : * The rule here is that if (year % 19) == 0, 3, 6, 8, 11, 14, or 17.
     472             : * The formula below performs the same test, believe it or not.
     473             : */
     474           0 : UBool HebrewCalendar::isLeapYear(int32_t year) {
     475             :     //return (year * 12 + 17) % 19 >= 12;
     476           0 :     int32_t x = (year*12 + 17) % 19;
     477           0 :     return x >= ((x < 0) ? -7 : 12);
     478             : }
     479             : 
     480           0 : int32_t HebrewCalendar::monthsInYear(int32_t year) {
     481           0 :     return isLeapYear(year) ? 13 : 12;
     482             : }
     483             : 
     484             : //-------------------------------------------------------------------------
     485             : // Calendar framework
     486             : //-------------------------------------------------------------------------
     487             : 
     488             : /**
     489             : * @internal
     490             : */
     491           0 : int32_t HebrewCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
     492           0 :     return LIMITS[field][limitType];
     493             : }
     494             : 
     495             : /**
     496             : * Returns the length of the given month in the given year
     497             : * @internal
     498             : */
     499           0 : int32_t HebrewCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
     500             :     // Resolve out-of-range months.  This is necessary in order to
     501             :     // obtain the correct year.  We correct to
     502             :     // a 12- or 13-month year (add/subtract 12 or 13, depending
     503             :     // on the year) but since we _always_ number from 0..12, and
     504             :     // the leap year determines whether or not month 5 (Adar 1)
     505             :     // is present, we allow 0..12 in any given year.
     506           0 :     while (month < 0) {
     507           0 :         month += monthsInYear(--extendedYear);
     508             :     }
     509             :     // Careful: allow 0..12 in all years
     510           0 :     while (month > 12) {
     511           0 :         month -= monthsInYear(extendedYear++);
     512             :     }
     513             : 
     514           0 :     switch (month) {
     515             :     case HESHVAN:
     516             :     case KISLEV:
     517             :       // These two month lengths can vary
     518           0 :       return MONTH_LENGTH[month][yearType(extendedYear)];
     519             : 
     520             :     default:
     521             :       // The rest are a fixed length
     522           0 :       return MONTH_LENGTH[month][0];
     523             :     }
     524             : }
     525             : 
     526             : /**
     527             : * Returns the number of days in the given Hebrew year
     528             : * @internal
     529             : */
     530           0 : int32_t HebrewCalendar::handleGetYearLength(int32_t eyear) const {
     531           0 :     UErrorCode status = U_ZERO_ERROR;
     532           0 :     return startOfYear(eyear+1, status) - startOfYear(eyear, status);
     533             : }
     534             : 
     535           0 : void HebrewCalendar::validateField(UCalendarDateFields field, UErrorCode &status) {
     536           0 :     if (field == UCAL_MONTH && !isLeapYear(handleGetExtendedYear()) && internalGet(UCAL_MONTH) == ADAR_1) {
     537           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
     538           0 :         return;
     539             :     }
     540           0 :     Calendar::validateField(field, status);
     541             : }
     542             : //-------------------------------------------------------------------------
     543             : // Functions for converting from milliseconds to field values
     544             : //-------------------------------------------------------------------------
     545             : 
     546             : /**
     547             : * Subclasses may override this method to compute several fields
     548             : * specific to each calendar system.  These are:
     549             : *
     550             : * <ul><li>ERA
     551             : * <li>YEAR
     552             : * <li>MONTH
     553             : * <li>DAY_OF_MONTH
     554             : * <li>DAY_OF_YEAR
     555             : * <li>EXTENDED_YEAR</ul>
     556             : * 
     557             : * Subclasses can refer to the DAY_OF_WEEK and DOW_LOCAL fields,
     558             : * which will be set when this method is called.  Subclasses can
     559             : * also call the getGregorianXxx() methods to obtain Gregorian
     560             : * calendar equivalents for the given Julian day.
     561             : *
     562             : * <p>In addition, subclasses should compute any subclass-specific
     563             : * fields, that is, fields from BASE_FIELD_COUNT to
     564             : * getFieldCount() - 1.
     565             : * @internal
     566             : */
     567           0 : void HebrewCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
     568           0 :     int32_t d = julianDay - 347997;
     569           0 :     double m = ((d * (double)DAY_PARTS)/ (double) MONTH_PARTS);         // Months (approx)
     570           0 :     int32_t year = (int32_t)( ((19. * m + 234.) / 235.) + 1.);     // Years (approx)
     571           0 :     int32_t ys  = startOfYear(year, status);                   // 1st day of year
     572           0 :     int32_t dayOfYear = (d - ys);
     573             : 
     574             :     // Because of the postponement rules, it's possible to guess wrong.  Fix it.
     575           0 :     while (dayOfYear < 1) {
     576           0 :         year--;
     577           0 :         ys  = startOfYear(year, status);
     578           0 :         dayOfYear = (d - ys);
     579             :     }
     580             : 
     581             :     // Now figure out which month we're in, and the date within that month
     582           0 :     int32_t type = yearType(year);
     583           0 :     UBool isLeap = isLeapYear(year);
     584             : 
     585           0 :     int32_t month = 0;
     586           0 :     int32_t momax = UPRV_LENGTHOF(MONTH_START);
     587           0 :     while (month < momax && dayOfYear > (  isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type] ) ) {
     588           0 :         month++;
     589             :     }
     590           0 :     if (month >= momax || month<=0) {
     591             :         // TODO: I found dayOfYear could be out of range when
     592             :         // a large value is set to julianDay.  I patched startOfYear
     593             :         // to reduce the chace, but it could be still reproduced either
     594             :         // by startOfYear or other places.  For now, we check
     595             :         // the month is in valid range to avoid out of array index
     596             :         // access problem here.  However, we need to carefully review
     597             :         // the calendar implementation to check the extreme limit of
     598             :         // each calendar field and the code works well for any values
     599             :         // in the valid value range.  -yoshito
     600           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
     601           0 :         return;
     602             :     }
     603           0 :     month--;
     604           0 :     int dayOfMonth = dayOfYear - (isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type]);
     605             : 
     606           0 :     internalSet(UCAL_ERA, 0);
     607           0 :     internalSet(UCAL_YEAR, year);
     608           0 :     internalSet(UCAL_EXTENDED_YEAR, year);
     609           0 :     internalSet(UCAL_MONTH, month);
     610           0 :     internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
     611           0 :     internalSet(UCAL_DAY_OF_YEAR, dayOfYear);       
     612             : }
     613             : 
     614             : //-------------------------------------------------------------------------
     615             : // Functions for converting from field values to milliseconds
     616             : //-------------------------------------------------------------------------
     617             : 
     618             : /**
     619             : * @internal
     620             : */
     621           0 : int32_t HebrewCalendar::handleGetExtendedYear() {
     622             :     int32_t year;
     623           0 :     if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
     624           0 :         year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
     625             :     } else {
     626           0 :         year = internalGet(UCAL_YEAR, 1); // Default to year 1
     627             :     }
     628           0 :     return year;
     629             : }
     630             : 
     631             : /**
     632             : * Return JD of start of given month/year.
     633             : * @internal
     634             : */
     635           0 : int32_t HebrewCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool /*useMonth*/) const {
     636           0 :     UErrorCode status = U_ZERO_ERROR;
     637             :     // Resolve out-of-range months.  This is necessary in order to
     638             :     // obtain the correct year.  We correct to
     639             :     // a 12- or 13-month year (add/subtract 12 or 13, depending
     640             :     // on the year) but since we _always_ number from 0..12, and
     641             :     // the leap year determines whether or not month 5 (Adar 1)
     642             :     // is present, we allow 0..12 in any given year.
     643           0 :     while (month < 0) {
     644           0 :         month += monthsInYear(--eyear);
     645             :     }
     646             :     // Careful: allow 0..12 in all years
     647           0 :     while (month > 12) {
     648           0 :         month -= monthsInYear(eyear++);
     649             :     }
     650             : 
     651           0 :     int32_t day = startOfYear(eyear, status);
     652             : 
     653           0 :     if(U_FAILURE(status)) {
     654           0 :         return 0;
     655             :     }
     656             : 
     657           0 :     if (month != 0) {
     658           0 :         if (isLeapYear(eyear)) {
     659           0 :             day += LEAP_MONTH_START[month][yearType(eyear)];
     660             :         } else {
     661           0 :             day += MONTH_START[month][yearType(eyear)];
     662             :         }
     663             :     }
     664             : 
     665           0 :     return (int) (day + 347997);
     666             : }
     667             : 
     668             : UBool
     669           0 : HebrewCalendar::inDaylightTime(UErrorCode& status) const
     670             : {
     671             :     // copied from GregorianCalendar
     672           0 :     if (U_FAILURE(status) || !getTimeZone().useDaylightTime()) 
     673           0 :         return FALSE;
     674             : 
     675             :     // Force an update of the state of the Calendar.
     676           0 :     ((HebrewCalendar*)this)->complete(status); // cast away const
     677             : 
     678           0 :     return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
     679             : }
     680             : 
     681             : /**
     682             :  * The system maintains a static default century start date and Year.  They are
     683             :  * initialized the first time they are used.  Once the system default century date 
     684             :  * and year are set, they do not change.
     685             :  */
     686             : static UDate           gSystemDefaultCenturyStart       = DBL_MIN;
     687             : static int32_t         gSystemDefaultCenturyStartYear   = -1;
     688             : static icu::UInitOnce  gSystemDefaultCenturyInit        = U_INITONCE_INITIALIZER;
     689             : 
     690           0 : UBool HebrewCalendar::haveDefaultCentury() const
     691             : {
     692           0 :     return TRUE;
     693             : }
     694             : 
     695           0 : static void U_CALLCONV initializeSystemDefaultCentury()
     696             : {
     697             :     // initialize systemDefaultCentury and systemDefaultCenturyYear based
     698             :     // on the current time.  They'll be set to 80 years before
     699             :     // the current time.
     700           0 :     UErrorCode status = U_ZERO_ERROR;
     701           0 :     HebrewCalendar calendar(Locale("@calendar=hebrew"),status);
     702           0 :     if (U_SUCCESS(status)) {
     703           0 :         calendar.setTime(Calendar::getNow(), status);
     704           0 :         calendar.add(UCAL_YEAR, -80, status);
     705             : 
     706           0 :         gSystemDefaultCenturyStart = calendar.getTime(status);
     707           0 :         gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
     708             :     }
     709             :     // We have no recourse upon failure unless we want to propagate the failure
     710             :     // out.
     711           0 : }
     712             : 
     713             : 
     714           0 : UDate HebrewCalendar::defaultCenturyStart() const {
     715             :     // lazy-evaluate systemDefaultCenturyStart
     716           0 :     umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
     717           0 :     return gSystemDefaultCenturyStart;
     718             : }
     719             : 
     720           0 : int32_t HebrewCalendar::defaultCenturyStartYear() const {
     721             :     // lazy-evaluate systemDefaultCenturyStartYear
     722           0 :     umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
     723           0 :     return gSystemDefaultCenturyStartYear;
     724             : }
     725             : 
     726             : 
     727           0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(HebrewCalendar)
     728             : 
     729             : U_NAMESPACE_END
     730             : 
     731             : #endif // UCONFIG_NO_FORMATTING
     732             : 

Generated by: LCOV version 1.13