intl/icu/source/i18n/gregocal.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

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

mercurial