12e5b6d6dSopenharmony_ci// © 2016 and later: Unicode, Inc. and others.
22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
32e5b6d6dSopenharmony_ci/*
42e5b6d6dSopenharmony_ci******************************************************************************
52e5b6d6dSopenharmony_ci* Copyright (C) 2003-2016, International Business Machines Corporation
62e5b6d6dSopenharmony_ci* and others. All Rights Reserved.
72e5b6d6dSopenharmony_ci******************************************************************************
82e5b6d6dSopenharmony_ci*
92e5b6d6dSopenharmony_ci* File HEBRWCAL.CPP
102e5b6d6dSopenharmony_ci*
112e5b6d6dSopenharmony_ci* Modification History:
122e5b6d6dSopenharmony_ci*
132e5b6d6dSopenharmony_ci*   Date        Name        Description
142e5b6d6dSopenharmony_ci*   12/03/2003  srl         ported from java HebrewCalendar
152e5b6d6dSopenharmony_ci*****************************************************************************
162e5b6d6dSopenharmony_ci*/
172e5b6d6dSopenharmony_ci
182e5b6d6dSopenharmony_ci#include "hebrwcal.h"
192e5b6d6dSopenharmony_ci
202e5b6d6dSopenharmony_ci#if !UCONFIG_NO_FORMATTING
212e5b6d6dSopenharmony_ci
222e5b6d6dSopenharmony_ci#include "cmemory.h"
232e5b6d6dSopenharmony_ci#include "umutex.h"
242e5b6d6dSopenharmony_ci#include <float.h>
252e5b6d6dSopenharmony_ci#include "gregoimp.h" // Math
262e5b6d6dSopenharmony_ci#include "astro.h" // CalendarAstronomer
272e5b6d6dSopenharmony_ci#include "uhash.h"
282e5b6d6dSopenharmony_ci#include "ucln_in.h"
292e5b6d6dSopenharmony_ci
302e5b6d6dSopenharmony_ci// Hebrew Calendar implementation
312e5b6d6dSopenharmony_ci
322e5b6d6dSopenharmony_ci/**
332e5b6d6dSopenharmony_ci* The absolute date, in milliseconds since 1/1/1970 AD, Gregorian,
342e5b6d6dSopenharmony_ci* of the start of the Hebrew calendar.  In order to keep this calendar's
352e5b6d6dSopenharmony_ci* time of day in sync with that of the Gregorian calendar, we use
362e5b6d6dSopenharmony_ci* midnight, rather than sunset the day before.
372e5b6d6dSopenharmony_ci*/
382e5b6d6dSopenharmony_ci//static const double EPOCH_MILLIS = -180799862400000.; // 1/1/1 HY
392e5b6d6dSopenharmony_ci
402e5b6d6dSopenharmony_cistatic const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
412e5b6d6dSopenharmony_ci    // Minimum  Greatest    Least  Maximum
422e5b6d6dSopenharmony_ci    //           Minimum  Maximum
432e5b6d6dSopenharmony_ci    {        0,        0,        0,        0}, // ERA
442e5b6d6dSopenharmony_ci    { -5000000, -5000000,  5000000,  5000000}, // YEAR
452e5b6d6dSopenharmony_ci    {        0,        0,       12,       12}, // MONTH
462e5b6d6dSopenharmony_ci    {        1,        1,       51,       56}, // WEEK_OF_YEAR
472e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
482e5b6d6dSopenharmony_ci    {        1,        1,       29,       30}, // DAY_OF_MONTH
492e5b6d6dSopenharmony_ci    {        1,        1,      353,      385}, // DAY_OF_YEAR
502e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
512e5b6d6dSopenharmony_ci    {       -1,       -1,        5,        5}, // DAY_OF_WEEK_IN_MONTH
522e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
532e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
542e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
552e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
562e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
572e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
582e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
592e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
602e5b6d6dSopenharmony_ci    { -5000000, -5000000,  5000000,  5000000}, // YEAR_WOY
612e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
622e5b6d6dSopenharmony_ci    { -5000000, -5000000,  5000000,  5000000}, // EXTENDED_YEAR
632e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
642e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
652e5b6d6dSopenharmony_ci    {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
662e5b6d6dSopenharmony_ci};
672e5b6d6dSopenharmony_ci
682e5b6d6dSopenharmony_ci/**
692e5b6d6dSopenharmony_ci* The lengths of the Hebrew months.  This is complicated, because there
702e5b6d6dSopenharmony_ci* are three different types of years, or six if you count leap years.
712e5b6d6dSopenharmony_ci* Due to the rules for postponing the start of the year to avoid having
722e5b6d6dSopenharmony_ci* certain holidays fall on the sabbath, the year can end up being three
732e5b6d6dSopenharmony_ci* different lengths, called "deficient", "normal", and "complete".
742e5b6d6dSopenharmony_ci*/
752e5b6d6dSopenharmony_cistatic const int8_t MONTH_LENGTH[][3] = {
762e5b6d6dSopenharmony_ci    // Deficient  Normal     Complete
772e5b6d6dSopenharmony_ci    {   30,         30,         30     },           //Tishri
782e5b6d6dSopenharmony_ci    {   29,         29,         30     },           //Heshvan
792e5b6d6dSopenharmony_ci    {   29,         30,         30     },           //Kislev
802e5b6d6dSopenharmony_ci    {   29,         29,         29     },           //Tevet
812e5b6d6dSopenharmony_ci    {   30,         30,         30     },           //Shevat
822e5b6d6dSopenharmony_ci    {   30,         30,         30     },           //Adar I (leap years only)
832e5b6d6dSopenharmony_ci    {   29,         29,         29     },           //Adar
842e5b6d6dSopenharmony_ci    {   30,         30,         30     },           //Nisan
852e5b6d6dSopenharmony_ci    {   29,         29,         29     },           //Iyar
862e5b6d6dSopenharmony_ci    {   30,         30,         30     },           //Sivan
872e5b6d6dSopenharmony_ci    {   29,         29,         29     },           //Tammuz
882e5b6d6dSopenharmony_ci    {   30,         30,         30     },           //Av
892e5b6d6dSopenharmony_ci    {   29,         29,         29     },           //Elul
902e5b6d6dSopenharmony_ci};
912e5b6d6dSopenharmony_ci
922e5b6d6dSopenharmony_ci/**
932e5b6d6dSopenharmony_ci* The cumulative # of days to the end of each month in a non-leap year
942e5b6d6dSopenharmony_ci* Although this can be calculated from the MONTH_LENGTH table,
952e5b6d6dSopenharmony_ci* keeping it around separately makes some calculations a lot faster
962e5b6d6dSopenharmony_ci*/
972e5b6d6dSopenharmony_ci
982e5b6d6dSopenharmony_cistatic const int16_t MONTH_START[][3] = {
992e5b6d6dSopenharmony_ci    // Deficient  Normal     Complete
1002e5b6d6dSopenharmony_ci    {    0,          0,          0  },          // (placeholder)
1012e5b6d6dSopenharmony_ci    {   30,         30,         30  },          // Tishri
1022e5b6d6dSopenharmony_ci    {   59,         59,         60  },          // Heshvan
1032e5b6d6dSopenharmony_ci    {   88,         89,         90  },          // Kislev
1042e5b6d6dSopenharmony_ci    {  117,        118,        119  },          // Tevet
1052e5b6d6dSopenharmony_ci    {  147,        148,        149  },          // Shevat
1062e5b6d6dSopenharmony_ci    {  147,        148,        149  },          // (Adar I placeholder)
1072e5b6d6dSopenharmony_ci    {  176,        177,        178  },          // Adar
1082e5b6d6dSopenharmony_ci    {  206,        207,        208  },          // Nisan
1092e5b6d6dSopenharmony_ci    {  235,        236,        237  },          // Iyar
1102e5b6d6dSopenharmony_ci    {  265,        266,        267  },          // Sivan
1112e5b6d6dSopenharmony_ci    {  294,        295,        296  },          // Tammuz
1122e5b6d6dSopenharmony_ci    {  324,        325,        326  },          // Av
1132e5b6d6dSopenharmony_ci    {  353,        354,        355  },          // Elul
1142e5b6d6dSopenharmony_ci};
1152e5b6d6dSopenharmony_ci
1162e5b6d6dSopenharmony_ci/**
1172e5b6d6dSopenharmony_ci* The cumulative # of days to the end of each month in a leap year
1182e5b6d6dSopenharmony_ci*/
1192e5b6d6dSopenharmony_cistatic const int16_t  LEAP_MONTH_START[][3] = {
1202e5b6d6dSopenharmony_ci    // Deficient  Normal     Complete
1212e5b6d6dSopenharmony_ci    {    0,          0,          0  },          // (placeholder)
1222e5b6d6dSopenharmony_ci    {   30,         30,         30  },          // Tishri
1232e5b6d6dSopenharmony_ci    {   59,         59,         60  },          // Heshvan
1242e5b6d6dSopenharmony_ci    {   88,         89,         90  },          // Kislev
1252e5b6d6dSopenharmony_ci    {  117,        118,        119  },          // Tevet
1262e5b6d6dSopenharmony_ci    {  147,        148,        149  },          // Shevat
1272e5b6d6dSopenharmony_ci    {  177,        178,        179  },          // Adar I
1282e5b6d6dSopenharmony_ci    {  206,        207,        208  },          // Adar II
1292e5b6d6dSopenharmony_ci    {  236,        237,        238  },          // Nisan
1302e5b6d6dSopenharmony_ci    {  265,        266,        267  },          // Iyar
1312e5b6d6dSopenharmony_ci    {  295,        296,        297  },          // Sivan
1322e5b6d6dSopenharmony_ci    {  324,        325,        326  },          // Tammuz
1332e5b6d6dSopenharmony_ci    {  354,        355,        356  },          // Av
1342e5b6d6dSopenharmony_ci    {  383,        384,        385  },          // Elul
1352e5b6d6dSopenharmony_ci};
1362e5b6d6dSopenharmony_ci
1372e5b6d6dSopenharmony_cistatic icu::CalendarCache *gCache =  NULL;
1382e5b6d6dSopenharmony_ci
1392e5b6d6dSopenharmony_ciU_CDECL_BEGIN
1402e5b6d6dSopenharmony_cistatic UBool calendar_hebrew_cleanup(void) {
1412e5b6d6dSopenharmony_ci    delete gCache;
1422e5b6d6dSopenharmony_ci    gCache = NULL;
1432e5b6d6dSopenharmony_ci    return true;
1442e5b6d6dSopenharmony_ci}
1452e5b6d6dSopenharmony_ciU_CDECL_END
1462e5b6d6dSopenharmony_ci
1472e5b6d6dSopenharmony_ciU_NAMESPACE_BEGIN
1482e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
1492e5b6d6dSopenharmony_ci// Constructors...
1502e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
1512e5b6d6dSopenharmony_ci
1522e5b6d6dSopenharmony_ci/**
1532e5b6d6dSopenharmony_ci* Constructs a default <code>HebrewCalendar</code> using the current time
1542e5b6d6dSopenharmony_ci* in the default time zone with the default locale.
1552e5b6d6dSopenharmony_ci* @internal
1562e5b6d6dSopenharmony_ci*/
1572e5b6d6dSopenharmony_ciHebrewCalendar::HebrewCalendar(const Locale& aLocale, UErrorCode& success)
1582e5b6d6dSopenharmony_ci:   Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
1592e5b6d6dSopenharmony_ci
1602e5b6d6dSopenharmony_ci{
1612e5b6d6dSopenharmony_ci    setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
1622e5b6d6dSopenharmony_ci}
1632e5b6d6dSopenharmony_ci
1642e5b6d6dSopenharmony_ci
1652e5b6d6dSopenharmony_ciHebrewCalendar::~HebrewCalendar() {
1662e5b6d6dSopenharmony_ci}
1672e5b6d6dSopenharmony_ci
1682e5b6d6dSopenharmony_ciconst char *HebrewCalendar::getType() const {
1692e5b6d6dSopenharmony_ci    return "hebrew";
1702e5b6d6dSopenharmony_ci}
1712e5b6d6dSopenharmony_ci
1722e5b6d6dSopenharmony_ciHebrewCalendar* HebrewCalendar::clone() const {
1732e5b6d6dSopenharmony_ci    return new HebrewCalendar(*this);
1742e5b6d6dSopenharmony_ci}
1752e5b6d6dSopenharmony_ci
1762e5b6d6dSopenharmony_ciHebrewCalendar::HebrewCalendar(const HebrewCalendar& other) : Calendar(other) {
1772e5b6d6dSopenharmony_ci}
1782e5b6d6dSopenharmony_ci
1792e5b6d6dSopenharmony_ci
1802e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
1812e5b6d6dSopenharmony_ci// Rolling and adding functions overridden from Calendar
1822e5b6d6dSopenharmony_ci//
1832e5b6d6dSopenharmony_ci// These methods call through to the default implementation in IBMCalendar
1842e5b6d6dSopenharmony_ci// for most of the fields and only handle the unusual ones themselves.
1852e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
1862e5b6d6dSopenharmony_ci
1872e5b6d6dSopenharmony_ci/**
1882e5b6d6dSopenharmony_ci* Add a signed amount to a specified field, using this calendar's rules.
1892e5b6d6dSopenharmony_ci* For example, to add three days to the current date, you can call
1902e5b6d6dSopenharmony_ci* <code>add(Calendar.DATE, 3)</code>.
1912e5b6d6dSopenharmony_ci* <p>
1922e5b6d6dSopenharmony_ci* When adding to certain fields, the values of other fields may conflict and
1932e5b6d6dSopenharmony_ci* need to be changed.  For example, when adding one to the {@link #MONTH MONTH} field
1942e5b6d6dSopenharmony_ci* for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
1952e5b6d6dSopenharmony_ci* must be adjusted so that the result is "29 Elul 5758" rather than the invalid
1962e5b6d6dSopenharmony_ci* "30 Elul 5758".
1972e5b6d6dSopenharmony_ci* <p>
1982e5b6d6dSopenharmony_ci* This method is able to add to
1992e5b6d6dSopenharmony_ci* all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
2002e5b6d6dSopenharmony_ci* and {@link #ZONE_OFFSET ZONE_OFFSET}.
2012e5b6d6dSopenharmony_ci* <p>
2022e5b6d6dSopenharmony_ci* <b>Note:</b> You should always use {@link #roll roll} and add rather
2032e5b6d6dSopenharmony_ci* than attempting to perform arithmetic operations directly on the fields
2042e5b6d6dSopenharmony_ci* of a <tt>HebrewCalendar</tt>.  Since the {@link #MONTH MONTH} field behaves
2052e5b6d6dSopenharmony_ci* discontinuously in non-leap years, simple arithmetic can give invalid results.
2062e5b6d6dSopenharmony_ci* <p>
2072e5b6d6dSopenharmony_ci* @param field     the time field.
2082e5b6d6dSopenharmony_ci* @param amount    the amount to add to the field.
2092e5b6d6dSopenharmony_ci*
2102e5b6d6dSopenharmony_ci* @exception   IllegalArgumentException if the field is invalid or refers
2112e5b6d6dSopenharmony_ci*              to a field that cannot be handled by this method.
2122e5b6d6dSopenharmony_ci* @internal
2132e5b6d6dSopenharmony_ci*/
2142e5b6d6dSopenharmony_civoid HebrewCalendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status)
2152e5b6d6dSopenharmony_ci{
2162e5b6d6dSopenharmony_ci    if(U_FAILURE(status)) {
2172e5b6d6dSopenharmony_ci        return;
2182e5b6d6dSopenharmony_ci    }
2192e5b6d6dSopenharmony_ci    switch (field) {
2202e5b6d6dSopenharmony_ci  case UCAL_MONTH:
2212e5b6d6dSopenharmony_ci      {
2222e5b6d6dSopenharmony_ci          // We can't just do a set(MONTH, get(MONTH) + amount).  The
2232e5b6d6dSopenharmony_ci          // reason is ADAR_1.  Suppose amount is +2 and we land in
2242e5b6d6dSopenharmony_ci          // ADAR_1 -- then we have to bump to ADAR_2 aka ADAR.  But
2252e5b6d6dSopenharmony_ci          // if amount is -2 and we land in ADAR_1, then we have to
2262e5b6d6dSopenharmony_ci          // bump the other way -- down to SHEVAT.  - Alan 11/00
2272e5b6d6dSopenharmony_ci          int32_t month = get(UCAL_MONTH, status);
2282e5b6d6dSopenharmony_ci          int32_t year = get(UCAL_YEAR, status);
2292e5b6d6dSopenharmony_ci          UBool acrossAdar1;
2302e5b6d6dSopenharmony_ci          if (amount > 0) {
2312e5b6d6dSopenharmony_ci              acrossAdar1 = (month < ADAR_1); // started before ADAR_1?
2322e5b6d6dSopenharmony_ci              month += amount;
2332e5b6d6dSopenharmony_ci              for (;;) {
2342e5b6d6dSopenharmony_ci                  if (acrossAdar1 && month>=ADAR_1 && !isLeapYear(year)) {
2352e5b6d6dSopenharmony_ci                      ++month;
2362e5b6d6dSopenharmony_ci                  }
2372e5b6d6dSopenharmony_ci                  if (month <= ELUL) {
2382e5b6d6dSopenharmony_ci                      break;
2392e5b6d6dSopenharmony_ci                  }
2402e5b6d6dSopenharmony_ci                  month -= ELUL+1;
2412e5b6d6dSopenharmony_ci                  ++year;
2422e5b6d6dSopenharmony_ci                  acrossAdar1 = true;
2432e5b6d6dSopenharmony_ci              }
2442e5b6d6dSopenharmony_ci          } else {
2452e5b6d6dSopenharmony_ci              acrossAdar1 = (month > ADAR_1); // started after ADAR_1?
2462e5b6d6dSopenharmony_ci              month += amount;
2472e5b6d6dSopenharmony_ci              for (;;) {
2482e5b6d6dSopenharmony_ci                  if (acrossAdar1 && month<=ADAR_1 && !isLeapYear(year)) {
2492e5b6d6dSopenharmony_ci                      --month;
2502e5b6d6dSopenharmony_ci                  }
2512e5b6d6dSopenharmony_ci                  if (month >= 0) {
2522e5b6d6dSopenharmony_ci                      break;
2532e5b6d6dSopenharmony_ci                  }
2542e5b6d6dSopenharmony_ci                  month += ELUL+1;
2552e5b6d6dSopenharmony_ci                  --year;
2562e5b6d6dSopenharmony_ci                  acrossAdar1 = true;
2572e5b6d6dSopenharmony_ci              }
2582e5b6d6dSopenharmony_ci          }
2592e5b6d6dSopenharmony_ci          set(UCAL_MONTH, month);
2602e5b6d6dSopenharmony_ci          set(UCAL_YEAR, year);
2612e5b6d6dSopenharmony_ci          pinField(UCAL_DAY_OF_MONTH, status);
2622e5b6d6dSopenharmony_ci          break;
2632e5b6d6dSopenharmony_ci      }
2642e5b6d6dSopenharmony_ci
2652e5b6d6dSopenharmony_ci  default:
2662e5b6d6dSopenharmony_ci      Calendar::add(field, amount, status);
2672e5b6d6dSopenharmony_ci      break;
2682e5b6d6dSopenharmony_ci    }
2692e5b6d6dSopenharmony_ci}
2702e5b6d6dSopenharmony_ci
2712e5b6d6dSopenharmony_ci/**
2722e5b6d6dSopenharmony_ci* @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
2732e5b6d6dSopenharmony_ci*/
2742e5b6d6dSopenharmony_civoid HebrewCalendar::add(EDateFields field, int32_t amount, UErrorCode& status)
2752e5b6d6dSopenharmony_ci{
2762e5b6d6dSopenharmony_ci    add((UCalendarDateFields)field, amount, status);
2772e5b6d6dSopenharmony_ci}
2782e5b6d6dSopenharmony_ci
2792e5b6d6dSopenharmony_ci/**
2802e5b6d6dSopenharmony_ci* Rolls (up/down) a specified amount time on the given field.  For
2812e5b6d6dSopenharmony_ci* example, to roll the current date up by three days, you can call
2822e5b6d6dSopenharmony_ci* <code>roll(Calendar.DATE, 3)</code>.  If the
2832e5b6d6dSopenharmony_ci* field is rolled past its maximum allowable value, it will "wrap" back
2842e5b6d6dSopenharmony_ci* to its minimum and continue rolling.
2852e5b6d6dSopenharmony_ci* For example, calling <code>roll(Calendar.DATE, 10)</code>
2862e5b6d6dSopenharmony_ci* on a Hebrew calendar set to "25 Av 5758" will result in the date "5 Av 5758".
2872e5b6d6dSopenharmony_ci* <p>
2882e5b6d6dSopenharmony_ci* When rolling certain fields, the values of other fields may conflict and
2892e5b6d6dSopenharmony_ci* need to be changed.  For example, when rolling the {@link #MONTH MONTH} field
2902e5b6d6dSopenharmony_ci* upward by one for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
2912e5b6d6dSopenharmony_ci* must be adjusted so that the result is "29 Elul 5758" rather than the invalid
2922e5b6d6dSopenharmony_ci* "30 Elul".
2932e5b6d6dSopenharmony_ci* <p>
2942e5b6d6dSopenharmony_ci* This method is able to roll
2952e5b6d6dSopenharmony_ci* all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
2962e5b6d6dSopenharmony_ci* and {@link #ZONE_OFFSET ZONE_OFFSET}.  Subclasses may, of course, add support for
2972e5b6d6dSopenharmony_ci* additional fields in their overrides of <code>roll</code>.
2982e5b6d6dSopenharmony_ci* <p>
2992e5b6d6dSopenharmony_ci* <b>Note:</b> You should always use roll and {@link #add add} rather
3002e5b6d6dSopenharmony_ci* than attempting to perform arithmetic operations directly on the fields
3012e5b6d6dSopenharmony_ci* of a <tt>HebrewCalendar</tt>.  Since the {@link #MONTH MONTH} field behaves
3022e5b6d6dSopenharmony_ci* discontinuously in non-leap years, simple arithmetic can give invalid results.
3032e5b6d6dSopenharmony_ci* <p>
3042e5b6d6dSopenharmony_ci* @param field     the time field.
3052e5b6d6dSopenharmony_ci* @param amount    the amount by which the field should be rolled.
3062e5b6d6dSopenharmony_ci*
3072e5b6d6dSopenharmony_ci* @exception   IllegalArgumentException if the field is invalid or refers
3082e5b6d6dSopenharmony_ci*              to a field that cannot be handled by this method.
3092e5b6d6dSopenharmony_ci* @internal
3102e5b6d6dSopenharmony_ci*/
3112e5b6d6dSopenharmony_civoid HebrewCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)
3122e5b6d6dSopenharmony_ci{
3132e5b6d6dSopenharmony_ci    if(U_FAILURE(status)) {
3142e5b6d6dSopenharmony_ci        return;
3152e5b6d6dSopenharmony_ci    }
3162e5b6d6dSopenharmony_ci    switch (field) {
3172e5b6d6dSopenharmony_ci  case UCAL_MONTH:
3182e5b6d6dSopenharmony_ci      {
3192e5b6d6dSopenharmony_ci          int32_t month = get(UCAL_MONTH, status);
3202e5b6d6dSopenharmony_ci          int32_t year = get(UCAL_YEAR, status);
3212e5b6d6dSopenharmony_ci
3222e5b6d6dSopenharmony_ci          UBool leapYear = isLeapYear(year);
3232e5b6d6dSopenharmony_ci          int32_t yearLength = monthsInYear(year);
3242e5b6d6dSopenharmony_ci          int32_t newMonth = month + (amount % yearLength);
3252e5b6d6dSopenharmony_ci          //
3262e5b6d6dSopenharmony_ci          // If it's not a leap year and we're rolling past the missing month
3272e5b6d6dSopenharmony_ci          // of ADAR_1, we need to roll an extra month to make up for it.
3282e5b6d6dSopenharmony_ci          //
3292e5b6d6dSopenharmony_ci          if (!leapYear) {
3302e5b6d6dSopenharmony_ci              if (amount > 0 && month < ADAR_1 && newMonth >= ADAR_1) {
3312e5b6d6dSopenharmony_ci                  newMonth++;
3322e5b6d6dSopenharmony_ci              } else if (amount < 0 && month > ADAR_1 && newMonth <= ADAR_1) {
3332e5b6d6dSopenharmony_ci                  newMonth--;
3342e5b6d6dSopenharmony_ci              }
3352e5b6d6dSopenharmony_ci          }
3362e5b6d6dSopenharmony_ci          set(UCAL_MONTH, (newMonth + 13) % 13);
3372e5b6d6dSopenharmony_ci          pinField(UCAL_DAY_OF_MONTH, status);
3382e5b6d6dSopenharmony_ci          return;
3392e5b6d6dSopenharmony_ci      }
3402e5b6d6dSopenharmony_ci  default:
3412e5b6d6dSopenharmony_ci      Calendar::roll(field, amount, status);
3422e5b6d6dSopenharmony_ci    }
3432e5b6d6dSopenharmony_ci}
3442e5b6d6dSopenharmony_ci
3452e5b6d6dSopenharmony_civoid HebrewCalendar::roll(EDateFields field, int32_t amount, UErrorCode& status) {
3462e5b6d6dSopenharmony_ci    roll((UCalendarDateFields)field, amount, status);
3472e5b6d6dSopenharmony_ci}
3482e5b6d6dSopenharmony_ci
3492e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
3502e5b6d6dSopenharmony_ci// Support methods
3512e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
3522e5b6d6dSopenharmony_ci
3532e5b6d6dSopenharmony_ci// Hebrew date calculations are performed in terms of days, hours, and
3542e5b6d6dSopenharmony_ci// "parts" (or halakim), which are 1/1080 of an hour, or 3 1/3 seconds.
3552e5b6d6dSopenharmony_cistatic const int32_t HOUR_PARTS = 1080;
3562e5b6d6dSopenharmony_cistatic const int32_t DAY_PARTS  = 24*HOUR_PARTS;
3572e5b6d6dSopenharmony_ci
3582e5b6d6dSopenharmony_ci// An approximate value for the length of a lunar month.
3592e5b6d6dSopenharmony_ci// It is used to calculate the approximate year and month of a given
3602e5b6d6dSopenharmony_ci// absolute date.
3612e5b6d6dSopenharmony_cistatic const int32_t  MONTH_DAYS = 29;
3622e5b6d6dSopenharmony_cistatic const int32_t MONTH_FRACT = 12*HOUR_PARTS + 793;
3632e5b6d6dSopenharmony_cistatic const int32_t MONTH_PARTS = MONTH_DAYS*DAY_PARTS + MONTH_FRACT;
3642e5b6d6dSopenharmony_ci
3652e5b6d6dSopenharmony_ci// The time of the new moon (in parts) on 1 Tishri, year 1 (the epoch)
3662e5b6d6dSopenharmony_ci// counting from noon on the day before.  BAHARAD is an abbreviation of
3672e5b6d6dSopenharmony_ci// Bet (Monday), Hey (5 hours from sunset), Resh-Daled (204).
3682e5b6d6dSopenharmony_cistatic const int32_t BAHARAD = 11*HOUR_PARTS + 204;
3692e5b6d6dSopenharmony_ci
3702e5b6d6dSopenharmony_ci/**
3712e5b6d6dSopenharmony_ci* Finds the day # of the first day in the given Hebrew year.
3722e5b6d6dSopenharmony_ci* To do this, we want to calculate the time of the Tishri 1 new moon
3732e5b6d6dSopenharmony_ci* in that year.
3742e5b6d6dSopenharmony_ci* <p>
3752e5b6d6dSopenharmony_ci* The algorithm here is similar to ones described in a number of
3762e5b6d6dSopenharmony_ci* references, including:
3772e5b6d6dSopenharmony_ci* <ul>
3782e5b6d6dSopenharmony_ci* <li>"Calendrical Calculations", by Nachum Dershowitz & Edward Reingold,
3792e5b6d6dSopenharmony_ci*     Cambridge University Press, 1997, pages 85-91.
3802e5b6d6dSopenharmony_ci*
3812e5b6d6dSopenharmony_ci* <li>Hebrew Calendar Science and Myths,
3822e5b6d6dSopenharmony_ci*     <a href="http://www.geocities.com/Athens/1584/">
3832e5b6d6dSopenharmony_ci*     http://www.geocities.com/Athens/1584/</a>
3842e5b6d6dSopenharmony_ci*
3852e5b6d6dSopenharmony_ci* <li>The Calendar FAQ,
3862e5b6d6dSopenharmony_ci*      <a href="http://www.faqs.org/faqs/calendars/faq/">
3872e5b6d6dSopenharmony_ci*      http://www.faqs.org/faqs/calendars/faq/</a>
3882e5b6d6dSopenharmony_ci* </ul>
3892e5b6d6dSopenharmony_ci*/
3902e5b6d6dSopenharmony_ciint32_t HebrewCalendar::startOfYear(int32_t year, UErrorCode &status)
3912e5b6d6dSopenharmony_ci{
3922e5b6d6dSopenharmony_ci    ucln_i18n_registerCleanup(UCLN_I18N_HEBREW_CALENDAR, calendar_hebrew_cleanup);
3932e5b6d6dSopenharmony_ci    int32_t day = CalendarCache::get(&gCache, year, status);
3942e5b6d6dSopenharmony_ci
3952e5b6d6dSopenharmony_ci    if (day == 0) {
3962e5b6d6dSopenharmony_ci        // # of months before year
3972e5b6d6dSopenharmony_ci        int32_t months = (int32_t)ClockMath::floorDivide((235 * (int64_t)year - 234), (int64_t)19);
3982e5b6d6dSopenharmony_ci
3992e5b6d6dSopenharmony_ci        int64_t frac = (int64_t)months * MONTH_FRACT + BAHARAD;  // Fractional part of day #
4002e5b6d6dSopenharmony_ci        day  = months * 29 + (int32_t)(frac / DAY_PARTS);        // Whole # part of calculation
4012e5b6d6dSopenharmony_ci        frac = frac % DAY_PARTS;                        // Time of day
4022e5b6d6dSopenharmony_ci
4032e5b6d6dSopenharmony_ci        int32_t wd = (day % 7);                        // Day of week (0 == Monday)
4042e5b6d6dSopenharmony_ci
4052e5b6d6dSopenharmony_ci        if (wd == 2 || wd == 4 || wd == 6) {
4062e5b6d6dSopenharmony_ci            // If the 1st is on Sun, Wed, or Fri, postpone to the next day
4072e5b6d6dSopenharmony_ci            day += 1;
4082e5b6d6dSopenharmony_ci            wd = (day % 7);
4092e5b6d6dSopenharmony_ci        }
4102e5b6d6dSopenharmony_ci        if (wd == 1 && frac > 15*HOUR_PARTS+204 && !isLeapYear(year) ) {
4112e5b6d6dSopenharmony_ci            // If the new moon falls after 3:11:20am (15h204p from the previous noon)
4122e5b6d6dSopenharmony_ci            // on a Tuesday and it is not a leap year, postpone by 2 days.
4132e5b6d6dSopenharmony_ci            // This prevents 356-day years.
4142e5b6d6dSopenharmony_ci            day += 2;
4152e5b6d6dSopenharmony_ci        }
4162e5b6d6dSopenharmony_ci        else if (wd == 0 && frac > 21*HOUR_PARTS+589 && isLeapYear(year-1) ) {
4172e5b6d6dSopenharmony_ci            // If the new moon falls after 9:32:43 1/3am (21h589p from yesterday noon)
4182e5b6d6dSopenharmony_ci            // on a Monday and *last* year was a leap year, postpone by 1 day.
4192e5b6d6dSopenharmony_ci            // Prevents 382-day years.
4202e5b6d6dSopenharmony_ci            day += 1;
4212e5b6d6dSopenharmony_ci        }
4222e5b6d6dSopenharmony_ci        CalendarCache::put(&gCache, year, day, status);
4232e5b6d6dSopenharmony_ci    }
4242e5b6d6dSopenharmony_ci    return day;
4252e5b6d6dSopenharmony_ci}
4262e5b6d6dSopenharmony_ci
4272e5b6d6dSopenharmony_ci/**
4282e5b6d6dSopenharmony_ci* Find the day of the week for a given day
4292e5b6d6dSopenharmony_ci*
4302e5b6d6dSopenharmony_ci* @param day   The # of days since the start of the Hebrew calendar,
4312e5b6d6dSopenharmony_ci*              1-based (i.e. 1/1/1 AM is day 1).
4322e5b6d6dSopenharmony_ci*/
4332e5b6d6dSopenharmony_ciint32_t HebrewCalendar::absoluteDayToDayOfWeek(int32_t day)
4342e5b6d6dSopenharmony_ci{
4352e5b6d6dSopenharmony_ci    // We know that 1/1/1 AM is a Monday, which makes the math easy...
4362e5b6d6dSopenharmony_ci    return (day % 7) + 1;
4372e5b6d6dSopenharmony_ci}
4382e5b6d6dSopenharmony_ci
4392e5b6d6dSopenharmony_ci/**
4402e5b6d6dSopenharmony_ci* Returns the the type of a given year.
4412e5b6d6dSopenharmony_ci*  0   "Deficient" year with 353 or 383 days
4422e5b6d6dSopenharmony_ci*  1   "Normal"    year with 354 or 384 days
4432e5b6d6dSopenharmony_ci*  2   "Complete"  year with 355 or 385 days
4442e5b6d6dSopenharmony_ci*/
4452e5b6d6dSopenharmony_ciint32_t HebrewCalendar::yearType(int32_t year) const
4462e5b6d6dSopenharmony_ci{
4472e5b6d6dSopenharmony_ci    int32_t yearLength = handleGetYearLength(year);
4482e5b6d6dSopenharmony_ci
4492e5b6d6dSopenharmony_ci    if (yearLength > 380) {
4502e5b6d6dSopenharmony_ci        yearLength -= 30;        // Subtract length of leap month.
4512e5b6d6dSopenharmony_ci    }
4522e5b6d6dSopenharmony_ci
4532e5b6d6dSopenharmony_ci    int type = 0;
4542e5b6d6dSopenharmony_ci
4552e5b6d6dSopenharmony_ci    switch (yearLength) {
4562e5b6d6dSopenharmony_ci  case 353:
4572e5b6d6dSopenharmony_ci      type = 0; break;
4582e5b6d6dSopenharmony_ci  case 354:
4592e5b6d6dSopenharmony_ci      type = 1; break;
4602e5b6d6dSopenharmony_ci  case 355:
4612e5b6d6dSopenharmony_ci      type = 2; break;
4622e5b6d6dSopenharmony_ci  default:
4632e5b6d6dSopenharmony_ci      //throw new RuntimeException("Illegal year length " + yearLength + " in year " + year);
4642e5b6d6dSopenharmony_ci      type = 1;
4652e5b6d6dSopenharmony_ci    }
4662e5b6d6dSopenharmony_ci    return type;
4672e5b6d6dSopenharmony_ci}
4682e5b6d6dSopenharmony_ci
4692e5b6d6dSopenharmony_ci/**
4702e5b6d6dSopenharmony_ci* Determine whether a given Hebrew year is a leap year
4712e5b6d6dSopenharmony_ci*
4722e5b6d6dSopenharmony_ci* The rule here is that if (year % 19) == 0, 3, 6, 8, 11, 14, or 17.
4732e5b6d6dSopenharmony_ci* The formula below performs the same test, believe it or not.
4742e5b6d6dSopenharmony_ci*/
4752e5b6d6dSopenharmony_ciUBool HebrewCalendar::isLeapYear(int32_t year) {
4762e5b6d6dSopenharmony_ci    //return (year * 12 + 17) % 19 >= 12;
4772e5b6d6dSopenharmony_ci    int32_t x = (year*12 + 17) % 19;
4782e5b6d6dSopenharmony_ci    return x >= ((x < 0) ? -7 : 12);
4792e5b6d6dSopenharmony_ci}
4802e5b6d6dSopenharmony_ci
4812e5b6d6dSopenharmony_ciint32_t HebrewCalendar::monthsInYear(int32_t year) {
4822e5b6d6dSopenharmony_ci    return isLeapYear(year) ? 13 : 12;
4832e5b6d6dSopenharmony_ci}
4842e5b6d6dSopenharmony_ci
4852e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
4862e5b6d6dSopenharmony_ci// Calendar framework
4872e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
4882e5b6d6dSopenharmony_ci
4892e5b6d6dSopenharmony_ci/**
4902e5b6d6dSopenharmony_ci* @internal
4912e5b6d6dSopenharmony_ci*/
4922e5b6d6dSopenharmony_ciint32_t HebrewCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
4932e5b6d6dSopenharmony_ci    return LIMITS[field][limitType];
4942e5b6d6dSopenharmony_ci}
4952e5b6d6dSopenharmony_ci
4962e5b6d6dSopenharmony_ci/**
4972e5b6d6dSopenharmony_ci* Returns the length of the given month in the given year
4982e5b6d6dSopenharmony_ci* @internal
4992e5b6d6dSopenharmony_ci*/
5002e5b6d6dSopenharmony_ciint32_t HebrewCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
5012e5b6d6dSopenharmony_ci    // Resolve out-of-range months.  This is necessary in order to
5022e5b6d6dSopenharmony_ci    // obtain the correct year.  We correct to
5032e5b6d6dSopenharmony_ci    // a 12- or 13-month year (add/subtract 12 or 13, depending
5042e5b6d6dSopenharmony_ci    // on the year) but since we _always_ number from 0..12, and
5052e5b6d6dSopenharmony_ci    // the leap year determines whether or not month 5 (Adar 1)
5062e5b6d6dSopenharmony_ci    // is present, we allow 0..12 in any given year.
5072e5b6d6dSopenharmony_ci    while (month < 0) {
5082e5b6d6dSopenharmony_ci        month += monthsInYear(--extendedYear);
5092e5b6d6dSopenharmony_ci    }
5102e5b6d6dSopenharmony_ci    // Careful: allow 0..12 in all years
5112e5b6d6dSopenharmony_ci    while (month > 12) {
5122e5b6d6dSopenharmony_ci        month -= monthsInYear(extendedYear++);
5132e5b6d6dSopenharmony_ci    }
5142e5b6d6dSopenharmony_ci
5152e5b6d6dSopenharmony_ci    switch (month) {
5162e5b6d6dSopenharmony_ci    case HESHVAN:
5172e5b6d6dSopenharmony_ci    case KISLEV:
5182e5b6d6dSopenharmony_ci      // These two month lengths can vary
5192e5b6d6dSopenharmony_ci      return MONTH_LENGTH[month][yearType(extendedYear)];
5202e5b6d6dSopenharmony_ci
5212e5b6d6dSopenharmony_ci    default:
5222e5b6d6dSopenharmony_ci      // The rest are a fixed length
5232e5b6d6dSopenharmony_ci      return MONTH_LENGTH[month][0];
5242e5b6d6dSopenharmony_ci    }
5252e5b6d6dSopenharmony_ci}
5262e5b6d6dSopenharmony_ci
5272e5b6d6dSopenharmony_ci/**
5282e5b6d6dSopenharmony_ci* Returns the number of days in the given Hebrew year
5292e5b6d6dSopenharmony_ci* @internal
5302e5b6d6dSopenharmony_ci*/
5312e5b6d6dSopenharmony_ciint32_t HebrewCalendar::handleGetYearLength(int32_t eyear) const {
5322e5b6d6dSopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
5332e5b6d6dSopenharmony_ci    return startOfYear(eyear+1, status) - startOfYear(eyear, status);
5342e5b6d6dSopenharmony_ci}
5352e5b6d6dSopenharmony_ci
5362e5b6d6dSopenharmony_civoid HebrewCalendar::validateField(UCalendarDateFields field, UErrorCode &status) {
5372e5b6d6dSopenharmony_ci    if (field == UCAL_MONTH && !isLeapYear(handleGetExtendedYear()) && internalGet(UCAL_MONTH) == ADAR_1) {
5382e5b6d6dSopenharmony_ci        status = U_ILLEGAL_ARGUMENT_ERROR;
5392e5b6d6dSopenharmony_ci        return;
5402e5b6d6dSopenharmony_ci    }
5412e5b6d6dSopenharmony_ci    Calendar::validateField(field, status);
5422e5b6d6dSopenharmony_ci}
5432e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
5442e5b6d6dSopenharmony_ci// Functions for converting from milliseconds to field values
5452e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
5462e5b6d6dSopenharmony_ci
5472e5b6d6dSopenharmony_ci/**
5482e5b6d6dSopenharmony_ci* Subclasses may override this method to compute several fields
5492e5b6d6dSopenharmony_ci* specific to each calendar system.  These are:
5502e5b6d6dSopenharmony_ci*
5512e5b6d6dSopenharmony_ci* <ul><li>ERA
5522e5b6d6dSopenharmony_ci* <li>YEAR
5532e5b6d6dSopenharmony_ci* <li>MONTH
5542e5b6d6dSopenharmony_ci* <li>DAY_OF_MONTH
5552e5b6d6dSopenharmony_ci* <li>DAY_OF_YEAR
5562e5b6d6dSopenharmony_ci* <li>EXTENDED_YEAR</ul>
5572e5b6d6dSopenharmony_ci*
5582e5b6d6dSopenharmony_ci* Subclasses can refer to the DAY_OF_WEEK and DOW_LOCAL fields,
5592e5b6d6dSopenharmony_ci* which will be set when this method is called.  Subclasses can
5602e5b6d6dSopenharmony_ci* also call the getGregorianXxx() methods to obtain Gregorian
5612e5b6d6dSopenharmony_ci* calendar equivalents for the given Julian day.
5622e5b6d6dSopenharmony_ci*
5632e5b6d6dSopenharmony_ci* <p>In addition, subclasses should compute any subclass-specific
5642e5b6d6dSopenharmony_ci* fields, that is, fields from BASE_FIELD_COUNT to
5652e5b6d6dSopenharmony_ci* getFieldCount() - 1.
5662e5b6d6dSopenharmony_ci* @internal
5672e5b6d6dSopenharmony_ci*/
5682e5b6d6dSopenharmony_civoid HebrewCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
5692e5b6d6dSopenharmony_ci    int32_t d = julianDay - 347997;
5702e5b6d6dSopenharmony_ci    double m = ClockMath::floorDivide((d * (double)DAY_PARTS), (double) MONTH_PARTS);  // Months (approx)
5712e5b6d6dSopenharmony_ci    int32_t year = (int32_t)(ClockMath::floorDivide((19. * m + 234.), 235.) + 1.);     // Years (approx)
5722e5b6d6dSopenharmony_ci    int32_t ys  = startOfYear(year, status);                   // 1st day of year
5732e5b6d6dSopenharmony_ci    int32_t dayOfYear = (d - ys);
5742e5b6d6dSopenharmony_ci
5752e5b6d6dSopenharmony_ci    // Because of the postponement rules, it's possible to guess wrong.  Fix it.
5762e5b6d6dSopenharmony_ci    while (dayOfYear < 1) {
5772e5b6d6dSopenharmony_ci        year--;
5782e5b6d6dSopenharmony_ci        ys  = startOfYear(year, status);
5792e5b6d6dSopenharmony_ci        dayOfYear = (d - ys);
5802e5b6d6dSopenharmony_ci    }
5812e5b6d6dSopenharmony_ci
5822e5b6d6dSopenharmony_ci    // Now figure out which month we're in, and the date within that month
5832e5b6d6dSopenharmony_ci    int32_t type = yearType(year);
5842e5b6d6dSopenharmony_ci    UBool isLeap = isLeapYear(year);
5852e5b6d6dSopenharmony_ci
5862e5b6d6dSopenharmony_ci    int32_t month = 0;
5872e5b6d6dSopenharmony_ci    int32_t momax = UPRV_LENGTHOF(MONTH_START);
5882e5b6d6dSopenharmony_ci    while (month < momax && dayOfYear > (  isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type] ) ) {
5892e5b6d6dSopenharmony_ci        month++;
5902e5b6d6dSopenharmony_ci    }
5912e5b6d6dSopenharmony_ci    if (month >= momax || month<=0) {
5922e5b6d6dSopenharmony_ci        // TODO: I found dayOfYear could be out of range when
5932e5b6d6dSopenharmony_ci        // a large value is set to julianDay.  I patched startOfYear
5942e5b6d6dSopenharmony_ci        // to reduce the chace, but it could be still reproduced either
5952e5b6d6dSopenharmony_ci        // by startOfYear or other places.  For now, we check
5962e5b6d6dSopenharmony_ci        // the month is in valid range to avoid out of array index
5972e5b6d6dSopenharmony_ci        // access problem here.  However, we need to carefully review
5982e5b6d6dSopenharmony_ci        // the calendar implementation to check the extreme limit of
5992e5b6d6dSopenharmony_ci        // each calendar field and the code works well for any values
6002e5b6d6dSopenharmony_ci        // in the valid value range.  -yoshito
6012e5b6d6dSopenharmony_ci        status = U_ILLEGAL_ARGUMENT_ERROR;
6022e5b6d6dSopenharmony_ci        return;
6032e5b6d6dSopenharmony_ci    }
6042e5b6d6dSopenharmony_ci    month--;
6052e5b6d6dSopenharmony_ci    int dayOfMonth = dayOfYear - (isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type]);
6062e5b6d6dSopenharmony_ci
6072e5b6d6dSopenharmony_ci    internalSet(UCAL_ERA, 0);
6082e5b6d6dSopenharmony_ci    internalSet(UCAL_YEAR, year);
6092e5b6d6dSopenharmony_ci    internalSet(UCAL_EXTENDED_YEAR, year);
6102e5b6d6dSopenharmony_ci    internalSet(UCAL_MONTH, month);
6112e5b6d6dSopenharmony_ci    internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
6122e5b6d6dSopenharmony_ci    internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
6132e5b6d6dSopenharmony_ci}
6142e5b6d6dSopenharmony_ci
6152e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
6162e5b6d6dSopenharmony_ci// Functions for converting from field values to milliseconds
6172e5b6d6dSopenharmony_ci//-------------------------------------------------------------------------
6182e5b6d6dSopenharmony_ci
6192e5b6d6dSopenharmony_ci/**
6202e5b6d6dSopenharmony_ci* @internal
6212e5b6d6dSopenharmony_ci*/
6222e5b6d6dSopenharmony_ciint32_t HebrewCalendar::handleGetExtendedYear() {
6232e5b6d6dSopenharmony_ci    int32_t year;
6242e5b6d6dSopenharmony_ci    if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
6252e5b6d6dSopenharmony_ci        year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
6262e5b6d6dSopenharmony_ci    } else {
6272e5b6d6dSopenharmony_ci        year = internalGet(UCAL_YEAR, 1); // Default to year 1
6282e5b6d6dSopenharmony_ci    }
6292e5b6d6dSopenharmony_ci    return year;
6302e5b6d6dSopenharmony_ci}
6312e5b6d6dSopenharmony_ci
6322e5b6d6dSopenharmony_ci/**
6332e5b6d6dSopenharmony_ci* Return JD of start of given month/year.
6342e5b6d6dSopenharmony_ci* @internal
6352e5b6d6dSopenharmony_ci*/
6362e5b6d6dSopenharmony_ciint32_t HebrewCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool /*useMonth*/) const {
6372e5b6d6dSopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
6382e5b6d6dSopenharmony_ci    // Resolve out-of-range months.  This is necessary in order to
6392e5b6d6dSopenharmony_ci    // obtain the correct year.  We correct to
6402e5b6d6dSopenharmony_ci    // a 12- or 13-month year (add/subtract 12 or 13, depending
6412e5b6d6dSopenharmony_ci    // on the year) but since we _always_ number from 0..12, and
6422e5b6d6dSopenharmony_ci    // the leap year determines whether or not month 5 (Adar 1)
6432e5b6d6dSopenharmony_ci    // is present, we allow 0..12 in any given year.
6442e5b6d6dSopenharmony_ci    while (month < 0) {
6452e5b6d6dSopenharmony_ci        month += monthsInYear(--eyear);
6462e5b6d6dSopenharmony_ci    }
6472e5b6d6dSopenharmony_ci    // Careful: allow 0..12 in all years
6482e5b6d6dSopenharmony_ci    while (month > 12) {
6492e5b6d6dSopenharmony_ci        month -= monthsInYear(eyear++);
6502e5b6d6dSopenharmony_ci    }
6512e5b6d6dSopenharmony_ci
6522e5b6d6dSopenharmony_ci    int32_t day = startOfYear(eyear, status);
6532e5b6d6dSopenharmony_ci
6542e5b6d6dSopenharmony_ci    if(U_FAILURE(status)) {
6552e5b6d6dSopenharmony_ci        return 0;
6562e5b6d6dSopenharmony_ci    }
6572e5b6d6dSopenharmony_ci
6582e5b6d6dSopenharmony_ci    if (month != 0) {
6592e5b6d6dSopenharmony_ci        if (isLeapYear(eyear)) {
6602e5b6d6dSopenharmony_ci            day += LEAP_MONTH_START[month][yearType(eyear)];
6612e5b6d6dSopenharmony_ci        } else {
6622e5b6d6dSopenharmony_ci            day += MONTH_START[month][yearType(eyear)];
6632e5b6d6dSopenharmony_ci        }
6642e5b6d6dSopenharmony_ci    }
6652e5b6d6dSopenharmony_ci
6662e5b6d6dSopenharmony_ci    return (int) (day + 347997);
6672e5b6d6dSopenharmony_ci}
6682e5b6d6dSopenharmony_ci
6692e5b6d6dSopenharmony_ciUBool
6702e5b6d6dSopenharmony_ciHebrewCalendar::inDaylightTime(UErrorCode& status) const
6712e5b6d6dSopenharmony_ci{
6722e5b6d6dSopenharmony_ci    // copied from GregorianCalendar
6732e5b6d6dSopenharmony_ci    if (U_FAILURE(status) || !getTimeZone().useDaylightTime())
6742e5b6d6dSopenharmony_ci        return false;
6752e5b6d6dSopenharmony_ci
6762e5b6d6dSopenharmony_ci    // Force an update of the state of the Calendar.
6772e5b6d6dSopenharmony_ci    ((HebrewCalendar*)this)->complete(status); // cast away const
6782e5b6d6dSopenharmony_ci
6792e5b6d6dSopenharmony_ci    return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : false);
6802e5b6d6dSopenharmony_ci}
6812e5b6d6dSopenharmony_ci
6822e5b6d6dSopenharmony_ci/**
6832e5b6d6dSopenharmony_ci * The system maintains a static default century start date and Year.  They are
6842e5b6d6dSopenharmony_ci * initialized the first time they are used.  Once the system default century date
6852e5b6d6dSopenharmony_ci * and year are set, they do not change.
6862e5b6d6dSopenharmony_ci */
6872e5b6d6dSopenharmony_cistatic UDate           gSystemDefaultCenturyStart       = DBL_MIN;
6882e5b6d6dSopenharmony_cistatic int32_t         gSystemDefaultCenturyStartYear   = -1;
6892e5b6d6dSopenharmony_cistatic icu::UInitOnce  gSystemDefaultCenturyInit        {};
6902e5b6d6dSopenharmony_ci
6912e5b6d6dSopenharmony_ciUBool HebrewCalendar::haveDefaultCentury() const
6922e5b6d6dSopenharmony_ci{
6932e5b6d6dSopenharmony_ci    return true;
6942e5b6d6dSopenharmony_ci}
6952e5b6d6dSopenharmony_ci
6962e5b6d6dSopenharmony_cistatic void U_CALLCONV initializeSystemDefaultCentury()
6972e5b6d6dSopenharmony_ci{
6982e5b6d6dSopenharmony_ci    // initialize systemDefaultCentury and systemDefaultCenturyYear based
6992e5b6d6dSopenharmony_ci    // on the current time.  They'll be set to 80 years before
7002e5b6d6dSopenharmony_ci    // the current time.
7012e5b6d6dSopenharmony_ci    UErrorCode status = U_ZERO_ERROR;
7022e5b6d6dSopenharmony_ci    HebrewCalendar calendar(Locale("@calendar=hebrew"),status);
7032e5b6d6dSopenharmony_ci    if (U_SUCCESS(status)) {
7042e5b6d6dSopenharmony_ci        calendar.setTime(Calendar::getNow(), status);
7052e5b6d6dSopenharmony_ci        calendar.add(UCAL_YEAR, -80, status);
7062e5b6d6dSopenharmony_ci
7072e5b6d6dSopenharmony_ci        gSystemDefaultCenturyStart = calendar.getTime(status);
7082e5b6d6dSopenharmony_ci        gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
7092e5b6d6dSopenharmony_ci    }
7102e5b6d6dSopenharmony_ci    // We have no recourse upon failure unless we want to propagate the failure
7112e5b6d6dSopenharmony_ci    // out.
7122e5b6d6dSopenharmony_ci}
7132e5b6d6dSopenharmony_ci
7142e5b6d6dSopenharmony_ci
7152e5b6d6dSopenharmony_ciUDate HebrewCalendar::defaultCenturyStart() const {
7162e5b6d6dSopenharmony_ci    // lazy-evaluate systemDefaultCenturyStart
7172e5b6d6dSopenharmony_ci    umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
7182e5b6d6dSopenharmony_ci    return gSystemDefaultCenturyStart;
7192e5b6d6dSopenharmony_ci}
7202e5b6d6dSopenharmony_ci
7212e5b6d6dSopenharmony_ciint32_t HebrewCalendar::defaultCenturyStartYear() const {
7222e5b6d6dSopenharmony_ci    // lazy-evaluate systemDefaultCenturyStartYear
7232e5b6d6dSopenharmony_ci    umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
7242e5b6d6dSopenharmony_ci    return gSystemDefaultCenturyStartYear;
7252e5b6d6dSopenharmony_ci}
7262e5b6d6dSopenharmony_ci
7272e5b6d6dSopenharmony_ci
7282e5b6d6dSopenharmony_ciUOBJECT_DEFINE_RTTI_IMPLEMENTATION(HebrewCalendar)
7292e5b6d6dSopenharmony_ci
7302e5b6d6dSopenharmony_ciU_NAMESPACE_END
7312e5b6d6dSopenharmony_ci
7322e5b6d6dSopenharmony_ci#endif // UCONFIG_NO_FORMATTING
7332e5b6d6dSopenharmony_ci
734