LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - gregocal.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 403 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 53 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) 1997-2016, International Business Machines Corporation and
       6             : * others. All Rights Reserved.
       7             : *******************************************************************************
       8             : *
       9             : * File GREGOCAL.CPP
      10             : *
      11             : * Modification History:
      12             : *
      13             : *   Date        Name        Description
      14             : *   02/05/97    clhuang     Creation.
      15             : *   03/28/97    aliu        Made highly questionable fix to computeFields to
      16             : *                           handle DST correctly.
      17             : *   04/22/97    aliu        Cleaned up code drastically.  Added monthLength().
      18             : *                           Finished unimplemented parts of computeTime() for
      19             : *                           week-based date determination.  Removed quetionable
      20             : *                           fix and wrote correct fix for computeFields() and
      21             : *                           daylight time handling.  Rewrote inDaylightTime()
      22             : *                           and computeFields() to handle sensitive Daylight to
      23             : *                           Standard time transitions correctly.
      24             : *   05/08/97    aliu        Added code review changes.  Fixed isLeapYear() to
      25             : *                           not cutover.
      26             : *   08/12/97    aliu        Added equivalentTo.  Misc other fixes.  Updated
      27             : *                           add() from Java source.
      28             : *    07/28/98    stephen        Sync up with JDK 1.2
      29             : *    09/14/98    stephen        Changed type of kOneDay, kOneWeek to double.
      30             : *                            Fixed bug in roll() 
      31             : *   10/15/99    aliu        Fixed j31, incorrect WEEK_OF_YEAR computation.
      32             : *   10/15/99    aliu        Fixed j32, cannot set date to Feb 29 2000 AD.
      33             : *                           {JDK bug 4210209 4209272}
      34             : *   11/15/99    weiv        Added YEAR_WOY and DOW_LOCAL computation
      35             : *                           to timeToFields method, updated kMinValues, kMaxValues & kLeastMaxValues
      36             : *   12/09/99    aliu        Fixed j81, calculation errors and roll bugs
      37             : *                           in year of cutover.
      38             : *   01/24/2000  aliu        Revised computeJulianDay for YEAR YEAR_WOY WOY.
      39             : ********************************************************************************
      40             : */
      41             : 
      42             : #include "unicode/utypes.h"
      43             : #include <float.h>
      44             : 
      45             : #if !UCONFIG_NO_FORMATTING
      46             : 
      47             : #include "unicode/gregocal.h"
      48             : #include "gregoimp.h"
      49             : #include "umutex.h"
      50             : #include "uassert.h"
      51             : 
      52             : // *****************************************************************************
      53             : // class GregorianCalendar
      54             : // *****************************************************************************
      55             : 
      56             : /**
      57             : * Note that the Julian date used here is not a true Julian date, since
      58             : * it is measured from midnight, not noon.  This value is the Julian
      59             : * day number of January 1, 1970 (Gregorian calendar) at noon UTC. [LIU]
      60             : */
      61             : 
      62             : static const int16_t kNumDays[]
      63             : = {0,31,59,90,120,151,181,212,243,273,304,334}; // 0-based, for day-in-year
      64             : static const int16_t kLeapNumDays[]
      65             : = {0,31,60,91,121,152,182,213,244,274,305,335}; // 0-based, for day-in-year
      66             : static const int8_t kMonthLength[]
      67             : = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
      68             : static const int8_t kLeapMonthLength[]
      69             : = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
      70             : 
      71             : // setTimeInMillis() limits the Julian day range to +/-7F000000.
      72             : // This would seem to limit the year range to:
      73             : //  ms=+183882168921600000  jd=7f000000  December 20, 5828963 AD
      74             : //  ms=-184303902528000000  jd=81000000  September 20, 5838270 BC
      75             : // HOWEVER, CalendarRegressionTest/Test4167060 shows that the actual
      76             : // range limit on the year field is smaller (~ +/-140000). [alan 3.0]
      77             : 
      78             : static const int32_t kGregorianCalendarLimits[UCAL_FIELD_COUNT][4] = {
      79             :     // Minimum  Greatest    Least  Maximum
      80             :     //           Minimum  Maximum
      81             :     {        0,        0,        1,        1}, // ERA
      82             :     {        1,        1,   140742,   144683}, // YEAR
      83             :     {        0,        0,       11,       11}, // MONTH
      84             :     {        1,        1,       52,       53}, // WEEK_OF_YEAR
      85             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
      86             :     {        1,        1,       28,       31}, // DAY_OF_MONTH
      87             :     {        1,        1,      365,      366}, // DAY_OF_YEAR
      88             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
      89             :     {       -1,       -1,        4,        5}, // DAY_OF_WEEK_IN_MONTH
      90             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
      91             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
      92             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
      93             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
      94             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
      95             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
      96             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
      97             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
      98             :     {  -140742,  -140742,   140742,   144683}, // YEAR_WOY
      99             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
     100             :     {  -140742,  -140742,   140742,   144683}, // EXTENDED_YEAR
     101             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
     102             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
     103             :     {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
     104             : };
     105             : 
     106             : /*
     107             : * <pre>
     108             : *                            Greatest       Least 
     109             : * Field name        Minimum   Minimum     Maximum     Maximum
     110             : * ----------        -------   -------     -------     -------
     111             : * ERA                     0         0           1           1
     112             : * YEAR                    1         1      140742      144683
     113             : * MONTH                   0         0          11          11
     114             : * WEEK_OF_YEAR            1         1          52          53
     115             : * WEEK_OF_MONTH           0         0           4           6
     116             : * DAY_OF_MONTH            1         1          28          31
     117             : * DAY_OF_YEAR             1         1         365         366
     118             : * DAY_OF_WEEK             1         1           7           7
     119             : * DAY_OF_WEEK_IN_MONTH   -1        -1           4           5
     120             : * AM_PM                   0         0           1           1
     121             : * HOUR                    0         0          11          11
     122             : * HOUR_OF_DAY             0         0          23          23
     123             : * MINUTE                  0         0          59          59
     124             : * SECOND                  0         0          59          59
     125             : * MILLISECOND             0         0         999         999
     126             : * ZONE_OFFSET           -12*      -12*         12*         12*
     127             : * DST_OFFSET              0         0           1*          1*
     128             : * YEAR_WOY                1         1      140742      144683
     129             : * DOW_LOCAL               1         1           7           7
     130             : * </pre>
     131             : * (*) In units of one-hour
     132             : */
     133             : 
     134             : #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
     135             : #include <stdio.h>
     136             : #endif
     137             : 
     138             : U_NAMESPACE_BEGIN
     139             : 
     140           0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GregorianCalendar)
     141             : 
     142             : // 00:00:00 UTC, October 15, 1582, expressed in ms from the epoch.
     143             : // Note that only Italy and other Catholic countries actually
     144             : // observed this cutover.  Most other countries followed in
     145             : // the next few centuries, some as late as 1928. [LIU]
     146             : // in Java, -12219292800000L
     147             : //const UDate GregorianCalendar::kPapalCutover = -12219292800000L;
     148             : static const uint32_t kCutoverJulianDay = 2299161;
     149             : static const UDate kPapalCutover = (2299161.0 - kEpochStartAsJulianDay) * U_MILLIS_PER_DAY;
     150             : //static const UDate kPapalCutoverJulian = (2299161.0 - kEpochStartAsJulianDay);
     151             : 
     152             : // -------------------------------------
     153             : 
     154           0 : GregorianCalendar::GregorianCalendar(UErrorCode& status)
     155             : :   Calendar(status),
     156             : fGregorianCutover(kPapalCutover),
     157           0 : fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
     158           0 : fIsGregorian(TRUE), fInvertGregorian(FALSE)
     159             : {
     160           0 :     setTimeInMillis(getNow(), status);
     161           0 : }
     162             : 
     163             : // -------------------------------------
     164             : 
     165           0 : GregorianCalendar::GregorianCalendar(TimeZone* zone, UErrorCode& status)
     166             : :   Calendar(zone, Locale::getDefault(), status),
     167             : fGregorianCutover(kPapalCutover),
     168           0 : fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
     169           0 : fIsGregorian(TRUE), fInvertGregorian(FALSE)
     170             : {
     171           0 :     setTimeInMillis(getNow(), status);
     172           0 : }
     173             : 
     174             : // -------------------------------------
     175             : 
     176           0 : GregorianCalendar::GregorianCalendar(const TimeZone& zone, UErrorCode& status)
     177             : :   Calendar(zone, Locale::getDefault(), status),
     178             : fGregorianCutover(kPapalCutover),
     179           0 : fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
     180           0 : fIsGregorian(TRUE), fInvertGregorian(FALSE)
     181             : {
     182           0 :     setTimeInMillis(getNow(), status);
     183           0 : }
     184             : 
     185             : // -------------------------------------
     186             : 
     187           0 : GregorianCalendar::GregorianCalendar(const Locale& aLocale, UErrorCode& status)
     188             : :   Calendar(TimeZone::createDefault(), aLocale, status),
     189             : fGregorianCutover(kPapalCutover),
     190           0 : fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
     191           0 : fIsGregorian(TRUE), fInvertGregorian(FALSE)
     192             : {
     193           0 :     setTimeInMillis(getNow(), status);
     194           0 : }
     195             : 
     196             : // -------------------------------------
     197             : 
     198           0 : GregorianCalendar::GregorianCalendar(TimeZone* zone, const Locale& aLocale,
     199           0 :                                      UErrorCode& status)
     200             :                                      :   Calendar(zone, aLocale, status),
     201             :                                      fGregorianCutover(kPapalCutover),
     202           0 :                                      fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
     203           0 :                                      fIsGregorian(TRUE), fInvertGregorian(FALSE)
     204             : {
     205           0 :     setTimeInMillis(getNow(), status);
     206           0 : }
     207             : 
     208             : // -------------------------------------
     209             : 
     210           0 : GregorianCalendar::GregorianCalendar(const TimeZone& zone, const Locale& aLocale,
     211           0 :                                      UErrorCode& status)
     212             :                                      :   Calendar(zone, aLocale, status),
     213             :                                      fGregorianCutover(kPapalCutover),
     214           0 :                                      fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
     215           0 :                                      fIsGregorian(TRUE), fInvertGregorian(FALSE)
     216             : {
     217           0 :     setTimeInMillis(getNow(), status);
     218           0 : }
     219             : 
     220             : // -------------------------------------
     221             : 
     222           0 : GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
     223           0 :                                      UErrorCode& status)
     224             :                                      :   Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
     225             :                                      fGregorianCutover(kPapalCutover),
     226           0 :                                      fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
     227           0 :                                      fIsGregorian(TRUE), fInvertGregorian(FALSE)
     228             : {
     229           0 :     set(UCAL_ERA, AD);
     230           0 :     set(UCAL_YEAR, year);
     231           0 :     set(UCAL_MONTH, month);
     232           0 :     set(UCAL_DATE, date);
     233           0 : }
     234             : 
     235             : // -------------------------------------
     236             : 
     237           0 : GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
     238           0 :                                      int32_t hour, int32_t minute, UErrorCode& status)
     239             :                                      :   Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
     240             :                                      fGregorianCutover(kPapalCutover),
     241           0 :                                      fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
     242           0 :                                      fIsGregorian(TRUE), fInvertGregorian(FALSE)
     243             : {
     244           0 :     set(UCAL_ERA, AD);
     245           0 :     set(UCAL_YEAR, year);
     246           0 :     set(UCAL_MONTH, month);
     247           0 :     set(UCAL_DATE, date);
     248           0 :     set(UCAL_HOUR_OF_DAY, hour);
     249           0 :     set(UCAL_MINUTE, minute);
     250           0 : }
     251             : 
     252             : // -------------------------------------
     253             : 
     254           0 : GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
     255             :                                      int32_t hour, int32_t minute, int32_t second,
     256           0 :                                      UErrorCode& status)
     257             :                                      :   Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
     258             :                                      fGregorianCutover(kPapalCutover),
     259           0 :                                      fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
     260           0 :                                      fIsGregorian(TRUE), fInvertGregorian(FALSE)
     261             : {
     262           0 :     set(UCAL_ERA, AD);
     263           0 :     set(UCAL_YEAR, year);
     264           0 :     set(UCAL_MONTH, month);
     265           0 :     set(UCAL_DATE, date);
     266           0 :     set(UCAL_HOUR_OF_DAY, hour);
     267           0 :     set(UCAL_MINUTE, minute);
     268           0 :     set(UCAL_SECOND, second);
     269           0 : }
     270             : 
     271             : // -------------------------------------
     272             : 
     273           0 : GregorianCalendar::~GregorianCalendar()
     274             : {
     275           0 : }
     276             : 
     277             : // -------------------------------------
     278             : 
     279           0 : GregorianCalendar::GregorianCalendar(const GregorianCalendar &source)
     280             : :   Calendar(source),
     281           0 : fGregorianCutover(source.fGregorianCutover),
     282           0 : fCutoverJulianDay(source.fCutoverJulianDay), fNormalizedGregorianCutover(source.fNormalizedGregorianCutover), fGregorianCutoverYear(source.fGregorianCutoverYear),
     283           0 : fIsGregorian(source.fIsGregorian), fInvertGregorian(source.fInvertGregorian)
     284             : {
     285           0 : }
     286             : 
     287             : // -------------------------------------
     288             : 
     289           0 : Calendar* GregorianCalendar::clone() const
     290             : {
     291           0 :     return new GregorianCalendar(*this);
     292             : }
     293             : 
     294             : // -------------------------------------
     295             : 
     296             : GregorianCalendar &
     297           0 : GregorianCalendar::operator=(const GregorianCalendar &right)
     298             : {
     299           0 :     if (this != &right)
     300             :     {
     301           0 :         Calendar::operator=(right);
     302           0 :         fGregorianCutover = right.fGregorianCutover;
     303           0 :         fNormalizedGregorianCutover = right.fNormalizedGregorianCutover;
     304           0 :         fGregorianCutoverYear = right.fGregorianCutoverYear;
     305           0 :         fCutoverJulianDay = right.fCutoverJulianDay;
     306             :     }
     307           0 :     return *this;
     308             : }
     309             : 
     310             : // -------------------------------------
     311             : 
     312           0 : UBool GregorianCalendar::isEquivalentTo(const Calendar& other) const
     313             : {
     314             :     // Calendar override.
     315           0 :     return Calendar::isEquivalentTo(other) &&
     316           0 :         fGregorianCutover == ((GregorianCalendar*)&other)->fGregorianCutover;
     317             : }
     318             : 
     319             : // -------------------------------------
     320             : 
     321             : void
     322           0 : GregorianCalendar::setGregorianChange(UDate date, UErrorCode& status)
     323             : {
     324           0 :     if (U_FAILURE(status)) 
     325           0 :         return;
     326             : 
     327           0 :     fGregorianCutover = date;
     328             : 
     329             :     // Precompute two internal variables which we use to do the actual
     330             :     // cutover computations.  These are the normalized cutover, which is the
     331             :     // midnight at or before the cutover, and the cutover year.  The
     332             :     // normalized cutover is in pure date milliseconds; it contains no time
     333             :     // of day or timezone component, and it used to compare against other
     334             :     // pure date values.
     335           0 :     int32_t cutoverDay = (int32_t)ClockMath::floorDivide(fGregorianCutover, (double)kOneDay);
     336           0 :     fNormalizedGregorianCutover = cutoverDay * kOneDay;
     337             : 
     338             :     // Handle the rare case of numeric overflow.  If the user specifies a
     339             :     // change of UDate(Long.MIN_VALUE), in order to get a pure Gregorian
     340             :     // calendar, then the epoch day is -106751991168, which when multiplied
     341             :     // by ONE_DAY gives 9223372036794351616 -- the negative value is too
     342             :     // large for 64 bits, and overflows into a positive value.  We correct
     343             :     // this by using the next day, which for all intents is semantically
     344             :     // equivalent.
     345           0 :     if (cutoverDay < 0 && fNormalizedGregorianCutover > 0) {
     346           0 :         fNormalizedGregorianCutover = (cutoverDay + 1) * kOneDay;
     347             :     }
     348             : 
     349             :     // Normalize the year so BC values are represented as 0 and negative
     350             :     // values.
     351           0 :     GregorianCalendar *cal = new GregorianCalendar(getTimeZone(), status);
     352             :     /* test for NULL */
     353           0 :     if (cal == 0) {
     354           0 :         status = U_MEMORY_ALLOCATION_ERROR;
     355           0 :         return;
     356             :     }
     357           0 :     if(U_FAILURE(status))
     358           0 :         return;
     359           0 :     cal->setTime(date, status);
     360           0 :     fGregorianCutoverYear = cal->get(UCAL_YEAR, status);
     361           0 :     if (cal->get(UCAL_ERA, status) == BC) 
     362           0 :         fGregorianCutoverYear = 1 - fGregorianCutoverYear;
     363           0 :     fCutoverJulianDay = cutoverDay;
     364           0 :     delete cal;
     365             : }
     366             : 
     367             : 
     368           0 : void GregorianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) {
     369             :     int32_t eyear, month, dayOfMonth, dayOfYear, unusedRemainder;
     370             : 
     371             : 
     372           0 :     if(U_FAILURE(status)) { 
     373           0 :         return; 
     374             :     }
     375             : 
     376             : #if defined (U_DEBUG_CAL)
     377             :     fprintf(stderr, "%s:%d: jd%d- (greg's %d)- [cut=%d]\n", 
     378             :         __FILE__, __LINE__, julianDay, getGregorianDayOfYear(), fCutoverJulianDay);
     379             : #endif
     380             : 
     381             : 
     382           0 :     if (julianDay >= fCutoverJulianDay) {
     383           0 :         month = getGregorianMonth();
     384           0 :         dayOfMonth = getGregorianDayOfMonth();
     385           0 :         dayOfYear = getGregorianDayOfYear();
     386           0 :         eyear = getGregorianYear();
     387             :     } else {
     388             :         // The Julian epoch day (not the same as Julian Day)
     389             :         // is zero on Saturday December 30, 0 (Gregorian).
     390           0 :         int32_t julianEpochDay = julianDay - (kJan1_1JulianDay - 2);
     391           0 :                 eyear = (int32_t) ClockMath::floorDivide((4.0*julianEpochDay) + 1464.0, (int32_t) 1461, unusedRemainder);
     392             : 
     393             :         // Compute the Julian calendar day number for January 1, eyear
     394           0 :         int32_t january1 = 365*(eyear-1) + ClockMath::floorDivide(eyear-1, (int32_t)4);
     395           0 :         dayOfYear = (julianEpochDay - january1); // 0-based
     396             : 
     397             :         // Julian leap years occurred historically every 4 years starting
     398             :         // with 8 AD.  Before 8 AD the spacing is irregular; every 3 years
     399             :         // from 45 BC to 9 BC, and then none until 8 AD.  However, we don't
     400             :         // implement this historical detail; instead, we implement the
     401             :         // computatinally cleaner proleptic calendar, which assumes
     402             :         // consistent 4-year cycles throughout time.
     403           0 :         UBool isLeap = ((eyear&0x3) == 0); // equiv. to (eyear%4 == 0)
     404             : 
     405             :         // Common Julian/Gregorian calculation
     406           0 :         int32_t correction = 0;
     407           0 :         int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
     408           0 :         if (dayOfYear >= march1) {
     409           0 :             correction = isLeap ? 1 : 2;
     410             :         }
     411           0 :         month = (12 * (dayOfYear + correction) + 6) / 367; // zero-based month
     412           0 :         dayOfMonth = dayOfYear - (isLeap?kLeapNumDays[month]:kNumDays[month]) + 1; // one-based DOM
     413           0 :         ++dayOfYear;
     414             : #if defined (U_DEBUG_CAL)
     415             :         //     fprintf(stderr, "%d - %d[%d] + 1\n", dayOfYear, isLeap?kLeapNumDays[month]:kNumDays[month], month );
     416             :         //           fprintf(stderr, "%s:%d:  greg's HCF %d -> %d/%d/%d not %d/%d/%d\n", 
     417             :         //                   __FILE__, __LINE__,julianDay,
     418             :         //          eyear,month,dayOfMonth,
     419             :         //          getGregorianYear(), getGregorianMonth(), getGregorianDayOfMonth()  );
     420             :         fprintf(stderr, "%s:%d: doy %d (greg's %d)- [cut=%d]\n", 
     421             :             __FILE__, __LINE__, dayOfYear, getGregorianDayOfYear(), fCutoverJulianDay);
     422             : #endif
     423             : 
     424             :     }
     425             : 
     426             :     // [j81] if we are after the cutover in its year, shift the day of the year
     427           0 :     if((eyear == fGregorianCutoverYear) && (julianDay >= fCutoverJulianDay)) {
     428             :         //from handleComputeMonthStart
     429           0 :         int32_t gregShift = Grego::gregorianShift(eyear);
     430             : #if defined (U_DEBUG_CAL)
     431             :         fprintf(stderr, "%s:%d:  gregorian shift %d :::  doy%d => %d [cut=%d]\n",
     432             :             __FILE__, __LINE__,gregShift, dayOfYear, dayOfYear+gregShift, fCutoverJulianDay);
     433             : #endif
     434           0 :         dayOfYear += gregShift;
     435             :     }
     436             : 
     437           0 :     internalSet(UCAL_MONTH, month);
     438           0 :     internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
     439           0 :     internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
     440           0 :     internalSet(UCAL_EXTENDED_YEAR, eyear);
     441           0 :     int32_t era = AD;
     442           0 :     if (eyear < 1) {
     443           0 :         era = BC;
     444           0 :         eyear = 1 - eyear;
     445             :     }
     446           0 :     internalSet(UCAL_ERA, era);
     447           0 :     internalSet(UCAL_YEAR, eyear);
     448             : }
     449             : 
     450             : 
     451             : // -------------------------------------
     452             : 
     453             : UDate
     454           0 : GregorianCalendar::getGregorianChange() const
     455             : {
     456           0 :     return fGregorianCutover;
     457             : }
     458             : 
     459             : // -------------------------------------
     460             : 
     461             : UBool 
     462           0 : GregorianCalendar::isLeapYear(int32_t year) const
     463             : {
     464             :     // MSVC complains bitterly if we try to use Grego::isLeapYear here
     465             :     // NOTE: year&0x3 == year%4
     466           0 :     return (year >= fGregorianCutoverYear ?
     467           0 :         (((year&0x3) == 0) && ((year%100 != 0) || (year%400 == 0))) : // Gregorian
     468           0 :     ((year&0x3) == 0)); // Julian
     469             : }
     470             : 
     471             : // -------------------------------------
     472             : 
     473           0 : int32_t GregorianCalendar::handleComputeJulianDay(UCalendarDateFields bestField) 
     474             : {
     475           0 :     fInvertGregorian = FALSE;
     476             : 
     477           0 :     int32_t jd = Calendar::handleComputeJulianDay(bestField);
     478             : 
     479           0 :     if((bestField == UCAL_WEEK_OF_YEAR) &&  // if we are doing WOY calculations, we are counting relative to Jan 1 *julian*
     480           0 :         (internalGet(UCAL_EXTENDED_YEAR)==fGregorianCutoverYear) && 
     481           0 :         jd >= fCutoverJulianDay) { 
     482           0 :             fInvertGregorian = TRUE;  // So that the Julian Jan 1 will be used in handleComputeMonthStart
     483           0 :             return Calendar::handleComputeJulianDay(bestField);
     484             :         }
     485             : 
     486             : 
     487             :         // The following check handles portions of the cutover year BEFORE the
     488             :         // cutover itself happens.
     489             :         //if ((fIsGregorian==TRUE) != (jd >= fCutoverJulianDay)) {  /*  cutoverJulianDay)) { */
     490           0 :         if ((fIsGregorian==TRUE) != (jd >= fCutoverJulianDay)) {  /*  cutoverJulianDay)) { */
     491             : #if defined (U_DEBUG_CAL)
     492             :             fprintf(stderr, "%s:%d: jd [invert] %d\n", 
     493             :                 __FILE__, __LINE__, jd);
     494             : #endif
     495           0 :             fInvertGregorian = TRUE;
     496           0 :             jd = Calendar::handleComputeJulianDay(bestField);
     497             : #if defined (U_DEBUG_CAL)
     498             :             fprintf(stderr, "%s:%d:  fIsGregorian %s, fInvertGregorian %s - ", 
     499             :                 __FILE__, __LINE__,fIsGregorian?"T":"F", fInvertGregorian?"T":"F");
     500             :             fprintf(stderr, " jd NOW %d\n", 
     501             :                 jd);
     502             : #endif
     503             :         } else {
     504             : #if defined (U_DEBUG_CAL)
     505             :             fprintf(stderr, "%s:%d: jd [==] %d - %sfIsGregorian %sfInvertGregorian, %d\n", 
     506             :                 __FILE__, __LINE__, jd, fIsGregorian?"T":"F", fInvertGregorian?"T":"F", bestField);
     507             : #endif
     508             :         }
     509             : 
     510           0 :         if(fIsGregorian && (internalGet(UCAL_EXTENDED_YEAR) == fGregorianCutoverYear)) {
     511           0 :             int32_t gregShift = Grego::gregorianShift(internalGet(UCAL_EXTENDED_YEAR));
     512           0 :             if (bestField == UCAL_DAY_OF_YEAR) {
     513             : #if defined (U_DEBUG_CAL)
     514             :                 fprintf(stderr, "%s:%d: [DOY%d] gregorian shift of JD %d += %d\n", 
     515             :                     __FILE__, __LINE__, fFields[bestField],jd, gregShift);
     516             : #endif
     517           0 :                 jd -= gregShift;
     518           0 :             } else if ( bestField == UCAL_WEEK_OF_MONTH ) {
     519           0 :                 int32_t weekShift = 14;
     520             : #if defined (U_DEBUG_CAL)
     521             :                 fprintf(stderr, "%s:%d: [WOY/WOM] gregorian week shift of %d += %d\n", 
     522             :                     __FILE__, __LINE__, jd, weekShift);
     523             : #endif
     524           0 :                 jd += weekShift; // shift by weeks for week based fields.
     525             :             }
     526             :         }
     527             : 
     528           0 :         return jd;
     529             : }
     530             : 
     531           0 : int32_t GregorianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month,
     532             : 
     533             :                                                    UBool /* useMonth */) const
     534             : {
     535           0 :     GregorianCalendar *nonConstThis = (GregorianCalendar*)this; // cast away const
     536             : 
     537             :     // If the month is out of range, adjust it into range, and
     538             :     // modify the extended year value accordingly.
     539           0 :     if (month < 0 || month > 11) {
     540           0 :         eyear += ClockMath::floorDivide(month, 12, month);
     541             :     }
     542             : 
     543           0 :     UBool isLeap = eyear%4 == 0;
     544           0 :     int32_t y = eyear-1;
     545           0 :     int32_t julianDay = 365*y + ClockMath::floorDivide(y, 4) + (kJan1_1JulianDay - 3);
     546             : 
     547           0 :     nonConstThis->fIsGregorian = (eyear >= fGregorianCutoverYear);
     548             : #if defined (U_DEBUG_CAL)
     549             :     fprintf(stderr, "%s:%d: (hcms%d/%d) fIsGregorian %s, fInvertGregorian %s\n", 
     550             :         __FILE__, __LINE__, eyear,month, fIsGregorian?"T":"F", fInvertGregorian?"T":"F");
     551             : #endif
     552           0 :     if (fInvertGregorian) {
     553           0 :         nonConstThis->fIsGregorian = !fIsGregorian;
     554             :     }
     555           0 :     if (fIsGregorian) {
     556           0 :         isLeap = isLeap && ((eyear%100 != 0) || (eyear%400 == 0));
     557             :         // Add 2 because Gregorian calendar starts 2 days after
     558             :         // Julian calendar
     559           0 :         int32_t gregShift = Grego::gregorianShift(eyear);
     560             : #if defined (U_DEBUG_CAL)
     561             :         fprintf(stderr, "%s:%d: (hcms%d/%d) gregorian shift of %d += %d\n", 
     562             :             __FILE__, __LINE__, eyear, month, julianDay, gregShift);
     563             : #endif
     564           0 :         julianDay += gregShift;
     565             :     }
     566             : 
     567             :     // At this point julianDay indicates the day BEFORE the first
     568             :     // day of January 1, <eyear> of either the Julian or Gregorian
     569             :     // calendar.
     570             : 
     571           0 :     if (month != 0) {
     572           0 :         julianDay += isLeap?kLeapNumDays[month]:kNumDays[month];
     573             :     }
     574             : 
     575           0 :     return julianDay;
     576             : }
     577             : 
     578           0 : int32_t GregorianCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month)  const
     579             : {
     580             :     // If the month is out of range, adjust it into range, and
     581             :     // modify the extended year value accordingly.
     582           0 :     if (month < 0 || month > 11) {
     583           0 :         extendedYear += ClockMath::floorDivide(month, 12, month);
     584             :     }
     585             : 
     586           0 :     return isLeapYear(extendedYear) ? kLeapMonthLength[month] : kMonthLength[month];
     587             : }
     588             : 
     589           0 : int32_t GregorianCalendar::handleGetYearLength(int32_t eyear) const {
     590           0 :     return isLeapYear(eyear) ? 366 : 365;
     591             : }
     592             : 
     593             : 
     594             : int32_t
     595           0 : GregorianCalendar::monthLength(int32_t month) const
     596             : {
     597           0 :     int32_t year = internalGet(UCAL_EXTENDED_YEAR);
     598           0 :     return handleGetMonthLength(year, month);
     599             : }
     600             : 
     601             : // -------------------------------------
     602             : 
     603             : int32_t
     604           0 : GregorianCalendar::monthLength(int32_t month, int32_t year) const
     605             : {
     606           0 :     return isLeapYear(year) ? kLeapMonthLength[month] : kMonthLength[month];
     607             : }
     608             : 
     609             : // -------------------------------------
     610             : 
     611             : int32_t
     612           0 : GregorianCalendar::yearLength(int32_t year) const
     613             : {
     614           0 :     return isLeapYear(year) ? 366 : 365;
     615             : }
     616             : 
     617             : // -------------------------------------
     618             : 
     619             : int32_t
     620           0 : GregorianCalendar::yearLength() const
     621             : {
     622           0 :     return isLeapYear(internalGet(UCAL_YEAR)) ? 366 : 365;
     623             : }
     624             : 
     625             : // -------------------------------------
     626             : 
     627             : /**
     628             : * After adjustments such as add(MONTH), add(YEAR), we don't want the
     629             : * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
     630             : * 3, we want it to go to Feb 28.  Adjustments which might run into this
     631             : * problem call this method to retain the proper month.
     632             : */
     633             : void 
     634           0 : GregorianCalendar::pinDayOfMonth() 
     635             : {
     636           0 :     int32_t monthLen = monthLength(internalGet(UCAL_MONTH));
     637           0 :     int32_t dom = internalGet(UCAL_DATE);
     638           0 :     if(dom > monthLen) 
     639           0 :         set(UCAL_DATE, monthLen);
     640           0 : }
     641             : 
     642             : // -------------------------------------
     643             : 
     644             : 
     645             : UBool
     646           0 : GregorianCalendar::validateFields() const
     647             : {
     648           0 :     for (int32_t field = 0; field < UCAL_FIELD_COUNT; field++) {
     649             :         // Ignore DATE and DAY_OF_YEAR which are handled below
     650           0 :         if (field != UCAL_DATE &&
     651           0 :             field != UCAL_DAY_OF_YEAR &&
     652           0 :             isSet((UCalendarDateFields)field) &&
     653           0 :             ! boundsCheck(internalGet((UCalendarDateFields)field), (UCalendarDateFields)field))
     654           0 :             return FALSE;
     655             :     }
     656             : 
     657             :     // Values differ in Least-Maximum and Maximum should be handled
     658             :     // specially.
     659           0 :     if (isSet(UCAL_DATE)) {
     660           0 :         int32_t date = internalGet(UCAL_DATE);
     661           0 :         if (date < getMinimum(UCAL_DATE) ||
     662           0 :             date > monthLength(internalGet(UCAL_MONTH))) {
     663           0 :                 return FALSE;
     664             :             }
     665             :     }
     666             : 
     667           0 :     if (isSet(UCAL_DAY_OF_YEAR)) {
     668           0 :         int32_t days = internalGet(UCAL_DAY_OF_YEAR);
     669           0 :         if (days < 1 || days > yearLength()) {
     670           0 :             return FALSE;
     671             :         }
     672             :     }
     673             : 
     674             :     // Handle DAY_OF_WEEK_IN_MONTH, which must not have the value zero.
     675             :     // We've checked against minimum and maximum above already.
     676           0 :     if (isSet(UCAL_DAY_OF_WEEK_IN_MONTH) &&
     677           0 :         0 == internalGet(UCAL_DAY_OF_WEEK_IN_MONTH)) {
     678           0 :             return FALSE;
     679             :         }
     680             : 
     681           0 :         return TRUE;
     682             : }
     683             : 
     684             : // -------------------------------------
     685             : 
     686             : UBool
     687           0 : GregorianCalendar::boundsCheck(int32_t value, UCalendarDateFields field) const
     688             : {
     689           0 :     return value >= getMinimum(field) && value <= getMaximum(field);
     690             : }
     691             : 
     692             : // -------------------------------------
     693             : 
     694             : UDate 
     695           0 : GregorianCalendar::getEpochDay(UErrorCode& status) 
     696             : {
     697           0 :     complete(status);
     698             :     // Divide by 1000 (convert to seconds) in order to prevent overflow when
     699             :     // dealing with UDate(Long.MIN_VALUE) and UDate(Long.MAX_VALUE).
     700           0 :     double wallSec = internalGetTime()/1000 + (internalGet(UCAL_ZONE_OFFSET) + internalGet(UCAL_DST_OFFSET))/1000;
     701             : 
     702           0 :     return ClockMath::floorDivide(wallSec, kOneDay/1000.0);
     703             : }
     704             : 
     705             : // -------------------------------------
     706             : 
     707             : 
     708             : // -------------------------------------
     709             : 
     710             : /**
     711             : * Compute the julian day number of the day BEFORE the first day of
     712             : * January 1, year 1 of the given calendar.  If julianDay == 0, it
     713             : * specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian
     714             : * or Gregorian).
     715             : */
     716           0 : double GregorianCalendar::computeJulianDayOfYear(UBool isGregorian,
     717             :                                                  int32_t year, UBool& isLeap)
     718             : {
     719           0 :     isLeap = year%4 == 0;
     720           0 :     int32_t y = year - 1;
     721           0 :     double julianDay = 365.0*y + ClockMath::floorDivide(y, 4) + (kJan1_1JulianDay - 3);
     722             : 
     723           0 :     if (isGregorian) {
     724           0 :         isLeap = isLeap && ((year%100 != 0) || (year%400 == 0));
     725             :         // Add 2 because Gregorian calendar starts 2 days after Julian calendar
     726           0 :         julianDay += Grego::gregorianShift(year);
     727             :     }
     728             : 
     729           0 :     return julianDay;
     730             : }
     731             : 
     732             : // /**
     733             : //  * Compute the day of week, relative to the first day of week, from
     734             : //  * 0..6, of the current DOW_LOCAL or DAY_OF_WEEK fields.  This is
     735             : //  * equivalent to get(DOW_LOCAL) - 1.
     736             : //  */
     737             : // int32_t GregorianCalendar::computeRelativeDOW() const {
     738             : //     int32_t relDow = 0;
     739             : //     if (fStamp[UCAL_DOW_LOCAL] > fStamp[UCAL_DAY_OF_WEEK]) {
     740             : //         relDow = internalGet(UCAL_DOW_LOCAL) - 1; // 1-based
     741             : //     } else if (fStamp[UCAL_DAY_OF_WEEK] != kUnset) {
     742             : //         relDow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();
     743             : //         if (relDow < 0) relDow += 7;
     744             : //     }
     745             : //     return relDow;
     746             : // }
     747             : 
     748             : // /**
     749             : //  * Compute the day of week, relative to the first day of week,
     750             : //  * from 0..6 of the given julian day.
     751             : //  */
     752             : // int32_t GregorianCalendar::computeRelativeDOW(double julianDay) const {
     753             : //   int32_t relDow = julianDayToDayOfWeek(julianDay) - getFirstDayOfWeek();
     754             : //     if (relDow < 0) {
     755             : //         relDow += 7;
     756             : //     }
     757             : //     return relDow;
     758             : // }
     759             : 
     760             : // /**
     761             : //  * Compute the DOY using the WEEK_OF_YEAR field and the julian day
     762             : //  * of the day BEFORE January 1 of a year (a return value from
     763             : //  * computeJulianDayOfYear).
     764             : //  */
     765             : // int32_t GregorianCalendar::computeDOYfromWOY(double julianDayOfYear) const {
     766             : //     // Compute DOY from day of week plus week of year
     767             : 
     768             : //     // Find the day of the week for the first of this year.  This
     769             : //     // is zero-based, with 0 being the locale-specific first day of
     770             : //     // the week.  Add 1 to get first day of year.
     771             : //     int32_t fdy = computeRelativeDOW(julianDayOfYear + 1);
     772             : 
     773             : //     return
     774             : //         // Compute doy of first (relative) DOW of WOY 1
     775             : //         (((7 - fdy) < getMinimalDaysInFirstWeek())
     776             : //          ? (8 - fdy) : (1 - fdy))
     777             : 
     778             : //         // Adjust for the week number.
     779             : //         + (7 * (internalGet(UCAL_WEEK_OF_YEAR) - 1))
     780             : 
     781             : //         // Adjust for the DOW
     782             : //         + computeRelativeDOW();
     783             : // }
     784             : 
     785             : // -------------------------------------
     786             : 
     787             : double 
     788           0 : GregorianCalendar::millisToJulianDay(UDate millis)
     789             : {
     790           0 :     return (double)kEpochStartAsJulianDay + ClockMath::floorDivide(millis, (double)kOneDay);
     791             : }
     792             : 
     793             : // -------------------------------------
     794             : 
     795             : UDate
     796           0 : GregorianCalendar::julianDayToMillis(double julian)
     797             : {
     798           0 :     return (UDate) ((julian - kEpochStartAsJulianDay) * (double) kOneDay);
     799             : }
     800             : 
     801             : // -------------------------------------
     802             : 
     803             : int32_t
     804           0 : GregorianCalendar::aggregateStamp(int32_t stamp_a, int32_t stamp_b) 
     805             : {
     806           0 :     return (((stamp_a != kUnset && stamp_b != kUnset) 
     807           0 :         ? uprv_max(stamp_a, stamp_b)
     808           0 :         : (int32_t)kUnset));
     809             : }
     810             : 
     811             : // -------------------------------------
     812             : 
     813             : /**
     814             : * Roll a field by a signed amount.
     815             : * Note: This will be made public later. [LIU]
     816             : */
     817             : 
     818             : void 
     819           0 : GregorianCalendar::roll(EDateFields field, int32_t amount, UErrorCode& status) {
     820           0 :     roll((UCalendarDateFields) field, amount, status); 
     821           0 : }
     822             : 
     823             : void
     824           0 : GregorianCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)
     825             : {
     826           0 :     if((amount == 0) || U_FAILURE(status)) {
     827           0 :         return;
     828             :     }
     829             : 
     830             :     // J81 processing. (gregorian cutover)
     831           0 :     UBool inCutoverMonth = FALSE;
     832           0 :     int32_t cMonthLen=0; // 'c' for cutover; in days
     833           0 :     int32_t cDayOfMonth=0; // no discontinuity: [0, cMonthLen)
     834           0 :     double cMonthStart=0.0; // in ms
     835             : 
     836             :     // Common code - see if we're in the cutover month of the cutover year
     837           0 :     if(get(UCAL_EXTENDED_YEAR, status) == fGregorianCutoverYear) {
     838           0 :         switch (field) {
     839             :         case UCAL_DAY_OF_MONTH:
     840             :         case UCAL_WEEK_OF_MONTH:
     841             :             {
     842           0 :                 int32_t max = monthLength(internalGet(UCAL_MONTH));
     843           0 :                 UDate t = internalGetTime();
     844             :                 // We subtract 1 from the DAY_OF_MONTH to make it zero-based, and an
     845             :                 // additional 10 if we are after the cutover. Thus the monthStart
     846             :                 // value will be correct iff we actually are in the cutover month.
     847           0 :                 cDayOfMonth = internalGet(UCAL_DAY_OF_MONTH) - ((t >= fGregorianCutover) ? 10 : 0);
     848           0 :                 cMonthStart = t - ((cDayOfMonth - 1) * kOneDay);
     849             :                 // A month containing the cutover is 10 days shorter.
     850           0 :                 if ((cMonthStart < fGregorianCutover) &&
     851           0 :                     (cMonthStart + (cMonthLen=(max-10))*kOneDay >= fGregorianCutover)) {
     852           0 :                         inCutoverMonth = TRUE;
     853             :                     }
     854             :             }
     855           0 :             break;
     856             :         default:
     857             :             ;
     858             :         }
     859             :     }
     860             : 
     861           0 :     switch (field) {
     862             :     case UCAL_WEEK_OF_YEAR: {
     863             :         // Unlike WEEK_OF_MONTH, WEEK_OF_YEAR never shifts the day of the
     864             :         // week.  Also, rolling the week of the year can have seemingly
     865             :         // strange effects simply because the year of the week of year
     866             :         // may be different from the calendar year.  For example, the
     867             :         // date Dec 28, 1997 is the first day of week 1 of 1998 (if
     868             :         // weeks start on Sunday and the minimal days in first week is
     869             :         // <= 3).
     870           0 :         int32_t woy = get(UCAL_WEEK_OF_YEAR, status);
     871             :         // Get the ISO year, which matches the week of year.  This
     872             :         // may be one year before or after the calendar year.
     873           0 :         int32_t isoYear = get(UCAL_YEAR_WOY, status);
     874           0 :         int32_t isoDoy = internalGet(UCAL_DAY_OF_YEAR);
     875           0 :         if (internalGet(UCAL_MONTH) == UCAL_JANUARY) {
     876           0 :             if (woy >= 52) {
     877           0 :                 isoDoy += handleGetYearLength(isoYear);
     878             :             }
     879             :         } else {
     880           0 :             if (woy == 1) {
     881           0 :                 isoDoy -= handleGetYearLength(isoYear - 1);
     882             :             }
     883             :         }
     884           0 :         woy += amount;
     885             :         // Do fast checks to avoid unnecessary computation:
     886           0 :         if (woy < 1 || woy > 52) {
     887             :             // Determine the last week of the ISO year.
     888             :             // We do this using the standard formula we use
     889             :             // everywhere in this file.  If we can see that the
     890             :             // days at the end of the year are going to fall into
     891             :             // week 1 of the next year, we drop the last week by
     892             :             // subtracting 7 from the last day of the year.
     893           0 :             int32_t lastDoy = handleGetYearLength(isoYear);
     894           0 :             int32_t lastRelDow = (lastDoy - isoDoy + internalGet(UCAL_DAY_OF_WEEK) -
     895           0 :                 getFirstDayOfWeek()) % 7;
     896           0 :             if (lastRelDow < 0) lastRelDow += 7;
     897           0 :             if ((6 - lastRelDow) >= getMinimalDaysInFirstWeek()) lastDoy -= 7;
     898           0 :             int32_t lastWoy = weekNumber(lastDoy, lastRelDow + 1);
     899           0 :             woy = ((woy + lastWoy - 1) % lastWoy) + 1;
     900             :         }
     901           0 :         set(UCAL_WEEK_OF_YEAR, woy);
     902           0 :         set(UCAL_YEAR_WOY,isoYear);
     903           0 :         return;
     904             :                             }
     905             : 
     906             :     case UCAL_DAY_OF_MONTH:
     907           0 :         if( !inCutoverMonth ) { 
     908           0 :             Calendar::roll(field, amount, status);
     909           0 :             return;
     910             :         } else {
     911             :             // [j81] 1582 special case for DOM
     912             :             // The default computation works except when the current month
     913             :             // contains the Gregorian cutover.  We handle this special case
     914             :             // here.  [j81 - aliu]
     915           0 :             double monthLen = cMonthLen * kOneDay;
     916           0 :             double msIntoMonth = uprv_fmod(internalGetTime() - cMonthStart +
     917           0 :                 amount * kOneDay, monthLen);
     918           0 :             if (msIntoMonth < 0) {
     919           0 :                 msIntoMonth += monthLen;
     920             :             }
     921             : #if defined (U_DEBUG_CAL)
     922             :             fprintf(stderr, "%s:%d: roll DOM %d  -> %.0lf ms  \n", 
     923             :                 __FILE__, __LINE__,amount, cMonthLen, cMonthStart+msIntoMonth);
     924             : #endif
     925           0 :             setTimeInMillis(cMonthStart + msIntoMonth, status);
     926           0 :             return;
     927             :         }
     928             : 
     929             :     case UCAL_WEEK_OF_MONTH:
     930           0 :         if( !inCutoverMonth ) { 
     931           0 :             Calendar::roll(field, amount, status);
     932           0 :             return;
     933             :         } else {
     934             : #if defined (U_DEBUG_CAL)
     935             :             fprintf(stderr, "%s:%d: roll WOM %d ??????????????????? \n", 
     936             :                 __FILE__, __LINE__,amount);
     937             : #endif
     938             :             // NOTE: following copied from  the old
     939             :             //     GregorianCalendar::roll( WEEK_OF_MONTH )  code 
     940             : 
     941             :             // This is tricky, because during the roll we may have to shift
     942             :             // to a different day of the week.  For example:
     943             : 
     944             :             //    s  m  t  w  r  f  s
     945             :             //          1  2  3  4  5
     946             :             //    6  7  8  9 10 11 12
     947             : 
     948             :             // When rolling from the 6th or 7th back one week, we go to the
     949             :             // 1st (assuming that the first partial week counts).  The same
     950             :             // thing happens at the end of the month.
     951             : 
     952             :             // The other tricky thing is that we have to figure out whether
     953             :             // the first partial week actually counts or not, based on the
     954             :             // minimal first days in the week.  And we have to use the
     955             :             // correct first day of the week to delineate the week
     956             :             // boundaries.
     957             : 
     958             :             // Here's our algorithm.  First, we find the real boundaries of
     959             :             // the month.  Then we discard the first partial week if it
     960             :             // doesn't count in this locale.  Then we fill in the ends with
     961             :             // phantom days, so that the first partial week and the last
     962             :             // partial week are full weeks.  We then have a nice square
     963             :             // block of weeks.  We do the usual rolling within this block,
     964             :             // as is done elsewhere in this method.  If we wind up on one of
     965             :             // the phantom days that we added, we recognize this and pin to
     966             :             // the first or the last day of the month.  Easy, eh?
     967             : 
     968             :             // Another wrinkle: To fix jitterbug 81, we have to make all this
     969             :             // work in the oddball month containing the Gregorian cutover.
     970             :             // This month is 10 days shorter than usual, and also contains
     971             :             // a discontinuity in the days; e.g., the default cutover month
     972             :             // is Oct 1582, and goes from day of month 4 to day of month 15.
     973             : 
     974             :             // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
     975             :             // in this locale.  We have dow in 0..6.
     976           0 :             int32_t dow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();
     977           0 :             if (dow < 0) 
     978           0 :                 dow += 7;
     979             : 
     980             :             // Find the day of month, compensating for cutover discontinuity.
     981           0 :             int32_t dom = cDayOfMonth;
     982             : 
     983             :             // Find the day of the week (normalized for locale) for the first
     984             :             // of the month.
     985           0 :             int32_t fdm = (dow - dom + 1) % 7;
     986           0 :             if (fdm < 0) 
     987           0 :                 fdm += 7;
     988             : 
     989             :             // Get the first day of the first full week of the month,
     990             :             // including phantom days, if any.  Figure out if the first week
     991             :             // counts or not; if it counts, then fill in phantom days.  If
     992             :             // not, advance to the first real full week (skip the partial week).
     993             :             int32_t start;
     994           0 :             if ((7 - fdm) < getMinimalDaysInFirstWeek())
     995           0 :                 start = 8 - fdm; // Skip the first partial week
     996             :             else
     997           0 :                 start = 1 - fdm; // This may be zero or negative
     998             : 
     999             :             // Get the day of the week (normalized for locale) for the last
    1000             :             // day of the month.
    1001           0 :             int32_t monthLen = cMonthLen;
    1002           0 :             int32_t ldm = (monthLen - dom + dow) % 7;
    1003             :             // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.
    1004             : 
    1005             :             // Get the limit day for the blocked-off rectangular month; that
    1006             :             // is, the day which is one past the last day of the month,
    1007             :             // after the month has already been filled in with phantom days
    1008             :             // to fill out the last week.  This day has a normalized DOW of 0.
    1009           0 :             int32_t limit = monthLen + 7 - ldm;
    1010             : 
    1011             :             // Now roll between start and (limit - 1).
    1012           0 :             int32_t gap = limit - start;
    1013           0 :             int32_t newDom = (dom + amount*7 - start) % gap;
    1014           0 :             if (newDom < 0) 
    1015           0 :                 newDom += gap;
    1016           0 :             newDom += start;
    1017             : 
    1018             :             // Finally, pin to the real start and end of the month.
    1019           0 :             if (newDom < 1) 
    1020           0 :                 newDom = 1;
    1021           0 :             if (newDom > monthLen) 
    1022           0 :                 newDom = monthLen;
    1023             : 
    1024             :             // Set the DAY_OF_MONTH.  We rely on the fact that this field
    1025             :             // takes precedence over everything else (since all other fields
    1026             :             // are also set at this point).  If this fact changes (if the
    1027             :             // disambiguation algorithm changes) then we will have to unset
    1028             :             // the appropriate fields here so that DAY_OF_MONTH is attended
    1029             :             // to.
    1030             : 
    1031             :             // If we are in the cutover month, manipulate ms directly.  Don't do
    1032             :             // this in general because it doesn't work across DST boundaries
    1033             :             // (details, details).  This takes care of the discontinuity.
    1034           0 :             setTimeInMillis(cMonthStart + (newDom-1)*kOneDay, status);                
    1035           0 :             return;
    1036             :         }
    1037             : 
    1038             :     default:
    1039           0 :         Calendar::roll(field, amount, status);
    1040           0 :         return;
    1041             :     }
    1042             : }
    1043             : 
    1044             : // -------------------------------------
    1045             : 
    1046             : 
    1047             : /**
    1048             : * Return the minimum value that this field could have, given the current date.
    1049             : * For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum().
    1050             : * @param field    the time field.
    1051             : * @return         the minimum value that this field could have, given the current date.
    1052             : * @deprecated ICU 2.6. Use getActualMinimum(UCalendarDateFields field) instead.
    1053             : */
    1054           0 : int32_t GregorianCalendar::getActualMinimum(EDateFields field) const
    1055             : {
    1056           0 :     return getMinimum((UCalendarDateFields)field);
    1057             : }
    1058             : 
    1059           0 : int32_t GregorianCalendar::getActualMinimum(EDateFields field, UErrorCode& /* status */) const
    1060             : {
    1061           0 :     return getMinimum((UCalendarDateFields)field);
    1062             : }
    1063             : 
    1064             : /**
    1065             : * Return the minimum value that this field could have, given the current date.
    1066             : * For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum().
    1067             : * @param field    the time field.
    1068             : * @return         the minimum value that this field could have, given the current date.
    1069             : * @draft ICU 2.6.
    1070             : */
    1071           0 : int32_t GregorianCalendar::getActualMinimum(UCalendarDateFields field, UErrorCode& /* status */) const
    1072             : {
    1073           0 :     return getMinimum(field);
    1074             : }
    1075             : 
    1076             : 
    1077             : // ------------------------------------
    1078             : 
    1079             : /**
    1080             : * Old year limits were least max 292269054, max 292278994.
    1081             : */
    1082             : 
    1083             : /**
    1084             : * @stable ICU 2.0
    1085             : */
    1086           0 : int32_t GregorianCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
    1087           0 :     return kGregorianCalendarLimits[field][limitType];
    1088             : }
    1089             : 
    1090             : /**
    1091             : * Return the maximum value that this field could have, given the current date.
    1092             : * For example, with the date "Feb 3, 1997" and the DAY_OF_MONTH field, the actual
    1093             : * maximum would be 28; for "Feb 3, 1996" it s 29.  Similarly for a Hebrew calendar,
    1094             : * for some years the actual maximum for MONTH is 12, and for others 13.
    1095             : * @stable ICU 2.0
    1096             : */
    1097           0 : int32_t GregorianCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const
    1098             : {
    1099             :     /* It is a known limitation that the code here (and in getActualMinimum)
    1100             :     * won't behave properly at the extreme limits of GregorianCalendar's
    1101             :     * representable range (except for the code that handles the YEAR
    1102             :     * field).  That's because the ends of the representable range are at
    1103             :     * odd spots in the year.  For calendars with the default Gregorian
    1104             :     * cutover, these limits are Sun Dec 02 16:47:04 GMT 292269055 BC to Sun
    1105             :     * Aug 17 07:12:55 GMT 292278994 AD, somewhat different for non-GMT
    1106             :     * zones.  As a result, if the calendar is set to Aug 1 292278994 AD,
    1107             :     * the actual maximum of DAY_OF_MONTH is 17, not 30.  If the date is Mar
    1108             :     * 31 in that year, the actual maximum month might be Jul, whereas is
    1109             :     * the date is Mar 15, the actual maximum might be Aug -- depending on
    1110             :     * the precise semantics that are desired.  Similar considerations
    1111             :     * affect all fields.  Nonetheless, this effect is sufficiently arcane
    1112             :     * that we permit it, rather than complicating the code to handle such
    1113             :     * intricacies. - liu 8/20/98
    1114             : 
    1115             :     * UPDATE: No longer true, since we have pulled in the limit values on
    1116             :     * the year. - Liu 11/6/00 */
    1117             : 
    1118           0 :     switch (field) {
    1119             : 
    1120             :     case UCAL_YEAR:
    1121             :         /* The year computation is no different, in principle, from the
    1122             :         * others, however, the range of possible maxima is large.  In
    1123             :         * addition, the way we know we've exceeded the range is different.
    1124             :         * For these reasons, we use the special case code below to handle
    1125             :         * this field.
    1126             :         *
    1127             :         * The actual maxima for YEAR depend on the type of calendar:
    1128             :         *
    1129             :         *     Gregorian = May 17, 292275056 BC - Aug 17, 292278994 AD
    1130             :         *     Julian    = Dec  2, 292269055 BC - Jan  3, 292272993 AD
    1131             :         *     Hybrid    = Dec  2, 292269055 BC - Aug 17, 292278994 AD
    1132             :         *
    1133             :         * We know we've exceeded the maximum when either the month, date,
    1134             :         * time, or era changes in response to setting the year.  We don't
    1135             :         * check for month, date, and time here because the year and era are
    1136             :         * sufficient to detect an invalid year setting.  NOTE: If code is
    1137             :         * added to check the month and date in the future for some reason,
    1138             :         * Feb 29 must be allowed to shift to Mar 1 when setting the year.
    1139             :         */
    1140             :         {
    1141           0 :             if(U_FAILURE(status)) return 0;
    1142           0 :             Calendar *cal = clone();
    1143           0 :             if(!cal) {
    1144           0 :                 status = U_MEMORY_ALLOCATION_ERROR;
    1145           0 :                 return 0;
    1146             :             }
    1147             : 
    1148           0 :             cal->setLenient(TRUE);
    1149             : 
    1150           0 :             int32_t era = cal->get(UCAL_ERA, status);
    1151           0 :             UDate d = cal->getTime(status);
    1152             : 
    1153             :             /* Perform a binary search, with the invariant that lowGood is a
    1154             :             * valid year, and highBad is an out of range year.
    1155             :             */
    1156           0 :             int32_t lowGood = kGregorianCalendarLimits[UCAL_YEAR][1];
    1157           0 :             int32_t highBad = kGregorianCalendarLimits[UCAL_YEAR][2]+1;
    1158           0 :             while ((lowGood + 1) < highBad) {
    1159           0 :                 int32_t y = (lowGood + highBad) / 2;
    1160           0 :                 cal->set(UCAL_YEAR, y);
    1161           0 :                 if (cal->get(UCAL_YEAR, status) == y && cal->get(UCAL_ERA, status) == era) {
    1162           0 :                     lowGood = y;
    1163             :                 } else {
    1164           0 :                     highBad = y;
    1165           0 :                     cal->setTime(d, status); // Restore original fields
    1166             :                 }
    1167             :             }
    1168             : 
    1169           0 :             delete cal;
    1170           0 :             return lowGood;
    1171             :         }
    1172             : 
    1173             :     default:
    1174           0 :         return Calendar::getActualMaximum(field,status);
    1175             :     }
    1176             : }
    1177             : 
    1178             : 
    1179           0 : int32_t GregorianCalendar::handleGetExtendedYear() {
    1180             :     // the year to return
    1181           0 :     int32_t year = kEpochYear;
    1182             : 
    1183             :     // year field to use
    1184           0 :     int32_t yearField = UCAL_EXTENDED_YEAR;
    1185             : 
    1186             :     // There are three separate fields which could be used to
    1187             :     // derive the proper year.  Use the one most recently set.
    1188           0 :     if (fStamp[yearField] < fStamp[UCAL_YEAR])
    1189           0 :         yearField = UCAL_YEAR;
    1190           0 :     if (fStamp[yearField] < fStamp[UCAL_YEAR_WOY])
    1191           0 :         yearField = UCAL_YEAR_WOY;
    1192             : 
    1193             :     // based on the "best" year field, get the year
    1194           0 :     switch(yearField) {
    1195             :     case UCAL_EXTENDED_YEAR:
    1196           0 :         year = internalGet(UCAL_EXTENDED_YEAR, kEpochYear);
    1197           0 :         break;
    1198             : 
    1199             :     case UCAL_YEAR:
    1200             :         {
    1201             :             // The year defaults to the epoch start, the era to AD
    1202           0 :             int32_t era = internalGet(UCAL_ERA, AD);
    1203           0 :             if (era == BC) {
    1204           0 :                 year = 1 - internalGet(UCAL_YEAR, 1); // Convert to extended year
    1205             :             } else {
    1206           0 :                 year = internalGet(UCAL_YEAR, kEpochYear);
    1207             :             }
    1208             :         }
    1209           0 :         break;
    1210             : 
    1211             :     case UCAL_YEAR_WOY:
    1212           0 :         year = handleGetExtendedYearFromWeekFields(internalGet(UCAL_YEAR_WOY), internalGet(UCAL_WEEK_OF_YEAR));
    1213             : #if defined (U_DEBUG_CAL)
    1214             :         //    if(internalGet(UCAL_YEAR_WOY) != year) {
    1215             :         fprintf(stderr, "%s:%d: hGEYFWF[%d,%d] ->  %d\n", 
    1216             :             __FILE__, __LINE__,internalGet(UCAL_YEAR_WOY),internalGet(UCAL_WEEK_OF_YEAR),year);
    1217             :         //}
    1218             : #endif
    1219           0 :         break;
    1220             : 
    1221             :     default:
    1222           0 :         year = kEpochYear;
    1223             :     }
    1224           0 :     return year;
    1225             : }
    1226             : 
    1227           0 : int32_t GregorianCalendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t woy)
    1228             : {
    1229             :     // convert year to extended form
    1230           0 :     int32_t era = internalGet(UCAL_ERA, AD);
    1231           0 :     if(era == BC) {
    1232           0 :         yearWoy = 1 - yearWoy;
    1233             :     }
    1234           0 :     return Calendar::handleGetExtendedYearFromWeekFields(yearWoy, woy);
    1235             : }
    1236             : 
    1237             : 
    1238             : // -------------------------------------
    1239             : 
    1240             : UBool
    1241           0 : GregorianCalendar::inDaylightTime(UErrorCode& status) const
    1242             : {
    1243           0 :     if (U_FAILURE(status) || !getTimeZone().useDaylightTime()) 
    1244           0 :         return FALSE;
    1245             : 
    1246             :     // Force an update of the state of the Calendar.
    1247           0 :     ((GregorianCalendar*)this)->complete(status); // cast away const
    1248             : 
    1249           0 :     return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
    1250             : }
    1251             : 
    1252             : // -------------------------------------
    1253             : 
    1254             : /**
    1255             : * Return the ERA.  We need a special method for this because the
    1256             : * default ERA is AD, but a zero (unset) ERA is BC.
    1257             : */
    1258             : int32_t
    1259           0 : GregorianCalendar::internalGetEra() const {
    1260           0 :     return isSet(UCAL_ERA) ? internalGet(UCAL_ERA) : (int32_t)AD;
    1261             : }
    1262             : 
    1263             : const char *
    1264           0 : GregorianCalendar::getType() const {
    1265             :     //static const char kGregorianType = "gregorian";
    1266             : 
    1267           0 :     return "gregorian";
    1268             : }
    1269             : 
    1270             : /**
    1271             :  * The system maintains a static default century start date and Year.  They are
    1272             :  * initialized the first time they are used.  Once the system default century date 
    1273             :  * and year are set, they do not change.
    1274             :  */
    1275             : static UDate           gSystemDefaultCenturyStart       = DBL_MIN;
    1276             : static int32_t         gSystemDefaultCenturyStartYear   = -1;
    1277             : static icu::UInitOnce  gSystemDefaultCenturyInit        = U_INITONCE_INITIALIZER;
    1278             : 
    1279             : 
    1280           0 : UBool GregorianCalendar::haveDefaultCentury() const
    1281             : {
    1282           0 :     return TRUE;
    1283             : }
    1284             : 
    1285             : static void U_CALLCONV
    1286           0 : initializeSystemDefaultCentury()
    1287             : {
    1288             :     // initialize systemDefaultCentury and systemDefaultCenturyYear based
    1289             :     // on the current time.  They'll be set to 80 years before
    1290             :     // the current time.
    1291           0 :     UErrorCode status = U_ZERO_ERROR;
    1292           0 :     GregorianCalendar calendar(status);
    1293           0 :     if (U_SUCCESS(status)) {
    1294           0 :         calendar.setTime(Calendar::getNow(), status);
    1295           0 :         calendar.add(UCAL_YEAR, -80, status);
    1296             : 
    1297           0 :         gSystemDefaultCenturyStart = calendar.getTime(status);
    1298           0 :         gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status);
    1299             :     }
    1300             :     // We have no recourse upon failure unless we want to propagate the failure
    1301             :     // out.
    1302           0 : }
    1303             : 
    1304           0 : UDate GregorianCalendar::defaultCenturyStart() const {
    1305             :     // lazy-evaluate systemDefaultCenturyStart
    1306           0 :     umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
    1307           0 :     return gSystemDefaultCenturyStart;
    1308             : }
    1309             : 
    1310           0 : int32_t GregorianCalendar::defaultCenturyStartYear() const {
    1311             :     // lazy-evaluate systemDefaultCenturyStartYear
    1312           0 :     umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
    1313           0 :     return gSystemDefaultCenturyStartYear;
    1314             : }
    1315             : 
    1316             : U_NAMESPACE_END
    1317             : 
    1318             : #endif /* #if !UCONFIG_NO_FORMATTING */
    1319             : 
    1320             : //eof

Generated by: LCOV version 1.13