home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / i18n / gregocal.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-19  |  68.1 KB  |  1,810 lines

  1. /*
  2. ********************************************************************************
  3. *                                                                              *
  4. * COPYRIGHT:                                                                   *
  5. *   (C) Copyright Taligent, Inc.,  1997                                        *
  6. *   (C) Copyright International Business Machines Corporation,  1997-1998      *
  7. *   Copyright (C) 1999 Alan Liu and others. All rights reserved.               *
  8. *   Licensed Material - Program-Property of IBM - All Rights Reserved.         *
  9. *   US Government Users Restricted Rights - Use, duplication, or disclosure    *
  10. *   restricted by GSA ADP Schedule Contract with IBM Corp.                     *
  11. *                                                                              *
  12. ********************************************************************************
  13. *
  14. * File GREGOCAL.CPP
  15. *
  16. * Modification History:
  17. *
  18. *   Date        Name        Description
  19. *   02/05/97    clhuang     Creation.
  20. *   03/28/97    aliu        Made highly questionable fix to computeFields to
  21. *                           handle DST correctly.
  22. *   04/22/97    aliu        Cleaned up code drastically.  Added monthLength().
  23. *                           Finished unimplemented parts of computeTime() for
  24. *                           week-based date determination.  Removed quetionable
  25. *                           fix and wrote correct fix for computeFields() and
  26. *                           daylight time handling.  Rewrote inDaylightTime()
  27. *                           and computeFields() to handle sensitive Daylight to
  28. *                           Standard time transitions correctly.
  29. *   05/08/97    aliu        Added code review changes.  Fixed isLeapYear() to
  30. *                           not cutover.
  31. *   08/12/97    aliu        Added equivalentTo.  Misc other fixes.  Updated
  32. *                           add() from Java source.
  33. *    07/28/98    stephen        Sync up with JDK 1.2
  34. *    09/14/98    stephen        Changed type of kOneDay, kOneWeek to double.
  35. *                            Fixed bug in roll() 
  36. *   10/15/99    aliu        Fixed j31, incorrect WEEK_OF_YEAR computation.
  37. *   10/15/99    aliu        Fixed j32, cannot set date to Feb 29 2000 AD.
  38. *                           {JDK bug 4210209 4209272}
  39. ********************************************************************************
  40. */
  41.  
  42. #ifndef _GREGOCAL
  43. #include "gregocal.h"
  44. #endif
  45.  
  46. // *****************************************************************************
  47. // class GregorianCalendar
  48. // *****************************************************************************
  49.  
  50.  
  51. const int32_t GregorianCalendar::kJan1_1JulianDay = 1721426; // January 1, year 1 (Gregorian)
  52.  
  53. /**
  54.  * Note that the Julian date used here is not a true Julian date, since
  55.  * it is measured from midnight, not noon.  This value is the Julian
  56.  * day number of January 1, 1970 (Gregorian calendar) at noon UTC. [LIU]
  57.  */
  58. const int32_t GregorianCalendar::kEpochStartAsJulianDay    = 2440588; // January 1, 1970 (Gregorian)
  59.  
  60. const int32_t GregorianCalendar::kEpochYear             = 1970;
  61.  
  62. const int32_t GregorianCalendar::kNumDays[]
  63.     = {0,31,59,90,120,151,181,212,243,273,304,334}; // 0-based, for day-in-year
  64. const int32_t GregorianCalendar::kLeapNumDays[]
  65.     = {0,31,60,91,121,152,182,213,244,274,305,335}; // 0-based, for day-in-year
  66. const int32_t GregorianCalendar::kMonthLength[]
  67.     = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
  68. const int32_t GregorianCalendar::kLeapMonthLength[]
  69.     = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
  70.  
  71. // Useful millisecond constants
  72. const int32_t GregorianCalendar::kOneSecond = 1000;
  73. const int32_t GregorianCalendar::kOneMinute = 60   * kOneSecond;     //      60,000
  74. const int32_t GregorianCalendar::kOneHour   = 60   * kOneMinute;    //   3,600,000
  75. const double  GregorianCalendar::kOneDay    = 24.0 * kOneHour;        //  86,400,000
  76. const double  GregorianCalendar::kOneWeek   = 7.0  * kOneDay;        // 604,800,000
  77.  
  78. // These numbers are 2^52 - 1, the largest allowable mantissa in a 64-bit double
  79. // with a 0 exponent.  These are the absolute largest numbers for millis that
  80. // this calendar will handle reliably.  It will work for larger values, however.
  81. // The problem is that, once the exponent is not 0, the calendar will jump.
  82. // When translated into a year, LATEST_SUPPORTED_MILLIS corresponds to 144,683 AD 
  83. // and EARLIEST_SUPPORTED_MILLIS corresponds to 140,742 BC
  84. const UDate GregorianCalendar::EARLIEST_SUPPORTED_MILLIS = - 4503599627370495.0;
  85. const UDate GregorianCalendar::LATEST_SUPPORTED_MILLIS    =   4503599627370495.0;
  86.  
  87. /*
  88.  * <pre>
  89.  *                            Greatest       Least 
  90.  * Field name        Minimum   Minimum     Maximum     Maximum
  91.  * ----------        -------   -------     -------     -------
  92.  * ERA                     0         0           1           1
  93.  * YEAR                    1         1      140742      144683
  94.  * MONTH                   0         0          11          11
  95.  * WEEK_OF_YEAR            1         1          52          53
  96.  * WEEK_OF_MONTH           0         0           4           6
  97.  * DAY_OF_MONTH            1         1          28          31
  98.  * DAY_OF_YEAR             1         1         365         366
  99.  * DAY_OF_WEEK             1         1           7           7
  100.  * DAY_OF_WEEK_IN_MONTH   -1        -1           4           6
  101.  * AM_PM                   0         0           1           1
  102.  * HOUR                    0         0          11          11
  103.  * HOUR_OF_DAY             0         0          23          23
  104.  * MINUTE                  0         0          59          59
  105.  * SECOND                  0         0          59          59
  106.  * MILLISECOND             0         0         999         999
  107.  * ZONE_OFFSET           -12*      -12*         12*         12*
  108.  * DST_OFFSET              0         0           1*          1*
  109.  * </pre>
  110.  * (*) In units of one-hour
  111.  */
  112. const int32_t GregorianCalendar::kMinValues[] = {
  113.     0,1,0,1,0,1,1,1,-1,0,0,0,0,0,0,-12*U_MILLIS_PER_HOUR,0
  114. };
  115. const int32_t GregorianCalendar::kLeastMaxValues[] = {
  116.     1,140742,11,52,4,28,365,7,4,1,11,23,59,59,999,12*U_MILLIS_PER_HOUR,1*U_MILLIS_PER_HOUR
  117. };
  118. const int32_t GregorianCalendar::kMaxValues[] = {
  119.     1,144683,11,53,6,31,366,7,6,1,11,23,59,59,999,12*U_MILLIS_PER_HOUR,1*U_MILLIS_PER_HOUR
  120. };
  121.  
  122. char GregorianCalendar::fgClassID = 0; // Value is irrelevant
  123.  
  124. // 00:00:00 UTC, October 15, 1582, expressed in ms from the epoch.
  125. // Note that only Italy and other Catholic countries actually
  126. // observed this cutover.  Most other countries followed in
  127. // the next few centuries, some as late as 1928. [LIU]
  128. // in Java, -12219292800000L
  129. //const UDate GregorianCalendar::kPapalCutover = -12219292800000L;
  130. const UDate GregorianCalendar::kPapalCutover = (2299161.0 - kEpochStartAsJulianDay) * kOneDay;
  131.  
  132. // -------------------------------------
  133.  
  134. GregorianCalendar::GregorianCalendar(UErrorCode& status)
  135.     :   Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
  136.         fGregorianCutover(kPapalCutover),
  137.         fNormalizedGregorianCutover(fGregorianCutover),
  138.         fGregorianCutoverYear(1582)
  139. {
  140.     setTimeInMillis(getNow(), status);
  141. }
  142.  
  143. // -------------------------------------
  144.  
  145. GregorianCalendar::GregorianCalendar(TimeZone* zone, UErrorCode& status)
  146.     :   Calendar(zone, Locale::getDefault(), status),
  147.         fGregorianCutover(kPapalCutover),
  148.         fNormalizedGregorianCutover(fGregorianCutover),
  149.         fGregorianCutoverYear(1582)
  150. {
  151.     setTimeInMillis(getNow(), status);
  152. }
  153.  
  154. // -------------------------------------
  155.  
  156. GregorianCalendar::GregorianCalendar(const TimeZone& zone, UErrorCode& status)
  157.     :   Calendar(zone, Locale::getDefault(), status),
  158.         fGregorianCutover(kPapalCutover),
  159.         fNormalizedGregorianCutover(fGregorianCutover),
  160.         fGregorianCutoverYear(1582)
  161. {
  162.     setTimeInMillis(getNow(), status);
  163. }
  164.  
  165. // -------------------------------------
  166.  
  167. GregorianCalendar::GregorianCalendar(const Locale& aLocale, UErrorCode& status)
  168.     :   Calendar(TimeZone::createDefault(), aLocale, status),
  169.         fGregorianCutover(kPapalCutover),
  170.         fNormalizedGregorianCutover(fGregorianCutover),
  171.         fGregorianCutoverYear(1582)
  172. {
  173.     setTimeInMillis(getNow(), status);
  174. }
  175.  
  176. // -------------------------------------
  177.  
  178. GregorianCalendar::GregorianCalendar(TimeZone* zone, const Locale& aLocale,
  179.                                      UErrorCode& status)
  180.     :   Calendar(zone, aLocale, status),
  181.         fGregorianCutover(kPapalCutover),
  182.         fNormalizedGregorianCutover(fGregorianCutover),
  183.         fGregorianCutoverYear(1582)
  184. {
  185.     setTimeInMillis(getNow(), status);
  186. }
  187.  
  188. // -------------------------------------
  189.  
  190. GregorianCalendar::GregorianCalendar(const TimeZone& zone, const Locale& aLocale,
  191.                                      UErrorCode& status)
  192.     :   Calendar(zone, aLocale, status),
  193.         fGregorianCutover(kPapalCutover),
  194.         fNormalizedGregorianCutover(fGregorianCutover),
  195.         fGregorianCutoverYear(1582)
  196. {
  197.     setTimeInMillis(getNow(), status);
  198. }
  199.  
  200. // -------------------------------------
  201.  
  202. GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
  203.                                      UErrorCode& status)
  204.     :   Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
  205.         fGregorianCutover(kPapalCutover),
  206.         fNormalizedGregorianCutover(fGregorianCutover),
  207.         fGregorianCutoverYear(1582)
  208. {
  209.     set(Calendar::ERA, AD);
  210.     set(Calendar::YEAR, year);
  211.     set(Calendar::MONTH, month);
  212.     set(Calendar::DATE, date);
  213. }
  214.  
  215. // -------------------------------------
  216.  
  217. GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
  218.                                      int32_t hour, int32_t minute, UErrorCode& status)
  219.     :   Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
  220.         fGregorianCutover(kPapalCutover),
  221.         fNormalizedGregorianCutover(fGregorianCutover),
  222.         fGregorianCutoverYear(1582)
  223. {
  224.     set(Calendar::ERA, AD);
  225.     set(Calendar::YEAR, year);
  226.     set(Calendar::MONTH, month);
  227.     set(Calendar::DATE, date);
  228.     set(Calendar::HOUR_OF_DAY, hour);
  229.     set(Calendar::MINUTE, minute);
  230. }
  231.  
  232. // -------------------------------------
  233.  
  234. GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
  235.                                      int32_t hour, int32_t minute, int32_t second,
  236.                                      UErrorCode& status)
  237.     :   Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
  238.         fGregorianCutover(kPapalCutover),
  239.         fNormalizedGregorianCutover(fGregorianCutover),
  240.         fGregorianCutoverYear(1582)
  241. {
  242.     set(Calendar::ERA, AD);
  243.     set(Calendar::YEAR, year);
  244.     set(Calendar::MONTH, month);
  245.     set(Calendar::DATE, date);
  246.     set(Calendar::HOUR_OF_DAY, hour);
  247.     set(Calendar::MINUTE, minute);
  248.     set(Calendar::SECOND, second);
  249. }
  250.  
  251. // -------------------------------------
  252.  
  253. GregorianCalendar::~GregorianCalendar()
  254. {
  255. }
  256.  
  257. // -------------------------------------
  258.  
  259. GregorianCalendar::GregorianCalendar(const GregorianCalendar &source)
  260.     :   Calendar(source),
  261.         fGregorianCutover(source.fGregorianCutover),
  262.         fNormalizedGregorianCutover(source.fNormalizedGregorianCutover),
  263.         fGregorianCutoverYear(source.fGregorianCutoverYear)
  264. {
  265. }
  266.  
  267. // -------------------------------------
  268.  
  269. Calendar* GregorianCalendar::clone() const
  270. {
  271.     return new GregorianCalendar(*this);
  272. }
  273.  
  274. // -------------------------------------
  275.  
  276. GregorianCalendar &
  277. GregorianCalendar::operator=(const GregorianCalendar &right)
  278. {
  279.     if (this != &right)
  280.     {
  281.         Calendar::operator=(right);
  282.         fGregorianCutover = right.fGregorianCutover;
  283.         fNormalizedGregorianCutover = right.fNormalizedGregorianCutover;
  284.         fGregorianCutoverYear = right.fGregorianCutoverYear;
  285.     }
  286.     return *this;
  287. }
  288.  
  289. // -------------------------------------
  290.  
  291. bool_t
  292. GregorianCalendar::operator==(const Calendar& that) const
  293. {
  294.     GregorianCalendar* other = (GregorianCalendar*)&that;
  295.  
  296.     return (this == &that) ||
  297.         (Calendar::operator==(that) &&
  298.          getDynamicClassID() == that.getDynamicClassID() &&
  299.          fGregorianCutover == other->fGregorianCutover);
  300. }
  301.  
  302. // {sfb} API change?
  303. bool_t GregorianCalendar::equivalentTo(const Calendar& other) const
  304. {
  305.     // Calendar override.
  306.     // Return true if another Calendar object is equivalent to this one.  An equivalent
  307.     // Calendar will behave exactly as this one does, but may be set to a different time.
  308.     return Calendar::equivalentTo(other) &&
  309.         fGregorianCutover == ((GregorianCalendar*)&other)->fGregorianCutover;
  310. }
  311.  
  312. // -------------------------------------
  313.  
  314. void
  315. GregorianCalendar::setGregorianChange(UDate date, UErrorCode& status)
  316. {
  317.     if (U_FAILURE(status)) 
  318.         return;
  319.  
  320.     fGregorianCutover = date;
  321.  
  322.     // Precompute two internal variables which we use to do the actual
  323.     // cutover computations.  These are the normalized cutover, which is the
  324.     // midnight at or before the cutover, and the cutover year.  The
  325.     // normalized cutover is in pure date milliseconds; it contains no time
  326.     // of day or timezone component, and it used to compare against other
  327.     // pure date values.
  328.     UDate cutoverDay = floorDivide(fGregorianCutover, kOneDay);
  329.     fNormalizedGregorianCutover = cutoverDay * kOneDay;
  330.  
  331.     // Handle the rare case of numeric overflow.  If the user specifies a
  332.     // change of UDate(Long.MIN_VALUE), in order to get a pure Gregorian
  333.     // calendar, then the epoch day is -106751991168, which when multiplied
  334.     // by ONE_DAY gives 9223372036794351616 -- the negative value is too
  335.     // large for 64 bits, and overflows into a positive value.  We correct
  336.     // this by using the next day, which for all intents is semantically
  337.     // equivalent.
  338.     if (cutoverDay < 0 && fNormalizedGregorianCutover > 0) {
  339.         fNormalizedGregorianCutover = (cutoverDay + 1) * kOneDay;
  340.     }
  341.  
  342.     // Normalize the year so BC values are represented as 0 and negative
  343.     // values.
  344.     GregorianCalendar *cal = new GregorianCalendar(getTimeZone(), status);
  345.     if(U_FAILURE(status))
  346.         return;
  347.     cal->setTime(date, status);
  348.     fGregorianCutoverYear = cal->get(YEAR, status);
  349.     if (cal->get(ERA, status) == BC) 
  350.         fGregorianCutoverYear = 1 - fGregorianCutoverYear;
  351.     
  352.     delete cal;
  353. }
  354.  
  355. // -------------------------------------
  356.  
  357. UDate
  358. GregorianCalendar::getGregorianChange() const
  359. {
  360.     return fGregorianCutover;
  361. }
  362.  
  363. // -------------------------------------
  364.  
  365. bool_t 
  366. GregorianCalendar::isLeapYear(int32_t year) const
  367. {
  368.     return (year >= fGregorianCutoverYear ?
  369.         ((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))) : // Gregorian
  370.         (year%4 == 0)); // Julian
  371. }
  372.  
  373.  
  374. // -------------------------------------
  375.  
  376. /**
  377.  * Compute the date-based fields given the milliseconds since the epoch start.
  378.  * Do not compute the time-based fields (HOUR, MINUTE, etc.).
  379.  *
  380.  * @param theTime the given time as LOCAL milliseconds, not UTC.
  381.  */
  382. void
  383. GregorianCalendar::timeToFields(UDate theTime, bool_t quick, UErrorCode& status)
  384. {
  385.     if (U_FAILURE(status)) 
  386.         return;
  387.  
  388.     int32_t rawYear;
  389.     int32_t year, month, date, dayOfWeek, dayOfYear, era;
  390.     bool_t isLeap;
  391.  
  392.     // Compute the year, month, and day of month from the given millis
  393.     if (theTime >= fNormalizedGregorianCutover) {
  394.         // The Gregorian epoch day is zero for Monday January 1, year 1.
  395.         double gregorianEpochDay = millisToJulianDay(theTime) - kJan1_1JulianDay;
  396.         // Here we convert from the day number to the multiple radix
  397.         // representation.  We use 400-year, 100-year, and 4-year cycles.
  398.         // For example, the 4-year cycle has 4 years + 1 leap day; giving
  399.         // 1461 == 365*4 + 1 days.
  400.         int32_t rem[1];
  401.         int32_t n400 = floorDivide(gregorianEpochDay, 146097, rem); // 400-year cycle length
  402.         int32_t n100 = floorDivide(rem[0], 36524, rem); // 100-year cycle length
  403.         int32_t n4 = floorDivide(rem[0], 1461, rem); // 4-year cycle length
  404.         int32_t n1 = floorDivide(rem[0], 365, rem);
  405.         rawYear = 400*n400 + 100*n100 + 4*n4 + n1;
  406.         dayOfYear = rem[0]; // zero-based day of year
  407.         if (n100 == 4 || n1 == 4) 
  408.             dayOfYear = 365; // Dec 31 at end of 4- or 400-yr cycle
  409.         else 
  410.             ++rawYear;
  411.         
  412.         isLeap = ((rawYear&0x3) == 0) && // equiv. to (rawYear%4 == 0)
  413.             (rawYear%100 != 0 || rawYear%400 == 0);
  414.         
  415.         // Gregorian day zero is a Monday
  416.         dayOfWeek = (int32_t)icu_fmod(gregorianEpochDay + 1, 7);
  417.     }
  418.     else {
  419.         // The Julian epoch day (not the same as Julian Day)
  420.         // is zero on Saturday December 30, 0 (Gregorian).
  421.         double julianEpochDay = millisToJulianDay(theTime) - (kJan1_1JulianDay - 2);
  422.         rawYear = (int32_t) floorDivide(4*julianEpochDay + 1464, 1461.0);
  423.         
  424.         // Compute the Julian calendar day number for January 1, rawYear
  425.         double january1 = 365.0 * (rawYear - 1) + floorDivide((double)(rawYear - 1), 4.0);
  426.         dayOfYear = (int32_t)(julianEpochDay - january1); // 0-based
  427.         
  428.         // Julian leap years occurred historically every 4 years starting
  429.         // with 8 AD.  Before 8 AD the spacing is irregular; every 3 years
  430.         // from 45 BC to 9 BC, and then none until 8 AD.  However, we don't
  431.         // implement this historical detail; instead, we implement the
  432.         // computatinally cleaner proleptic calendar, which assumes
  433.         // consistent 4-year cycles throughout time.
  434.         isLeap = ((rawYear & 0x3) == 0); // equiv. to (rawYear%4 == 0)
  435.         
  436.         // Julian calendar day zero is a Saturday
  437.         dayOfWeek = (int32_t)icu_fmod(julianEpochDay-1, 7);
  438.     }
  439.     
  440.     // Common Julian/Gregorian calculation
  441.     int32_t correction = 0;
  442.     int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
  443.     if (dayOfYear >= march1) 
  444.         correction = isLeap ? 1 : 2;
  445.     month = (12 * (dayOfYear + correction) + 6) / 367; // zero-based month
  446.     date = dayOfYear -
  447.         (isLeap ? kLeapNumDays[month] : kNumDays[month]) + 1; // one-based DOM
  448.     
  449.     // Normalize day of week
  450.     dayOfWeek += (dayOfWeek < 0) ? (SUNDAY+7) : SUNDAY;
  451.  
  452.     era = AD;
  453.     year = rawYear;
  454.     if (year < 1) {
  455.         era = BC;
  456.         year = 1 - year;
  457.     }
  458.  
  459.     internalSet(ERA, era);
  460.     internalSet(YEAR, year);
  461.     internalSet(MONTH, month + JANUARY); // 0-based
  462.     internalSet(DATE, date);
  463.     internalSet(DAY_OF_WEEK, dayOfWeek);
  464.     internalSet(DAY_OF_YEAR, ++dayOfYear); // Convert from 0-based to 1-based
  465.     if (quick) 
  466.         return;
  467.  
  468.     // Compute the week of the year.  Valid week numbers run from 1 to 52
  469.     // or 53, depending on the year, the first day of the week, and the
  470.     // minimal days in the first week.  Days at the start of the year may
  471.     // fall into the last week of the previous year; days at the end of
  472.     // the year may fall into the first week of the next year.
  473.     int32_t relDow = (dayOfWeek + 7 - getFirstDayOfWeek()) % 7; // 0..6
  474.     int32_t relDowJan1 = (dayOfWeek - dayOfYear + 701 - getFirstDayOfWeek()) % 7; // 0..6
  475.     int32_t woy = (dayOfYear - 1 + relDowJan1) / 7; // 0..53
  476.     if ((7 - relDowJan1) >= getMinimalDaysInFirstWeek()) {
  477.         ++woy;
  478.         // Check to see if we are in the last week; if so, we need
  479.         // to handle the case in which we are the first week of the
  480.         // next year.
  481.         int32_t lastDoy = yearLength();
  482.         int32_t lastRelDow = (relDow + lastDoy - dayOfYear) % 7;
  483.         if (lastRelDow < 0) lastRelDow += 7;
  484.         if (dayOfYear > 359 && // Fast check which eliminates most cases
  485.             (6 - lastRelDow) >= getMinimalDaysInFirstWeek() &&
  486.             (dayOfYear + 7 - relDow) > lastDoy) woy = 1;
  487.     }
  488.     else if (woy == 0) {
  489.         // We are the last week of the previous year.
  490.         int32_t prevDoy = dayOfYear + yearLength(rawYear - 1);
  491.         woy = weekNumber(prevDoy, dayOfWeek);
  492.     }
  493.     internalSet(WEEK_OF_YEAR, woy);
  494.  
  495.     internalSet(WEEK_OF_MONTH, weekNumber(date, dayOfWeek));
  496.     internalSet(DAY_OF_WEEK_IN_MONTH, (date-1) / 7 + 1);
  497. }
  498.  
  499. // -------------------------------------
  500.  
  501. /**
  502.  * Return the week number of a day, within a period. This may be the week number in
  503.  * a year, or the week number in a month. Usually this will be a value >= 1, but if
  504.  * some initial days of the period are excluded from week 1, because
  505.  * minimalDaysInFirstWeek is > 1, then the week number will be zero for those
  506.  * initial days. Requires the day of week for the given date in order to determine
  507.  * the day of week of the first day of the period.
  508.  *
  509.  * @param dayOfPeriod  Day-of-year or day-of-month. Should be 1 for first day of period.
  510.  * @param day   Day-of-week for given dayOfPeriod. 1-based with 1=Sunday.
  511.  * @return      Week number, one-based, or zero if the day falls in part of the
  512.  *              month before the first week, when there are days before the first
  513.  *              week because the minimum days in the first week is more than one.
  514.  */
  515. int32_t
  516. GregorianCalendar::weekNumber(int32_t dayOfPeriod, int32_t dayOfWeek)
  517. {
  518.     // Determine the day of the week of the first day of the period
  519.     // in question (either a year or a month).  Zero represents the
  520.     // first day of the week on this calendar.
  521.     int32_t periodStartDayOfWeek = (dayOfWeek - getFirstDayOfWeek() - dayOfPeriod + 1) % 7;
  522.     if (periodStartDayOfWeek < 0) 
  523.         periodStartDayOfWeek += 7;
  524.     
  525.     // Compute the week number.  Initially, ignore the first week, which
  526.     // may be fractional (or may not be).  We add periodStartDayOfWeek in
  527.     // order to fill out the first week, if it is fractional.
  528.     int32_t weekNo = (dayOfPeriod + periodStartDayOfWeek - 1)/7;
  529.     
  530.     // If the first week is long enough, then count it.  If
  531.     // the minimal days in the first week is one, or if the period start
  532.     // is zero, we always increment weekNo.
  533.     if ((7 - periodStartDayOfWeek) >= getMinimalDaysInFirstWeek()) 
  534.         ++weekNo;
  535.     
  536.     return weekNo;
  537. }
  538.  
  539. // -------------------------------------
  540.  
  541. int32_t
  542. GregorianCalendar::monthLength(int32_t month) const
  543. {
  544.     int32_t year = internalGet(YEAR);
  545.     if(internalGetEra() == BC) {
  546.         year = 1 - year;
  547.     }
  548.  
  549.     return monthLength(month, year);
  550. }
  551.  
  552. // -------------------------------------
  553.  
  554. int32_t
  555. GregorianCalendar::monthLength(int32_t month, int32_t year) const
  556. {
  557.     return isLeapYear(year) ? kLeapMonthLength[month] : kMonthLength[month];
  558. }
  559.  
  560. // -------------------------------------
  561.  
  562. int32_t
  563. GregorianCalendar::yearLength(int32_t year) const
  564. {
  565.     return isLeapYear(year) ? 366 : 365;
  566. }
  567.  
  568. // -------------------------------------
  569.  
  570. int32_t
  571. GregorianCalendar::yearLength() const
  572. {
  573.     return isLeapYear(internalGet(YEAR)) ? 366 : 365;
  574. }
  575.  
  576. // -------------------------------------
  577.  
  578. /**
  579.  * Overrides Calendar
  580.  * Converts UTC as milliseconds to time field values.
  581.  * The time is <em>not</em>
  582.  * recomputed first; to recompute the time, then the fields, call the
  583.  * <code>complete</code> method.
  584.  * @see Calendar#complete
  585.  */
  586. void
  587. GregorianCalendar::computeFields(UErrorCode& status)
  588. {
  589.     if (U_FAILURE(status)) 
  590.         return;
  591.  
  592.     int32_t rawOffset = getTimeZone().getRawOffset();
  593.     double localMillis = internalGetTime() + rawOffset;
  594.  
  595.     /* Check for very extreme values -- millis near Long.MIN_VALUE or
  596.      * Long.MAX_VALUE.  For these values, adding the zone offset can push
  597.      * the millis past MAX_VALUE to MIN_VALUE, or vice versa.  This produces
  598.      * the undesirable effect that the time can wrap around at the ends,
  599.      * yielding, for example, a UDate(Long.MAX_VALUE) with a big BC year
  600.      * (should be AD).  Handle this by pinning such values to Long.MIN_VALUE
  601.      * or Long.MAX_VALUE. - liu 8/11/98 bug 4149677 */
  602.     
  603.     /* {sfb} 9/04/98 
  604.      * Since in C++ we use doubles instead of longs for dates, there is
  605.      * an inherent loss of range in the calendar (because in Java you have all 64
  606.      * bits to store data, while in C++ you have only 52 bits of mantissa.
  607.      * So, I will pin to these (2^52 - 1) values instead */
  608.     
  609.     if(internalGetTime() > 0 && localMillis < 0 && rawOffset > 0) {
  610.         localMillis = LATEST_SUPPORTED_MILLIS;
  611.     } 
  612.     else if(internalGetTime() < 0 && localMillis > 0 && rawOffset < 0) {
  613.         localMillis = EARLIEST_SUPPORTED_MILLIS;
  614.     }
  615.  
  616.     // Time to fields takes the wall millis (Standard or DST).
  617.     timeToFields(localMillis, FALSE, status);
  618.  
  619.     uint8_t era         = (uint8_t) internalGetEra();
  620.     int32_t year         = internalGet(YEAR);
  621.     int32_t month         = internalGet(MONTH);
  622.     int32_t date         = internalGet(DATE);
  623.     uint8_t dayOfWeek     = (uint8_t) internalGet(DAY_OF_WEEK);
  624.  
  625.     double days = icu_floor(localMillis / kOneDay);
  626.     int32_t millisInDay = (int32_t) (localMillis - (days * kOneDay));
  627.     if (millisInDay < 0) 
  628.         millisInDay += U_MILLIS_PER_DAY;
  629.  
  630.     // Call getOffset() to get the TimeZone offset.  The millisInDay value must
  631.     // be standard local millis.
  632.     int32_t dstOffset = getTimeZone().getOffset(era, year, month, date, dayOfWeek, millisInDay,
  633.                                             monthLength(month), status) - rawOffset;
  634.     if(U_FAILURE(status))
  635.         return;
  636.  
  637.     // Adjust our millisInDay for DST, if necessary.
  638.     millisInDay += dstOffset;
  639.  
  640.     // If DST has pushed us into the next day, we must call timeToFields() again.
  641.     // This happens in DST between 12:00 am and 1:00 am every day.  The call to
  642.     // timeToFields() will give the wrong day, since the Standard time is in the
  643.     // previous day.
  644.     if (millisInDay >= U_MILLIS_PER_DAY) {
  645.         UDate dstMillis = localMillis + dstOffset;
  646.         millisInDay -= U_MILLIS_PER_DAY;
  647.         // As above, check for and pin extreme values
  648.         if(localMillis > 0 && dstMillis < 0 && dstOffset > 0) {
  649.             dstMillis = LATEST_SUPPORTED_MILLIS;
  650.         } 
  651.         else if(localMillis < 0 && dstMillis > 0 && dstOffset < 0) {
  652.             dstMillis = EARLIEST_SUPPORTED_MILLIS;
  653.         }
  654.         timeToFields(dstMillis, FALSE, status);
  655.     }
  656.  
  657.     // Fill in all time-related fields based on millisInDay.  Call internalSet()
  658.     // so as not to perturb flags.
  659.     internalSet(MILLISECOND, millisInDay % 1000);
  660.     millisInDay /= 1000;
  661.     internalSet(SECOND, millisInDay % 60);
  662.     millisInDay /= 60;
  663.     internalSet(MINUTE, millisInDay % 60);
  664.     millisInDay /= 60;
  665.     internalSet(HOUR_OF_DAY, millisInDay);
  666.     internalSet(AM_PM, millisInDay / 12); // Assume AM == 0
  667.     internalSet(HOUR, millisInDay % 12);
  668.  
  669.     internalSet(ZONE_OFFSET, rawOffset);
  670.     internalSet(DST_OFFSET, dstOffset);
  671.  
  672.     // Careful here: We are manually setting the time stamps[] flags to
  673.     // INTERNALLY_SET, so we must be sure that the above code actually does
  674.     // set all these fields.
  675.     for (int i=0; i<FIELD_COUNT; ++i) {
  676.         fStamp[i] = kInternallySet;
  677.         fIsSet[i] = TRUE; // Remove later
  678.     }
  679. }
  680.  
  681. // -------------------------------------
  682.  
  683. /**
  684.  * After adjustments such as add(MONTH), add(YEAR), we don't want the
  685.  * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
  686.  * 3, we want it to go to Feb 28.  Adjustments which might run into this
  687.  * problem call this method to retain the proper month.
  688.  */
  689. void 
  690. GregorianCalendar::pinDayOfMonth() 
  691. {
  692.     int32_t monthLen = monthLength(internalGet(MONTH));
  693.     int32_t dom = internalGet(DAY_OF_MONTH);
  694.     if(dom > monthLen) 
  695.         set(DAY_OF_MONTH, monthLen);
  696. }
  697.  
  698. // -------------------------------------
  699.  
  700. bool_t
  701. GregorianCalendar::validateFields() const
  702. {
  703.     for (int32_t field = 0; field < FIELD_COUNT; field++) {
  704.         // Ignore DATE and DAY_OF_YEAR which are handled below
  705.         if (field != DATE &&
  706.             field != DAY_OF_YEAR &&
  707.             isSet((EDateFields)field) &&
  708.             ! boundsCheck(internalGet((EDateFields)field), (EDateFields)field))
  709.  
  710.             return FALSE;
  711.     }
  712.  
  713.     // Values differ in Least-Maximum and Maximum should be handled
  714.     // specially.
  715.     if (isSet(DATE)) {
  716.         int32_t date = internalGet(DATE);
  717.         if (date < getMinimum(DATE) ||
  718.             date > monthLength(internalGet(MONTH))) {
  719.             return FALSE;
  720.         }
  721.     }
  722.  
  723.     if (isSet(DAY_OF_YEAR)) {
  724.         int32_t days = internalGet(DAY_OF_YEAR);
  725.         if (days < 1 || days > yearLength()) 
  726.             return FALSE;
  727.     }
  728.  
  729.     // Handle DAY_OF_WEEK_IN_MONTH, which must not have the value zero.
  730.     // We've checked against minimum and maximum above already.
  731.     if (isSet(DAY_OF_WEEK_IN_MONTH) &&
  732.         0 == internalGet(DAY_OF_WEEK_IN_MONTH)) 
  733.             return FALSE;
  734.  
  735.     return TRUE;
  736. }
  737.  
  738. // -------------------------------------
  739.  
  740. bool_t
  741. GregorianCalendar::boundsCheck(int32_t value, EDateFields field) const
  742. {
  743.     return value >= getMinimum(field) && value <= getMaximum(field);
  744. }
  745.  
  746. // -------------------------------------
  747.  
  748. UDate 
  749. GregorianCalendar::getEpochDay(UErrorCode& status) 
  750. {
  751.     complete(status);
  752.     // Divide by 1000 (convert to seconds) in order to prevent overflow when
  753.     // dealing with UDate(Long.MIN_VALUE) and UDate(Long.MAX_VALUE).
  754.     double wallSec = internalGetTime()/1000 + (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET))/1000;
  755.     
  756.     // {sfb} force conversion to double
  757.     return icu_trunc(wallSec / (kOneDay/1000.0));
  758.     //return floorDivide(wallSec, kOneDay/1000.0);
  759. }
  760.  
  761. // -------------------------------------
  762.  
  763. void
  764. GregorianCalendar::computeTime(UErrorCode& status)
  765. {
  766.     if (U_FAILURE(status)) 
  767.         return;
  768.  
  769.     if (! isLenient() && ! validateFields()) {
  770.         status = U_ILLEGAL_ARGUMENT_ERROR;
  771.         return;
  772.     }
  773.  
  774.     // This function takes advantage of the fact that unset fields in
  775.     // the time field list have a value of zero.
  776.  
  777.     // The year defaults to the epoch start.
  778.     int32_t year = (fStamp[YEAR] != kUnset) ? internalGet(YEAR) : kEpochYear;
  779.  
  780.     int32_t era = AD;
  781.     if (fStamp[ERA] != kUnset) {
  782.         era = internalGet(ERA);
  783.         if (era == BC)
  784.             year = 1 - year;
  785.         // Even in lenient mode we disallow ERA values other than AD & BC
  786.         else if (era != AD) {
  787.             status = U_ILLEGAL_ARGUMENT_ERROR;
  788.             return;
  789.         }
  790.     }
  791.  
  792.     // First, use the year to determine whether to use the Gregorian or the
  793.     // Julian calendar. If the year is not the year of the cutover, this
  794.     // computation will be correct. But if the year is the cutover year,
  795.     // this may be incorrect. In that case, assume the Gregorian calendar,
  796.     // make the computation, and then recompute if the resultant millis
  797.     // indicate the wrong calendar has been assumed.
  798.  
  799.     // A date such as Oct. 10, 1582 does not exist in a Gregorian calendar
  800.     // with the default changeover of Oct. 15, 1582, since in such a
  801.     // calendar Oct. 4 (Julian) is followed by Oct. 15 (Gregorian).  This
  802.     // algorithm will interpret such a date using the Julian calendar,
  803.     // yielding Oct. 20, 1582 (Gregorian).
  804.     bool_t isGregorian = year >= fGregorianCutoverYear;
  805.     double julianDay = computeJulianDay(isGregorian, year);
  806.     double millis = julianDayToMillis(julianDay);
  807.  
  808.     // The following check handles portions of the cutover year BEFORE the
  809.     // cutover itself happens. The check for the julianDate number is for a
  810.     // rare case; it's a hardcoded number, but it's efficient.  The given
  811.     // Julian day number corresponds to Dec 3, 292269055 BC, which
  812.     // corresponds to millis near Long.MIN_VALUE.  The need for the check
  813.     // arises because for extremely negative Julian day numbers, the millis
  814.     // actually overflow to be positive values. Without the check, the
  815.     // initial date is interpreted with the Gregorian calendar, even when
  816.     // the cutover doesn't warrant it.
  817.     if (isGregorian != (millis >= fNormalizedGregorianCutover) &&
  818.         julianDay != -106749550580.0) { // See above
  819.         julianDay = computeJulianDay(!isGregorian, year);
  820.         millis = julianDayToMillis(julianDay);
  821.     }
  822.  
  823.     // Do the time portion of the conversion.
  824.  
  825.     int32_t millisInDay = 0;
  826.  
  827.     // Find the best set of fields specifying the time of day.  There
  828.     // are only two possibilities here; the HOUR_OF_DAY or the
  829.     // AM_PM and the HOUR.
  830.     int32_t hourOfDayStamp = fStamp[HOUR_OF_DAY];
  831.     int32_t hourStamp = fStamp[HOUR];
  832.     int32_t bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
  833.  
  834.     // Hours
  835.     if (bestStamp != kUnset) {
  836.         if (bestStamp == hourOfDayStamp)
  837.             // Don't normalize here; let overflow bump into the next period.
  838.             // This is consistent with how we handle other fields.
  839.             millisInDay += internalGet(HOUR_OF_DAY);
  840.  
  841.         else {
  842.             // Don't normalize here; let overflow bump into the next period.
  843.             // This is consistent with how we handle other fields.
  844.             millisInDay += internalGet(HOUR);
  845.  
  846.             millisInDay += 12 * internalGet(AM_PM); // Default works for unset AM_PM
  847.         }
  848.     }
  849.  
  850.     // We use the fact that unset == 0; we start with millisInDay
  851.     // == HOUR_OF_DAY.
  852.     millisInDay *= 60;
  853.     millisInDay += internalGet(MINUTE); // now have minutes
  854.     millisInDay *= 60;
  855.     millisInDay += internalGet(SECOND); // now have seconds
  856.     millisInDay *= 1000;
  857.     millisInDay += internalGet(MILLISECOND); // now have millis
  858.  
  859.     // Compute the time zone offset and DST offset.  There are two potential
  860.     // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
  861.     // for discussion purposes here.
  862.     // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
  863.     //    can be in standard or in DST depending.  However, 2:00 am is an invalid
  864.     //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
  865.     //    We assume standard time.
  866.     // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
  867.     //    can be in standard or DST.  Both are valid representations (the rep
  868.     //    jumps from 1:59:59 DST to 1:00:00 Std).
  869.     //    Again, we assume standard time.
  870.     // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
  871.     // or DST_OFFSET fields; then we use those fields.
  872.     const TimeZone& zone = getTimeZone();
  873.     int32_t zoneOffset = (fStamp[ZONE_OFFSET] >= kMinimumUserStamp)
  874.         /*isSet(ZONE_OFFSET) && userSetZoneOffset*/ ?
  875.         internalGet(ZONE_OFFSET) : zone.getRawOffset();
  876.  
  877.     // Now add date and millisInDay together, to make millis contain local wall
  878.     // millis, with no zone or DST adjustments
  879.     millis += millisInDay;
  880.  
  881.     int32_t dstOffset = 0;
  882.     if (fStamp[ZONE_OFFSET] >= kMinimumUserStamp
  883.         /*isSet(DST_OFFSET) && userSetDSTOffset*/)
  884.         dstOffset = internalGet(DST_OFFSET);
  885.     else {
  886.         /* Normalize the millisInDay to 0..ONE_DAY-1.  If the millis is out
  887.          * of range, then we must call timeToFields() to recompute our
  888.          * fields. */
  889.         int32_t normalizedMillisInDay [1];
  890.         floorDivide(millis, (int32_t)kOneDay, normalizedMillisInDay);
  891.  
  892.         // We need to have the month, the day, and the day of the week.
  893.         // Calling timeToFields will compute the MONTH and DATE fields.
  894.         // If we're lenient then we need to call timeToFields() to
  895.         // normalize the year, month, and date numbers.
  896.         uint8_t dow;
  897.         if (isLenient() || fStamp[MONTH] == kUnset || fStamp[DATE] == kUnset
  898.                 || millisInDay != normalizedMillisInDay[0]) {
  899.             timeToFields(millis, TRUE, status); // Use wall time; true == do quick computation
  900.             dow = (uint8_t) internalGet(DAY_OF_WEEK); // DOW is computed by timeToFields
  901.         }
  902.         else {
  903.             // It's tempting to try to use DAY_OF_WEEK here, if it
  904.             // is set, but we CAN'T.  Even if it's set, it might have
  905.             // been set wrong by the user.  We should rely only on
  906.             // the Julian day number, which has been computed correctly
  907.             // using the disambiguation algorithm above. [LIU]
  908.             dow = julianDayToDayOfWeek(julianDay);
  909.         }
  910.  
  911.         // It's tempting to try to use DAY_OF_WEEK here, if it
  912.         // is set, but we CAN'T.  Even if it's set, it might have
  913.         // been set wrong by the user.  We should rely only on
  914.         // the Julian day number, which has been computed correctly
  915.         // using the disambiguation algorithm above. [LIU]
  916.         dstOffset = zone.getOffset((uint8_t)era,
  917.                                    internalGet(YEAR),
  918.                                    internalGet(MONTH),
  919.                                    internalGet(DATE),
  920.                                    dow,
  921.                                    normalizedMillisInDay[0],
  922.                                    monthLength(internalGet(MONTH)),
  923.                                    status) -
  924.             zoneOffset;
  925.         // Note: Because we pass in wall millisInDay, rather than
  926.         // standard millisInDay, we interpret "1:00 am" on the day
  927.         // of cessation of DST as "1:00 am Std" (assuming the time
  928.         // of cessation is 2:00 am).
  929.     }
  930.  
  931.     // Store our final computed GMT time, with timezone adjustments.
  932.     internalSetTime(millis - zoneOffset - dstOffset);
  933. }
  934.  
  935. // -------------------------------------
  936.  
  937. double 
  938. GregorianCalendar::computeJulianDay(bool_t isGregorian, int32_t year) 
  939. {
  940.     int32_t month = 0;
  941.     int32_t date = 0;
  942.     int32_t y;
  943.     double millis = 0;
  944.  
  945.     // Find the most recent set of fields specifying the day within
  946.     // the year.  These may be any of the following combinations:
  947.     //   MONTH* + DAY_OF_MONTH*
  948.     //   MONTH* + WEEK_OF_MONTH* + DAY_OF_WEEK
  949.     //   MONTH* + DAY_OF_WEEK_IN_MONTH* + DAY_OF_WEEK
  950.     //   DAY_OF_YEAR*
  951.     //   WEEK_OF_YEAR* + DAY_OF_WEEK
  952.     // We look for the most recent of the fields marked thus*.  If other
  953.     // fields are missing, we use their default values, which are those of
  954.     // the epoch start, or in the case of DAY_OF_WEEK, the first day in
  955.     // the week.
  956.     int32_t monthStamp     = fStamp[MONTH];
  957.     int32_t domStamp     = fStamp[DAY_OF_MONTH];
  958.     int32_t womStamp     = fStamp[WEEK_OF_MONTH];
  959.     int32_t dowimStamp     = fStamp[DAY_OF_WEEK_IN_MONTH];
  960.     int32_t doyStamp     = fStamp[DAY_OF_YEAR];
  961.     int32_t woyStamp     = fStamp[WEEK_OF_YEAR];
  962.  
  963.     int32_t bestStamp = (monthStamp > domStamp) ? monthStamp : domStamp;
  964.     if (womStamp > bestStamp) bestStamp = womStamp;
  965.     if (dowimStamp > bestStamp) bestStamp = dowimStamp;
  966.     if (doyStamp > bestStamp) bestStamp = doyStamp;
  967.     if (woyStamp > bestStamp) bestStamp = woyStamp;
  968.  
  969.     bool_t useMonth = FALSE;
  970.  
  971.     if (bestStamp != kUnset &&
  972.         (bestStamp == monthStamp ||
  973.          bestStamp == domStamp ||
  974.          bestStamp == womStamp ||
  975.          bestStamp == dowimStamp)) {
  976.         useMonth = TRUE;
  977.  
  978.         // We have the month specified. Make it 0-based for the algorithm.
  979.         month = (monthStamp != kUnset) ? internalGet(MONTH) - JANUARY : 0;
  980.  
  981.         // If the month is out of range, adjust it into range
  982.         if (month < 0 || month > 11) {
  983.             int32_t rem[1];
  984.             year += floorDivide(month, 12, rem);
  985.             month = rem[0];
  986.         }
  987.     }
  988.  
  989.     bool_t isLeap = year%4 == 0;
  990.     y = year - 1;
  991.     double julianDay = 365.0*y + floorDivide(y, 4) + (kJan1_1JulianDay - 3);
  992.  
  993.     if (isGregorian) {
  994.         isLeap = isLeap && ((year%100 != 0) || (year%400 == 0));
  995.         // Add 2 because Gregorian calendar starts 2 days after Julian calendar
  996.         julianDay += floorDivide(y, 400) - floorDivide(y, 100) + 2;
  997.     }
  998.  
  999.     // At this point julianDay is the 0-based day BEFORE the first day of
  1000.     // January 1, year 1 of the given calendar.  If julianDay == 0, it
  1001.     // specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian
  1002.     // or Gregorian).
  1003.  
  1004.     if (useMonth) {
  1005.  
  1006.         julianDay += isLeap ? kLeapNumDays[month] : kNumDays[month];
  1007.  
  1008.         if (bestStamp == domStamp ||
  1009.             bestStamp == monthStamp) {
  1010.  
  1011.             date = (domStamp != kUnset) ? internalGet(DAY_OF_MONTH) : 1;
  1012.         }
  1013.         else { // assert(bestStamp == womStamp || bestStamp == dowimStamp)
  1014.             // Compute from day of week plus week number or from the day of
  1015.             // week plus the day of week in month.  The computations are
  1016.             // almost identical.
  1017.  
  1018.             // Find the day of the week for the first of this month.  This
  1019.             // is zero-based, with 0 being the locale-specific first day of
  1020.             // the week.  Add 1 to get the 1st day of month.  Subtract
  1021.             // getFirstDayOfWeek() to make 0-based.
  1022.             int32_t fdm = julianDayToDayOfWeek(julianDay + 1) - getFirstDayOfWeek();
  1023.             if (fdm < 0) 
  1024.                 fdm += 7;
  1025.  
  1026.             // Find the start of the first week.  This will be a date from
  1027.             // 1..-6.  It represents the locale-specific first day of the
  1028.             // week of the first day of the month, ignoring minimal days in
  1029.             // first week.
  1030.             date = 1 - fdm + ((fStamp[DAY_OF_WEEK] != kUnset) ?
  1031.                               (internalGet(DAY_OF_WEEK) - getFirstDayOfWeek()) : 0);
  1032.  
  1033.             if (bestStamp == womStamp) {
  1034.                 // Adjust for minimal days in first week.
  1035.                 if ((7 - fdm) < getMinimalDaysInFirstWeek()) 
  1036.                     date += 7;
  1037.  
  1038.                 // Now adjust for the week number.
  1039.                 date += 7 * (internalGet(WEEK_OF_MONTH) - 1);
  1040.             }
  1041.             else { // assert(bestStamp == dowimStamp)
  1042.                 // Adjust into the month, if needed.
  1043.                 if (date < 1) date += 7;
  1044.  
  1045.                 // We are basing this on the day-of-week-in-month.  The only
  1046.                 // trickiness occurs if the day-of-week-in-month is
  1047.                 // negative.
  1048.                 int32_t dim = internalGet(DAY_OF_WEEK_IN_MONTH);
  1049.                 if (dim >= 0) 
  1050.                     date += 7*(dim - 1);
  1051.                 else {
  1052.                     // Move date to the last of this day-of-week in this
  1053.                     // month, then back up as needed.  If dim==-1, we don't
  1054.                     // back up at all.  If dim==-2, we back up once, etc.
  1055.                     // Don't back up past the first of the given day-of-week
  1056.                     // in this month.  Note that we handle -2, -3,
  1057.                     // etc. correctly, even though values < -1 are
  1058.                     // technically disallowed.
  1059.                     date += ((monthLength(internalGet(MONTH), year) - date) / 7 + dim + 1) * 7;
  1060.                 }
  1061.             }
  1062.         }
  1063.  
  1064.         julianDay += date;
  1065.     }
  1066.     else {
  1067.         // assert(bestStamp == doyStamp || bestStamp == woyStamp ||
  1068.         // bestStamp == UNSET).  In the last case we should use January 1.
  1069.  
  1070.         // No month, start with January 0 (day before Jan 1), then adjust.
  1071.  
  1072.         if (bestStamp == kUnset) {
  1073.             ++julianDay; // Advance to January 1
  1074.         }
  1075.         else if (bestStamp == doyStamp) {
  1076.             julianDay += internalGet(DAY_OF_YEAR);
  1077.         }
  1078.         else if (bestStamp == woyStamp) {
  1079.             // Compute from day of week plus week of year
  1080.  
  1081.             // Find the day of the week for the first of this year.  This
  1082.             // is zero-based, with 0 being the locale-specific first day of
  1083.             // the week.  Add 1 to get the 1st day of month.  Subtract
  1084.             // getFirstDayOfWeek() to make 0-based.
  1085.             int32_t fdy = julianDayToDayOfWeek(julianDay + 1) - getFirstDayOfWeek();
  1086.             if (fdy < 0) 
  1087.                 fdy += 7;
  1088.  
  1089.             // Find the start of the first week.  This may be a valid date
  1090.             // from 1..7, or a date before the first, from 0..-6.  It
  1091.             // represents the locale-specific first day of the week
  1092.             // of the first day of the year.
  1093.  
  1094.             // First ignore the minimal days in first week.
  1095.             date = 1 - fdy + ((fStamp[DAY_OF_WEEK] != kUnset) ?
  1096.                               (internalGet(DAY_OF_WEEK) - getFirstDayOfWeek()) : 0);
  1097.  
  1098.             // Adjust for minimal days in first week.
  1099.             if ((7 - fdy) < getMinimalDaysInFirstWeek()) 
  1100.                 date += 7;
  1101.  
  1102.             // Now adjust for the week number.
  1103.             date += 7 * (internalGet(WEEK_OF_YEAR) - 1);
  1104.  
  1105.             julianDay += date;
  1106.         }
  1107.     }
  1108.  
  1109.     return julianDay;
  1110. }
  1111.  
  1112. // -------------------------------------
  1113.  
  1114. double 
  1115. GregorianCalendar::millisToJulianDay(UDate millis)
  1116. {
  1117.     return (double)kEpochStartAsJulianDay + floorDivide(millis, kOneDay);
  1118.     //return kEpochStartAsJulianDay + icu_trunc(millis / kOneDay);
  1119. }
  1120.  
  1121. // -------------------------------------
  1122.  
  1123. UDate
  1124. GregorianCalendar::julianDayToMillis(double julian)
  1125. {
  1126.     return (UDate) ((julian - kEpochStartAsJulianDay) * (double) kOneDay);
  1127. }
  1128.  
  1129. // -------------------------------------
  1130.  
  1131. double
  1132. GregorianCalendar::floorDivide(double numerator, double denominator) 
  1133. {
  1134.     return icu_floor(numerator / denominator);
  1135. }
  1136.  
  1137. // -------------------------------------
  1138.  
  1139. int32_t 
  1140. GregorianCalendar::floorDivide(int32_t numerator, int32_t denominator) 
  1141. {
  1142.     // We do this computation in order to handle
  1143.     // a numerator of Long.MIN_VALUE correctly
  1144.     return (numerator >= 0) ?
  1145.         numerator / denominator :
  1146.         ((numerator + 1) / denominator) - 1;
  1147. }
  1148.  
  1149. // -------------------------------------
  1150.  
  1151. int32_t 
  1152. GregorianCalendar::floorDivide(int32_t numerator, int32_t denominator, int32_t remainder[])
  1153. {
  1154.     if (numerator >= 0) {
  1155.         remainder[0] = numerator % denominator;
  1156.         return numerator / denominator;
  1157.     }
  1158.     int32_t quotient = ((numerator + 1) / denominator) - 1;
  1159.     remainder[0] = numerator - (quotient * denominator);
  1160.     return quotient;
  1161. }
  1162.  
  1163. // -------------------------------------
  1164.  
  1165. int32_t
  1166. GregorianCalendar::floorDivide(double numerator, int32_t denominator, int32_t remainder[]) 
  1167. {
  1168.     if (numerator >= 0) {
  1169.         remainder[0] = (int32_t)icu_fmod(numerator, denominator);
  1170.         return (int32_t)icu_trunc(numerator / denominator);
  1171.     }
  1172.     int32_t quotient = (int32_t)(icu_trunc((numerator + 1) / denominator) - 1);
  1173.     remainder[0] = (int32_t)(numerator - ((double)quotient * denominator));
  1174.     return quotient;
  1175. }
  1176.  
  1177.  
  1178. // -------------------------------------
  1179.  
  1180. // {sfb} why does this work, while Calendar::EStampValues doesn't?
  1181. GregorianCalendar::EStampValues
  1182. GregorianCalendar::aggregateStamp(EStampValues stamp_a, EStampValues stamp_b) 
  1183. {
  1184.     return ((EStampValues)((stamp_a != kUnset && stamp_b != kUnset) 
  1185.         ? icu_max((int32_t)stamp_a, (int32_t)stamp_b)
  1186.         : kUnset));
  1187. }
  1188.  
  1189. // -------------------------------------
  1190.  
  1191. void
  1192. GregorianCalendar::add(EDateFields field, int32_t amount, UErrorCode& status)
  1193. {
  1194.     if (U_FAILURE(status)) 
  1195.         return;
  1196.  
  1197.     if (amount == 0) 
  1198.         return;   // Do nothing!
  1199.     complete(status);
  1200.  
  1201.     if (field == YEAR) {
  1202.         int32_t year = internalGet(YEAR);
  1203.         if (internalGetEra() == AD) {
  1204.             year += amount;
  1205.             if (year > 0)
  1206.                 set(YEAR, year);
  1207.             else { // year <= 0
  1208.                 set(YEAR, 1 - year);
  1209.                 // if year == 0, you get 1 BC
  1210.                 set(ERA, BC);
  1211.             }
  1212.         }
  1213.         else { // era == BC
  1214.             year -= amount;
  1215.             if (year > 0)
  1216.                 set(YEAR, year);
  1217.             else { // year <= 0
  1218.                 set(YEAR, 1 - year);
  1219.                 // if year == 0, you get 1 AD
  1220.                 set(ERA, AD);
  1221.             }
  1222.         }
  1223.         pinDayOfMonth();
  1224.     }
  1225.     else if (field == MONTH) {
  1226.         int32_t month = internalGet(MONTH) + amount;
  1227.         if (month >= 0) {
  1228.             add(YEAR, (int32_t) (month / 12), status);
  1229.             set(MONTH, (int32_t) (month % 12));
  1230.         }
  1231.         else { // month < 0
  1232.  
  1233.             add(YEAR, (int32_t) ((month + 1) / 12) - 1, status);
  1234.             month %= 12;
  1235.             if (month < 0) 
  1236.                 month += 12;
  1237.             set(MONTH, JANUARY + month);
  1238.         }
  1239.         pinDayOfMonth();
  1240.     }
  1241.     else if (field == ERA) {
  1242.         int32_t era = internalGet(ERA) + amount;
  1243.         if (era < 0) 
  1244.             era = 0;
  1245.         if (era > 1) 
  1246.             era = 1;
  1247.         set(ERA, era);
  1248.     }
  1249.     else {
  1250.         // We handle most fields here.  The algorithm is to add a computed amount
  1251.         // of millis to the current millis.  The only wrinkle is with DST -- if
  1252.         // the result of the add operation is to move from DST to Standard, or vice
  1253.         // versa, we need to adjust by an hour forward or back, respectively.
  1254.         // Otherwise you get weird effects in which the hour seems to shift when
  1255.         // you add to the DAY_OF_MONTH field, for instance.
  1256.  
  1257.         // We only adjust the DST for fields larger than an hour.  For fields
  1258.         // smaller than an hour, we cannot adjust for DST without causing problems.
  1259.         // for instance, if you add one hour to April 5, 1998, 1:00 AM, in PST,
  1260.         // the time becomes "2:00 AM PDT" (an illegal value), but then the adjustment
  1261.         // sees the change and compensates by subtracting an hour.  As a result the
  1262.         // time doesn't advance at all.
  1263.  
  1264.         // {sfb} do we want to use a double here, or a int32_t?
  1265.         // probably a double, since if we used a int32_t in the
  1266.         // WEEK_OF_YEAR clause below, if delta was greater than approx.
  1267.         // 7.1 we would reach the limit of a int32_t
  1268.         double delta = amount;
  1269.         bool_t adjustDST = TRUE;
  1270.  
  1271.         switch (field) {
  1272.         case WEEK_OF_YEAR:
  1273.         case WEEK_OF_MONTH:
  1274.         case DAY_OF_WEEK_IN_MONTH:
  1275.             delta *= 7 * 24 * 60 * 60 * 1000; // 7 days
  1276.             break;
  1277.  
  1278.         case AM_PM:
  1279.             delta *= 12 * 60 * 60 * 1000; // 12 hrs
  1280.             break;
  1281.  
  1282.         case DATE: // synonym of DAY_OF_MONTH
  1283.         case DAY_OF_YEAR:
  1284.         case DAY_OF_WEEK:
  1285.             delta *= 24 * 60 * 60 * 1000; // 1 day
  1286.             break;
  1287.  
  1288.         case HOUR_OF_DAY:
  1289.         case HOUR:
  1290.             delta *= 60 * 60 * 1000; // 1 hour
  1291.             adjustDST = FALSE;
  1292.             break;
  1293.  
  1294.         case MINUTE:
  1295.             delta *= 60 * 1000; // 1 minute
  1296.             adjustDST = FALSE;
  1297.             break;
  1298.  
  1299.         case SECOND:
  1300.             delta *= 1000; // 1 second
  1301.             adjustDST = FALSE;
  1302.             break;
  1303.  
  1304.         case MILLISECOND:
  1305.             adjustDST = FALSE;
  1306.             break;
  1307.  
  1308.         case ZONE_OFFSET:
  1309.         case DST_OFFSET:
  1310.         default:
  1311.             status = U_ILLEGAL_ARGUMENT_ERROR;
  1312.             return;
  1313.         }
  1314.  
  1315.         // Save the current DST state.
  1316.         int32_t dst = 0;
  1317.         if (adjustDST) 
  1318.             dst = internalGet(DST_OFFSET);
  1319.  
  1320.         setTimeInMillis(internalGetTime() + delta, status); // Automatically computes fields if necessary
  1321.  
  1322.         if (adjustDST) {
  1323.             // Now do the DST adjustment alluded to above.
  1324.             // Only call setTimeInMillis if necessary, because it's an expensive call.
  1325.             dst -= internalGet(DST_OFFSET);
  1326.             if(dst!= 0) 
  1327.                 setTimeInMillis(internalGetTime() + dst, status);
  1328.         }
  1329.     }
  1330. }
  1331.  
  1332. // -------------------------------------
  1333.  
  1334. /**
  1335.  * Roll a field by a signed amount.
  1336.  * Note: This will be made public later. [LIU]
  1337.  */
  1338. void
  1339. GregorianCalendar::roll(EDateFields field, int32_t amount, UErrorCode& status)
  1340. {
  1341.     if(U_FAILURE(status))
  1342.         return;
  1343.  
  1344.     if (amount == 0) 
  1345.         return; // Nothing to do
  1346.  
  1347.     int32_t min = 0, max = 0, gap;
  1348.     if (field >= 0 && field < FIELD_COUNT) {
  1349.         complete(status);
  1350.         min = getMinimum(field);
  1351.         max = getMaximum(field);
  1352.     }
  1353.  
  1354.     switch (field) {
  1355.     case ERA:
  1356.     case YEAR:
  1357.     case AM_PM:
  1358.     case MINUTE:
  1359.     case SECOND:
  1360.     case MILLISECOND:
  1361.         // These fields are handled simply, since they have fixed minima
  1362.         // and maxima.  The field DAY_OF_MONTH is almost as simple.  Other
  1363.         // fields are complicated, since the range within they must roll
  1364.         // varies depending on the date.
  1365.         break;
  1366.  
  1367.     case HOUR:
  1368.     case HOUR_OF_DAY:
  1369.         // Rolling the hour is difficult on the ONSET and CEASE days of
  1370.         // daylight savings.  For example, if the change occurs at
  1371.         // 2 AM, we have the following progression:
  1372.         // ONSET: 12 Std -> 1 Std -> 3 Dst -> 4 Dst
  1373.         // CEASE: 12 Dst -> 1 Dst -> 1 Std -> 2 Std
  1374.         // To get around this problem we don't use fields; we manipulate
  1375.         // the time in millis directly.
  1376.         {
  1377.             // Assume min == 0 in calculations below
  1378.             UDate start = getTime(status);
  1379.             int32_t oldHour = internalGet(field);
  1380.             int32_t newHour = (oldHour + amount) % (max + 1);
  1381.             if(newHour < 0)
  1382.                 newHour += max + 1;
  1383.             setTime(start + ((double)kOneHour * (newHour - oldHour)), status);
  1384.             return;
  1385.         }
  1386.     case MONTH:
  1387.         // Rolling the month involves both pinning the final value to [0, 11]
  1388.         // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
  1389.         // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
  1390.         // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
  1391.         {
  1392.             int32_t mon = (internalGet(MONTH) + amount) % 12;
  1393.             if (mon < 0) 
  1394.                 mon += 12;
  1395.             set(MONTH, mon);
  1396.             
  1397.             // Keep the day of month in range.  We don't want to spill over
  1398.             // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
  1399.             // mar3.
  1400.             // NOTE: We could optimize this later by checking for dom <= 28
  1401.             // first.  Do this if there appears to be a need. [LIU]
  1402.             int32_t monthLen = monthLength(mon);
  1403.             int32_t dom = internalGet(DAY_OF_MONTH);
  1404.             if (dom > monthLen) 
  1405.                 set(DAY_OF_MONTH, monthLen);
  1406.             return;
  1407.         }
  1408.  
  1409.     case WEEK_OF_YEAR:
  1410.         {
  1411.             // Unlike WEEK_OF_MONTH, WEEK_OF_YEAR never shifts the day of the
  1412.             // week.  Also, rolling the week of the year can have seemingly
  1413.             // strange effects simply because the year of the week of year
  1414.             // may be different from the calendar year.  For example, the
  1415.             // date Dec 28, 1997 is the first day of week 1 of 1998 (if
  1416.             // weeks start on Sunday and the minimal days in first week is
  1417.             // <= 3).
  1418.             int32_t woy = internalGet(WEEK_OF_YEAR);
  1419.             // Get the ISO year, which matches the week of year.  This
  1420.             // may be one year before or after the calendar year.
  1421.             int32_t isoYear = internalGet(YEAR);
  1422.             int32_t isoDoy = internalGet(DAY_OF_YEAR);
  1423.             if (internalGet(MONTH) == Calendar::JANUARY) {
  1424.                 if (woy >= 52) {
  1425.                     --isoYear;
  1426.                     isoDoy += yearLength(isoYear);
  1427.                 }
  1428.             }
  1429.             else {
  1430.                 if (woy == 1) {
  1431.                     isoDoy -= yearLength(isoYear);
  1432.                     ++isoYear;
  1433.                 }
  1434.             }
  1435.             woy += amount;
  1436.             // Do fast checks to avoid unnecessary computation:
  1437.             if (woy < 1 || woy > 52) {
  1438.                 // Determine the last week of the ISO year.
  1439.                 // We do this using the standard formula we use
  1440.                 // everywhere in this file.  If we can see that the
  1441.                 // days at the end of the year are going to fall into
  1442.                 // week 1 of the next year, we drop the last week by
  1443.                 // subtracting 7 from the last day of the year.
  1444.                 int32_t lastDoy = yearLength(isoYear);
  1445.                 int32_t lastRelDow = (lastDoy - isoDoy + internalGet(DAY_OF_WEEK) -
  1446.                                   getFirstDayOfWeek()) % 7;
  1447.                 if (lastRelDow < 0) 
  1448.                     lastRelDow += 7;
  1449.                 if ((6 - lastRelDow) >= getMinimalDaysInFirstWeek()) 
  1450.                     lastDoy -= 7;
  1451.                 int32_t lastWoy = weekNumber(lastDoy, lastRelDow + 1);
  1452.                 woy = ((woy + lastWoy - 1) % lastWoy) + 1;
  1453.             }
  1454.             set(WEEK_OF_YEAR, woy);
  1455.             set(YEAR, isoYear);
  1456.             return;
  1457.         }
  1458.     case WEEK_OF_MONTH:
  1459.         {
  1460.             // This is tricky, because during the roll we may have to shift
  1461.             // to a different day of the week.  For example:
  1462.  
  1463.             //    s  m  t  w  r  f  s
  1464.             //          1  2  3  4  5
  1465.             //    6  7  8  9 10 11 12
  1466.  
  1467.             // When rolling from the 6th or 7th back one week, we go to the
  1468.             // 1st (assuming that the first partial week counts).  The same
  1469.             // thing happens at the end of the month.
  1470.  
  1471.             // The other tricky thing is that we have to figure out whether
  1472.             // the first partial week actually counts or not, based on the
  1473.             // minimal first days in the week.  And we have to use the
  1474.             // correct first day of the week to delineate the week
  1475.             // boundaries.
  1476.  
  1477.             // Here's our algorithm.  First, we find the real boundaries of
  1478.             // the month.  Then we discard the first partial week if it
  1479.             // doesn't count in this locale.  Then we fill in the ends with
  1480.             // phantom days, so that the first partial week and the last
  1481.             // partial week are full weeks.  We then have a nice square
  1482.             // block of weeks.  We do the usual rolling within this block,
  1483.             // as is done elsewhere in this method.  If we wind up on one of
  1484.             // the phantom days that we added, we recognize this and pin to
  1485.             // the first or the last day of the month.  Easy, eh?
  1486.  
  1487.             // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
  1488.             // in this locale.  We have dow in 0..6.
  1489.             int32_t dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  1490.             if (dow < 0) 
  1491.                 dow += 7;
  1492.  
  1493.             // Find the day of the week (normalized for locale) for the first
  1494.             // of the month.
  1495.             int32_t fdm = (dow - internalGet(DAY_OF_MONTH) + 1) % 7;
  1496.             if (fdm < 0) 
  1497.                 fdm += 7;
  1498.  
  1499.             // Get the first day of the first full week of the month,
  1500.             // including phantom days, if any.  Figure out if the first week
  1501.             // counts or not; if it counts, then fill in phantom days.  If
  1502.             // not, advance to the first real full week (skip the partial week).
  1503.             int32_t start;
  1504.             if ((7 - fdm) < getMinimalDaysInFirstWeek())
  1505.                 start = 8 - fdm; // Skip the first partial week
  1506.             else
  1507.                 start = 1 - fdm; // This may be zero or negative
  1508.  
  1509.             // Get the day of the week (normalized for locale) for the last
  1510.             // day of the month.
  1511.             int32_t monthLen = monthLength(internalGet(MONTH));
  1512.             int32_t ldm = (monthLen - internalGet(DAY_OF_MONTH) + dow) % 7;
  1513.             // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.
  1514.  
  1515.             // Get the limit day for the blocked-off rectangular month; that
  1516.             // is, the day which is one past the last day of the month,
  1517.             // after the month has already been filled in with phantom days
  1518.             // to fill out the last week.  This day has a normalized DOW of 0.
  1519.             int32_t limit = monthLen + 7 - ldm;
  1520.  
  1521.             // Now roll between start and (limit - 1).
  1522.             gap = limit - start;
  1523.             int32_t day_of_month = (internalGet(DAY_OF_MONTH) + amount*7 -
  1524.                                 start) % gap;
  1525.             if (day_of_month < 0) 
  1526.                 day_of_month += gap;
  1527.             day_of_month += start;
  1528.  
  1529.             // Finally, pin to the real start and end of the month.
  1530.             if (day_of_month < 1) 
  1531.                 day_of_month = 1;
  1532.             if (day_of_month > monthLen) 
  1533.                 day_of_month = monthLen;
  1534.  
  1535.             // Set the DAY_OF_MONTH.  We rely on the fact that this field
  1536.             // takes precedence over everything else (since all other fields
  1537.             // are also set at this point).  If this fact changes (if the
  1538.             // disambiguation algorithm changes) then we will have to unset
  1539.             // the appropriate fields here so that DAY_OF_MONTH is attended
  1540.             // to.
  1541.             set(DAY_OF_MONTH, day_of_month);
  1542.             return;
  1543.         }
  1544.     case DAY_OF_MONTH:
  1545.         max = monthLength(internalGet(MONTH));
  1546.         break;
  1547.     case DAY_OF_YEAR:
  1548.         {
  1549.             // Roll the day of year using millis.  Compute the millis for
  1550.             // the start of the year, and get the length of the year.
  1551.             double delta = amount * kOneDay; // Scale up from days to millis
  1552.             double min2 = internalGetTime() - (internalGet(DAY_OF_YEAR) - 1) * kOneDay;
  1553.             int32_t yearLen = yearLength();
  1554.             internalSetTime( icu_fmod((internalGetTime() + delta - min2), (yearLen * kOneDay)));
  1555.             if (internalGetTime() < 0) 
  1556.                 internalSetTime( internalGetTime() + yearLen * kOneDay);
  1557.  
  1558.             setTimeInMillis(internalGetTime() + min2, status);
  1559.             return;
  1560.         }
  1561.     case DAY_OF_WEEK:
  1562.         {
  1563.             // Roll the day of week using millis.  Compute the millis for
  1564.             // the start of the week, using the first day of week setting.
  1565.             // Restrict the millis to [start, start+7days).
  1566.             double delta = amount * kOneDay; // Scale up from days to millis
  1567.             // Compute the number of days before the current day in this
  1568.             // week.  This will be a value 0..6.
  1569.             int32_t leadDays = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
  1570.             if (leadDays < 0) 
  1571.                 leadDays += 7;
  1572.             double min2 = internalGetTime() - leadDays * kOneDay;
  1573.             internalSetTime(icu_fmod((internalGetTime() + delta - min2), kOneWeek));
  1574.             if (internalGetTime() < 0) 
  1575.                 internalSetTime(internalGetTime() + kOneWeek);
  1576.             setTimeInMillis(internalGetTime() + min2, status);
  1577.             return;
  1578.         }
  1579.     case DAY_OF_WEEK_IN_MONTH:
  1580.         {
  1581.             // Roll the day of week in the month using millis.  Determine
  1582.             // the first day of the week in the month, and then the last,
  1583.             // and then roll within that range.
  1584.             double delta = amount * kOneWeek; // Scale up from weeks to millis
  1585.             // Find the number of same days of the week before this one
  1586.             // in this month.
  1587.             int32_t preWeeks = (internalGet(DAY_OF_MONTH) - 1) / 7;
  1588.             // Find the number of same days of the week after this one
  1589.             // in this month.
  1590.             int32_t postWeeks = (monthLength(internalGet(MONTH)) - internalGet(DAY_OF_MONTH)) / 7;
  1591.             // From these compute the min and gap millis for rolling.
  1592.             double min2 = internalGetTime() - preWeeks * kOneWeek;
  1593.             double gap2 = kOneWeek * (preWeeks + postWeeks + 1); // Must add 1!
  1594.             // Roll within this range
  1595.             internalSetTime(icu_fmod((internalGetTime() + delta - min2), gap2));
  1596.             if (internalGetTime() < 0) 
  1597.                 internalSetTime(internalGetTime() + gap2);
  1598.             setTimeInMillis(internalGetTime() + min2, status);
  1599.             return;
  1600.         }
  1601.     case ZONE_OFFSET:
  1602.     case DST_OFFSET:
  1603.     default:
  1604.         status = U_ILLEGAL_ARGUMENT_ERROR;
  1605.         return;
  1606.         // These fields cannot be rolled
  1607.     }
  1608.  
  1609.     // These are the standard roll instructions.  These work for all
  1610.     // simple cases, that is, cases in which the limits are fixed, such
  1611.     // as the hour, the month, and the era.
  1612.     gap = max - min + 1;
  1613.     int32_t value = internalGet(field) + amount;
  1614.     value = (value - min) % gap;
  1615.     if (value < 0) 
  1616.         value += gap;
  1617.     value += min;
  1618.  
  1619.     set(field, value);
  1620. }
  1621.  
  1622. // -------------------------------------
  1623.  
  1624. int32_t
  1625. GregorianCalendar::getMinimum(EDateFields field) const
  1626. {
  1627.     return kMinValues[field];
  1628. }
  1629.  
  1630. // -------------------------------------
  1631.  
  1632. int32_t
  1633. GregorianCalendar::getMaximum(EDateFields field) const
  1634. {
  1635.     return kMaxValues[field];
  1636. }
  1637.  
  1638. // -------------------------------------
  1639.  
  1640. int32_t
  1641. GregorianCalendar::getGreatestMinimum(EDateFields field) const
  1642. {
  1643.     return kMinValues[field];
  1644. }
  1645.  
  1646. // -------------------------------------
  1647.  
  1648. int32_t
  1649. GregorianCalendar::getLeastMaximum(EDateFields field) const
  1650. {
  1651.     return kLeastMaxValues[field];
  1652. }
  1653.  
  1654. // -------------------------------------
  1655.  
  1656. int32_t 
  1657. GregorianCalendar::getActualMinimum(EDateFields field) const
  1658. {
  1659.     return getMinimum(field);
  1660. }
  1661.  
  1662. // -------------------------------------
  1663.  
  1664. int32_t 
  1665. GregorianCalendar::getActualMaximum(EDateFields field) const
  1666. {
  1667.     /* It is a known limitation that the code here (and in getActualMinimum)
  1668.      * won't behave properly at the extreme limits of GregorianCalendar's
  1669.      * representable range (except for the code that handles the YEAR
  1670.      * field).  That's because the ends of the representable range are at
  1671.      * odd spots in the year.  For calendars with the default Gregorian
  1672.      * cutover, these limits are Sun Dec 02 16:47:04 GMT 292269055 BC to Sun
  1673.      * Aug 17 07:12:55 GMT 292278994 AD, somewhat different for non-GMT
  1674.      * zones.  As a result, if the calendar is set to Aug 1 292278994 AD,
  1675.      * the actual maximum of DAY_OF_MONTH is 17, not 30.  If the date is Mar
  1676.      * 31 in that year, the actual maximum month might be Jul, whereas is
  1677.      * the date is Mar 15, the actual maximum might be Aug -- depending on
  1678.      * the precise semantics that are desired.  Similar considerations
  1679.      * affect all fields.  Nonetheless, this effect is sufficiently arcane
  1680.      * that we permit it, rather than complicating the code to handle such
  1681.      * intricacies. - liu 8/20/98 */
  1682.  
  1683.     UErrorCode status = U_ZERO_ERROR;
  1684.  
  1685.     switch (field) {
  1686.         // we have functions that enable us to fast-path number of days in month
  1687.         // of year
  1688.     case DAY_OF_MONTH:
  1689.         return monthLength(get(MONTH, status));
  1690.  
  1691.     case DAY_OF_YEAR:
  1692.         return yearLength();
  1693.  
  1694.         // for week of year, week of month, or day of week in month, we
  1695.         // just fall back on the default implementation in Calendar (I'm not sure
  1696.         // we could do better by having special calculations here)
  1697.     case WEEK_OF_YEAR:
  1698.     case WEEK_OF_MONTH:
  1699.     case DAY_OF_WEEK_IN_MONTH:
  1700.         return Calendar::getActualMaximum(field, status);
  1701.  
  1702.     case YEAR:
  1703.         /* The year computation is no different, in principle, from the
  1704.          * others, however, the range of possible maxima is large.  In
  1705.          * addition, the way we know we've exceeded the range is different.
  1706.          * For these reasons, we use the special case code below to handle
  1707.          * this field.
  1708.          *
  1709.          * The actual maxima for YEAR depend on the type of calendar:
  1710.          *
  1711.          *     Gregorian = May 17, 292275056 BC - Aug 17, 292278994 AD
  1712.          *     Julian    = Dec  2, 292269055 BC - Jan  3, 292272993 AD
  1713.          *     Hybrid    = Dec  2, 292269055 BC - Aug 17, 292278994 AD
  1714.          *
  1715.          * We know we've exceeded the maximum when either the month, date,
  1716.          * time, or era changes in response to setting the year.  We don't
  1717.          * check for month, date, and time here because the year and era are
  1718.          * sufficient to detect an invalid year setting.  NOTE: If code is
  1719.          * added to check the month and date in the future for some reason,
  1720.          * Feb 29 must be allowed to shift to Mar 1 when setting the year.
  1721.          */
  1722.         {
  1723.             Calendar *cal = (Calendar*)this->clone();
  1724.             cal->setLenient(TRUE);
  1725.             
  1726.             int32_t era = cal->get(ERA, status);
  1727.             if(U_FAILURE(status))
  1728.                 return 0;
  1729.  
  1730.             UDate d = cal->getTime(status);
  1731.             if(U_FAILURE(status))
  1732.                 return 0;
  1733.  
  1734.             /* Perform a binary search, with the invariant that lowGood is a
  1735.              * valid year, and highBad is an out of range year.
  1736.              */
  1737.             int32_t lowGood = kLeastMaxValues[YEAR];
  1738.             int32_t highBad = kMaxValues[YEAR] + 1;
  1739.             while((lowGood + 1) < highBad) {
  1740.                 int32_t y = (lowGood + highBad) / 2;
  1741.                 cal->set(YEAR, y);
  1742.                 if(cal->get(YEAR, status) == y && cal->get(ERA, status) == era) {
  1743.                     lowGood = y;
  1744.                 } 
  1745.                 else {
  1746.                     highBad = y;
  1747.                     cal->setTime(d, status); // Restore original fields
  1748.                 }
  1749.             }
  1750.             
  1751.             delete cal;
  1752.             return lowGood;
  1753.         }
  1754.  
  1755.         // and we know none of the other fields have variable maxima in
  1756.         // GregorianCalendar, so we can just return the fixed maximum
  1757.     default:
  1758.         return getMaximum(field);
  1759.     }
  1760. }
  1761.  
  1762. // -------------------------------------
  1763.  
  1764. bool_t
  1765. GregorianCalendar::inDaylightTime(UErrorCode& status) const
  1766. {
  1767.     if (U_FAILURE(status) || !getTimeZone().useDaylightTime()) 
  1768.         return FALSE;
  1769.  
  1770.     // Force an update of the state of the Calendar.
  1771.     ((GregorianCalendar*)this)->complete(status); // cast away const
  1772.  
  1773.     return U_SUCCESS(status) ? (internalGet(DST_OFFSET) != 0) : FALSE;
  1774. }
  1775.  
  1776. // -------------------------------------
  1777.  
  1778. int32_t
  1779. GregorianCalendar::getISOYear(UErrorCode& status) 
  1780. {
  1781.     ((GregorianCalendar*)this)->complete(status);
  1782.  
  1783.     int32_t woy = internalGet(WEEK_OF_YEAR);
  1784.     // Get the ISO year, which matches the week of year.  This
  1785.     // may be one year before or after the calendar year.
  1786.     int32_t isoYear = internalGet(YEAR);
  1787.     if (internalGet(MONTH) == Calendar::JANUARY) {
  1788.         if (woy >= 52) {
  1789.             --isoYear;
  1790.         }
  1791.     }
  1792.     else {
  1793.         if (woy == 1) {
  1794.             ++isoYear;
  1795.         }
  1796.     }
  1797.     return isoYear;
  1798. }
  1799.  
  1800. /**
  1801.  * Return the ERA.  We need a special method for this because the
  1802.  * default ERA is AD, but a zero (unset) ERA is BC.
  1803.  */
  1804. int32_t
  1805. GregorianCalendar::internalGetEra() const {
  1806.     return isSet(ERA) ? internalGet(ERA) : AD;
  1807. }
  1808.  
  1809. //eof
  1810.