mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 06:25:30 +00:00
ICU-22743 Change internal functions to propagate errors up.
This commit is contained in:
parent
5e35ffc87e
commit
0c02f8c007
11 changed files with 372 additions and 183 deletions
|
@ -3446,7 +3446,10 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField, UErrorCo
|
|||
if(isSet(UCAL_DAY_OF_MONTH)) {
|
||||
dayOfMonth = internalGet(UCAL_DAY_OF_MONTH,1);
|
||||
} else {
|
||||
dayOfMonth = getDefaultDayInMonth(year, month);
|
||||
dayOfMonth = getDefaultDayInMonth(year, month, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (uprv_add32_overflow(dayOfMonth, julianDay, &dayOfMonth)) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
|
@ -3654,7 +3657,7 @@ Calendar::getDefaultMonthInYear(int32_t /*eyear*/, UErrorCode& /* status */)
|
|||
}
|
||||
|
||||
int32_t
|
||||
Calendar::getDefaultDayInMonth(int32_t /*eyear*/, int32_t /*month*/)
|
||||
Calendar::getDefaultDayInMonth(int32_t /*eyear*/, int32_t /*month*/, UErrorCode& /* status */)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -116,9 +116,9 @@ U_NAMESPACE_BEGIN
|
|||
namespace {
|
||||
|
||||
const TimeZone* getAstronomerTimeZone();
|
||||
int32_t newMoonNear(const TimeZone*, double, UBool);
|
||||
int32_t newYear(const icu::ChineseCalendar::Setting&, int32_t);
|
||||
UBool isLeapMonthBetween(const TimeZone*, int32_t, int32_t);
|
||||
int32_t newMoonNear(const TimeZone*, double, UBool, UErrorCode&);
|
||||
int32_t newYear(const icu::ChineseCalendar::Setting&, int32_t, UErrorCode&);
|
||||
UBool isLeapMonthBetween(const TimeZone*, int32_t, int32_t, UErrorCode&);
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -253,13 +253,16 @@ int32_t ChineseCalendar::handleGetExtendedYear(UErrorCode& status) {
|
|||
*/
|
||||
int32_t ChineseCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month, UErrorCode& status) const {
|
||||
const Setting setting = getSetting(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
int32_t thisStart = handleComputeMonthStart(extendedYear, month, true, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
thisStart = thisStart -
|
||||
kEpochStartAsJulianDay + 1; // Julian day -> local days
|
||||
int32_t nextStart = newMoonNear(setting.zoneAstroCalc, thisStart + SYNODIC_GAP, true);
|
||||
int32_t nextStart = newMoonNear(setting.zoneAstroCalc, thisStart + SYNODIC_GAP, true, status);
|
||||
return nextStart - thisStart;
|
||||
}
|
||||
|
||||
|
@ -311,7 +314,7 @@ struct MonthInfo {
|
|||
};
|
||||
struct MonthInfo computeMonthInfo(
|
||||
const icu::ChineseCalendar::Setting& setting,
|
||||
int32_t gyear, int32_t days);
|
||||
int32_t gyear, int32_t days, UErrorCode& status);
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -353,8 +356,11 @@ int64_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t theNewYear = newYear(setting, gyear);
|
||||
int32_t newMoon = newMoonNear(setting.zoneAstroCalc, theNewYear + month * 29, true);
|
||||
int32_t theNewYear = newYear(setting, gyear, status);
|
||||
int32_t newMoon = newMoonNear(setting.zoneAstroCalc, theNewYear + month * 29, true, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Ignore IS_LEAP_MONTH field if useMonth is false
|
||||
bool isLeapMonth = false;
|
||||
|
@ -368,9 +374,15 @@ int64_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
|
|||
int32_t unusedDayOfYear;
|
||||
Grego::dayToFields(newMoon, gyear, unusedMonth, unusedDayOfWeek, unusedDayOfMonth, unusedDayOfYear);
|
||||
|
||||
struct MonthInfo monthInfo = computeMonthInfo(setting, gyear, newMoon);
|
||||
struct MonthInfo monthInfo = computeMonthInfo(setting, gyear, newMoon, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
if (month != monthInfo.month-1 || isLeapMonth != monthInfo.isLeapMonth) {
|
||||
newMoon = newMoonNear(setting.zoneAstroCalc, newMoon + SYNODIC_GAP, true);
|
||||
newMoon = newMoonNear(setting.zoneAstroCalc, newMoon + SYNODIC_GAP, true, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
int32_t julianDay;
|
||||
if (uprv_add32_overflow(newMoon-1, kEpochStartAsJulianDay, &julianDay)) {
|
||||
|
@ -450,10 +462,16 @@ struct RollMonthInfo rollMonth(const TimeZone* timeZone, int32_t amount, int32_t
|
|||
// otherwise it will be the start of month 1.
|
||||
int prevMoon = output.thisMoon -
|
||||
(int) (CalendarAstronomer::SYNODIC_MONTH * (month - 0.5));
|
||||
prevMoon = newMoonNear(timeZone, prevMoon, true);
|
||||
if (isLeapMonthBetween(timeZone, prevMoon, output.thisMoon)) {
|
||||
prevMoon = newMoonNear(timeZone, prevMoon, true, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
if (isLeapMonthBetween(timeZone, prevMoon, output.thisMoon, status)) {
|
||||
++month;
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now do the standard roll computation on month, with the
|
||||
|
@ -488,8 +506,9 @@ void ChineseCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode
|
|||
int32_t dayOfMonth = get(UCAL_DAY_OF_MONTH, status);
|
||||
bool isLeapMonth = get(UCAL_IS_LEAP_MONTH, status) == 1;
|
||||
if (U_FAILURE(status)) break;
|
||||
struct RollMonthInfo r = rollMonth(setting.zoneAstroCalc, amount,
|
||||
day, month, dayOfMonth, isLeapMonth, hasLeapMonthBetweenWinterSolstices, status);
|
||||
struct RollMonthInfo r = rollMonth(
|
||||
setting.zoneAstroCalc, amount, day, month, dayOfMonth, isLeapMonth,
|
||||
hasLeapMonthBetweenWinterSolstices, status);
|
||||
if (U_FAILURE(status)) break;
|
||||
if (r.newMoon != r.month) {
|
||||
offsetMonth(r.thisMoon, dayOfMonth, r.newMoon - r.month, status);
|
||||
|
@ -525,15 +544,18 @@ namespace {
|
|||
* @param days days after January 1, 1970 0:00 in the astronomical base zone
|
||||
* @return milliseconds after January 1, 1970 0:00 GMT
|
||||
*/
|
||||
double daysToMillis(const TimeZone* timeZone, double days) {
|
||||
double daysToMillis(const TimeZone* timeZone, double days, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
double millis = days * (double)kOneDay;
|
||||
if (timeZone != nullptr) {
|
||||
int32_t rawOffset, dstOffset;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
timeZone->getOffset(millis, false, rawOffset, dstOffset, status);
|
||||
if (U_SUCCESS(status)) {
|
||||
return millis - (double)(rawOffset + dstOffset);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
return millis - (double)(rawOffset + dstOffset);
|
||||
}
|
||||
return millis - (double)CHINA_OFFSET;
|
||||
}
|
||||
|
@ -544,14 +566,17 @@ double daysToMillis(const TimeZone* timeZone, double days) {
|
|||
* @param millis milliseconds after January 1, 1970 0:00 GMT
|
||||
* @return days after January 1, 1970 0:00 in the astronomical base zone
|
||||
*/
|
||||
double millisToDays(const TimeZone* timeZone, double millis) {
|
||||
double millisToDays(const TimeZone* timeZone, double millis, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
if (timeZone != nullptr) {
|
||||
int32_t rawOffset, dstOffset;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
timeZone->getOffset(millis, false, rawOffset, dstOffset, status);
|
||||
if (U_SUCCESS(status)) {
|
||||
return ClockMath::floorDivide(millis + (double)(rawOffset + dstOffset), kOneDay);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
return ClockMath::floorDivide(millis + (double)(rawOffset + dstOffset), kOneDay);
|
||||
}
|
||||
return ClockMath::floorDivide(millis + (double)CHINA_OFFSET, kOneDay);
|
||||
}
|
||||
|
@ -571,23 +596,35 @@ double millisToDays(const TimeZone* timeZone, double millis) {
|
|||
* winter solstice of the given year
|
||||
*/
|
||||
int32_t winterSolstice(const icu::ChineseCalendar::Setting& setting,
|
||||
int32_t gyear) {
|
||||
int32_t gyear, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
const TimeZone* timeZone = setting.zoneAstroCalc;
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int32_t cacheValue = CalendarCache::get(setting.winterSolsticeCache, gyear, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cacheValue == 0) {
|
||||
// In books December 15 is used, but it fails for some years
|
||||
// using our algorithms, e.g.: 1298 1391 1492 1553 1560. That
|
||||
// is, winterSolstice(1298) starts search at Dec 14 08:00:00
|
||||
// PST 1298 with a final result of Dec 14 10:31:59 PST 1299.
|
||||
double ms = daysToMillis(timeZone, Grego::fieldsToDay(gyear, UCAL_DECEMBER, 1));
|
||||
double ms = daysToMillis(timeZone, Grego::fieldsToDay(gyear, UCAL_DECEMBER, 1), status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Winter solstice is 270 degrees solar longitude aka Dongzhi
|
||||
double days = millisToDays(timeZone,
|
||||
CalendarAstronomer(ms)
|
||||
.getSunTime(CalendarAstronomer::WINTER_SOLSTICE(), true));
|
||||
.getSunTime(CalendarAstronomer::WINTER_SOLSTICE(), true),
|
||||
status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
if (days < INT32_MIN || days > INT32_MAX) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return 0;
|
||||
|
@ -608,14 +645,23 @@ int32_t winterSolstice(const icu::ChineseCalendar::Setting& setting,
|
|||
* @param days days after January 1, 1970 0:00 Asia/Shanghai
|
||||
* @param after if true, search for a new moon on or after the given
|
||||
* date; otherwise, search for a new moon before it
|
||||
* @param status
|
||||
* @return days after January 1, 1970 0:00 Asia/Shanghai of the nearest
|
||||
* new moon after or before <code>days</code>
|
||||
*/
|
||||
int32_t newMoonNear(const TimeZone* timeZone, double days, UBool after) {
|
||||
int32_t newMoonNear(const TimeZone* timeZone, double days, UBool after, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
double ms = daysToMillis(timeZone, days, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
return (int32_t) millisToDays(
|
||||
timeZone,
|
||||
CalendarAstronomer(daysToMillis(timeZone, days))
|
||||
.getMoonTime(CalendarAstronomer::NEW_MOON(), after));
|
||||
CalendarAstronomer(ms)
|
||||
.getMoonTime(CalendarAstronomer::NEW_MOON(), after),
|
||||
status);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -637,10 +683,20 @@ int32_t synodicMonthsBetween(int32_t day1, int32_t day2) {
|
|||
* @param timeZone time zone for the Astro calculation.
|
||||
* @param days days after January 1, 1970 0:00 Asia/Shanghai
|
||||
*/
|
||||
int32_t majorSolarTerm(const TimeZone* timeZone, int32_t days) {
|
||||
int32_t majorSolarTerm(const TimeZone* timeZone, int32_t days, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
// Compute (floor(solarLongitude / (pi/6)) + 2) % 12
|
||||
int32_t term = ( ((int32_t)(6 * CalendarAstronomer(daysToMillis(timeZone, days))
|
||||
double ms = daysToMillis(timeZone, days, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
int32_t term = ( ((int32_t)(6 * CalendarAstronomer(ms)
|
||||
.getSunLongitude() / CalendarAstronomer::PI)) + 2 ) % 12;
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
if (term < 1) {
|
||||
term += 12;
|
||||
}
|
||||
|
@ -653,9 +709,17 @@ int32_t majorSolarTerm(const TimeZone* timeZone, int32_t days) {
|
|||
* @param newMoon days after January 1, 1970 0:00 Asia/Shanghai of a new
|
||||
* moon
|
||||
*/
|
||||
UBool hasNoMajorSolarTerm(const TimeZone* timeZone, int32_t newMoon) {
|
||||
return majorSolarTerm(timeZone, newMoon) ==
|
||||
majorSolarTerm(timeZone, newMoonNear(timeZone, newMoon + SYNODIC_GAP, true));
|
||||
UBool hasNoMajorSolarTerm(const TimeZone* timeZone, int32_t newMoon, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return false;
|
||||
}
|
||||
int32_t term1 = majorSolarTerm(timeZone, newMoon, status);
|
||||
int32_t term2 = majorSolarTerm(
|
||||
timeZone, newMoonNear(timeZone, newMoon + SYNODIC_GAP, true, status), status);
|
||||
if (U_FAILURE(status)) {
|
||||
return false;
|
||||
}
|
||||
return term1 == term2;
|
||||
}
|
||||
|
||||
|
||||
|
@ -672,7 +736,10 @@ UBool hasNoMajorSolarTerm(const TimeZone* timeZone, int32_t newMoon) {
|
|||
* @param newMoon2 days after January 1, 1970 0:00 astronomical base zone
|
||||
* of a new moon
|
||||
*/
|
||||
UBool isLeapMonthBetween(const TimeZone* timeZone, int32_t newMoon1, int32_t newMoon2) {
|
||||
UBool isLeapMonthBetween(const TimeZone* timeZone, int32_t newMoon1, int32_t newMoon2, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef U_DEBUG_CHNSECAL
|
||||
// This is only needed to debug the timeOfAngle divergence bug.
|
||||
|
@ -685,10 +752,13 @@ UBool isLeapMonthBetween(const TimeZone* timeZone, int32_t newMoon1, int32_t new
|
|||
#endif
|
||||
|
||||
while (newMoon2 >= newMoon1) {
|
||||
if (hasNoMajorSolarTerm(timeZone, newMoon2)) {
|
||||
if (hasNoMajorSolarTerm(timeZone, newMoon2, status)) {
|
||||
return true;
|
||||
}
|
||||
newMoon2 = newMoonNear(timeZone, newMoon2 - SYNODIC_GAP, false);
|
||||
newMoon2 = newMoonNear(timeZone, newMoon2 - SYNODIC_GAP, false, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -704,39 +774,63 @@ UBool isLeapMonthBetween(const TimeZone* timeZone, int32_t newMoon1, int32_t new
|
|||
*/
|
||||
struct MonthInfo computeMonthInfo(
|
||||
const icu::ChineseCalendar::Setting& setting,
|
||||
int32_t gyear, int32_t days) {
|
||||
struct MonthInfo output;
|
||||
int32_t gyear, int32_t days, UErrorCode& status) {
|
||||
struct MonthInfo output = {0, 0, 0, false, false};
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
// Find the winter solstices before and after the target date.
|
||||
// These define the boundaries of this Chinese year, specifically,
|
||||
// the position of month 11, which always contains the solstice.
|
||||
// We want solsticeBefore <= date < solsticeAfter.
|
||||
int32_t solsticeBefore;
|
||||
int32_t solsticeAfter = winterSolstice(setting, gyear);
|
||||
int32_t solsticeAfter = winterSolstice(setting, gyear, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
if (days < solsticeAfter) {
|
||||
solsticeBefore = winterSolstice(setting, gyear - 1);
|
||||
solsticeBefore = winterSolstice(setting, gyear - 1, status);
|
||||
} else {
|
||||
solsticeBefore = solsticeAfter;
|
||||
solsticeAfter = winterSolstice(setting, gyear + 1);
|
||||
solsticeAfter = winterSolstice(setting, gyear + 1, status);
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
|
||||
const TimeZone* timeZone = setting.zoneAstroCalc;
|
||||
// Find the start of the month after month 11. This will be either
|
||||
// the prior month 12 or leap month 11 (very rare). Also find the
|
||||
// start of the following month 11.
|
||||
int32_t firstMoon = newMoonNear(timeZone, solsticeBefore + 1, true);
|
||||
int32_t lastMoon = newMoonNear(timeZone, solsticeAfter + 1, false);
|
||||
output.thisMoon = newMoonNear(timeZone, days + 1, false); // Start of this month
|
||||
int32_t firstMoon = newMoonNear(timeZone, solsticeBefore + 1, true, status);
|
||||
int32_t lastMoon = newMoonNear(timeZone, solsticeAfter + 1, false, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
output.thisMoon = newMoonNear(timeZone, days + 1, false, status); // Start of this month
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
output.hasLeapMonthBetweenWinterSolstices = synodicMonthsBetween(firstMoon, lastMoon) == 12;
|
||||
|
||||
output.month = synodicMonthsBetween(firstMoon, output.thisMoon);
|
||||
int32_t theNewYear = newYear(setting, gyear);
|
||||
int32_t theNewYear = newYear(setting, gyear, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
if (days < theNewYear) {
|
||||
theNewYear = newYear(setting, gyear-1);
|
||||
theNewYear = newYear(setting, gyear-1, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
if (output.hasLeapMonthBetweenWinterSolstices &&
|
||||
isLeapMonthBetween(timeZone, firstMoon, output.thisMoon)) {
|
||||
isLeapMonthBetween(timeZone, firstMoon, output.thisMoon, status)) {
|
||||
output.month--;
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
if (output.month < 1) {
|
||||
output.month += 12;
|
||||
}
|
||||
|
@ -745,9 +839,13 @@ struct MonthInfo computeMonthInfo(
|
|||
output.ordinalMonth += 12;
|
||||
}
|
||||
output.isLeapMonth = output.hasLeapMonthBetweenWinterSolstices &&
|
||||
hasNoMajorSolarTerm(timeZone, output.thisMoon) &&
|
||||
hasNoMajorSolarTerm(timeZone, output.thisMoon, status) &&
|
||||
!isLeapMonthBetween(timeZone, firstMoon,
|
||||
newMoonNear(timeZone, output.thisMoon - SYNODIC_GAP, false));
|
||||
newMoonNear(timeZone, output.thisMoon - SYNODIC_GAP, false, status),
|
||||
status);
|
||||
if (U_FAILURE(status)) {
|
||||
return output;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -787,7 +885,10 @@ void ChineseCalendar::handleComputeFields(int32_t julianDay, UErrorCode & status
|
|||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
struct MonthInfo monthInfo = computeMonthInfo(setting, gyear, days);
|
||||
struct MonthInfo monthInfo = computeMonthInfo(setting, gyear, days, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
hasLeapMonthBetweenWinterSolstices = monthInfo.hasLeapMonthBetweenWinterSolstices;
|
||||
|
||||
// Extended year and cycle year is based on the epoch year
|
||||
|
@ -808,9 +909,15 @@ void ChineseCalendar::handleComputeFields(int32_t julianDay, UErrorCode & status
|
|||
// date is in month 11, leap 11, 12. There is never a leap 12.
|
||||
// New year computations are cached so this should be cheap in
|
||||
// the long run.
|
||||
int32_t theNewYear = newYear(setting, gyear);
|
||||
int32_t theNewYear = newYear(setting, gyear, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (days < theNewYear) {
|
||||
theNewYear = newYear(setting, gyear-1);
|
||||
theNewYear = newYear(setting, gyear-1, status);
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
cycle++;
|
||||
yearOfCycle++;
|
||||
|
@ -858,26 +965,37 @@ namespace {
|
|||
* Chinese new year of the given year (this will be a new moon)
|
||||
*/
|
||||
int32_t newYear(const icu::ChineseCalendar::Setting& setting,
|
||||
int32_t gyear) {
|
||||
int32_t gyear, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
const TimeZone* timeZone = setting.zoneAstroCalc;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int32_t cacheValue = CalendarCache::get(setting.newYearCache, gyear, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cacheValue == 0) {
|
||||
|
||||
int32_t solsticeBefore= winterSolstice(setting, gyear - 1);
|
||||
int32_t solsticeAfter = winterSolstice(setting, gyear);
|
||||
int32_t newMoon1 = newMoonNear(timeZone, solsticeBefore + 1, true);
|
||||
int32_t newMoon2 = newMoonNear(timeZone, newMoon1 + SYNODIC_GAP, true);
|
||||
int32_t newMoon11 = newMoonNear(timeZone, solsticeAfter + 1, false);
|
||||
int32_t solsticeBefore= winterSolstice(setting, gyear - 1, status);
|
||||
int32_t solsticeAfter = winterSolstice(setting, gyear, status);
|
||||
int32_t newMoon1 = newMoonNear(timeZone, solsticeBefore + 1, true, status);
|
||||
int32_t newMoon2 = newMoonNear(timeZone, newMoon1 + SYNODIC_GAP, true, status);
|
||||
int32_t newMoon11 = newMoonNear(timeZone, solsticeAfter + 1, false, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (synodicMonthsBetween(newMoon1, newMoon11) == 12 &&
|
||||
(hasNoMajorSolarTerm(timeZone, newMoon1) ||
|
||||
hasNoMajorSolarTerm(timeZone, newMoon2))) {
|
||||
cacheValue = newMoonNear(timeZone, newMoon2 + SYNODIC_GAP, true);
|
||||
(hasNoMajorSolarTerm(timeZone, newMoon1, status) ||
|
||||
hasNoMajorSolarTerm(timeZone, newMoon2, status))) {
|
||||
cacheValue = newMoonNear(timeZone, newMoon2 + SYNODIC_GAP, true, status);
|
||||
} else {
|
||||
cacheValue = newMoon2;
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CalendarCache::put(setting.newYearCache, gyear, cacheValue, status);
|
||||
}
|
||||
|
@ -904,7 +1022,9 @@ int32_t newYear(const icu::ChineseCalendar::Setting& setting,
|
|||
void ChineseCalendar::offsetMonth(int32_t newMoon, int32_t dayOfMonth, int32_t delta,
|
||||
UErrorCode& status) {
|
||||
const Setting setting = getSetting(status);
|
||||
if (U_FAILURE(status)) { return; }
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Move to the middle of the month before our target month.
|
||||
double value = newMoon;
|
||||
|
@ -917,7 +1037,10 @@ void ChineseCalendar::offsetMonth(int32_t newMoon, int32_t dayOfMonth, int32_t d
|
|||
newMoon = static_cast<int32_t>(value);
|
||||
|
||||
// Search forward to the target month's new moon
|
||||
newMoon = newMoonNear(setting.zoneAstroCalc, newMoon, true);
|
||||
newMoon = newMoonNear(setting.zoneAstroCalc, newMoon, true, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the target dayOfMonth
|
||||
int32_t jd = newMoon + kEpochStartAsJulianDay - 1 + dayOfMonth;
|
||||
|
|
|
@ -304,6 +304,12 @@ void HebrewCalendar::add(EDateFields field, int32_t amount, UErrorCode& status)
|
|||
add((UCalendarDateFields)field, amount, status);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
int32_t monthsInYear(int32_t year);
|
||||
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* Rolls (up/down) a specified amount time on the given field. For
|
||||
* example, to roll the current date up by three days, you can call
|
||||
|
@ -396,6 +402,8 @@ static const int32_t MONTH_PARTS = MONTH_DAYS*DAY_PARTS + MONTH_FRACT;
|
|||
// Bet (Monday), Hey (5 hours from sunset), Resh-Daled (204).
|
||||
static const int32_t BAHARAD = 11*HOUR_PARTS + 204;
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Finds the day # of the first day in the given Hebrew year.
|
||||
* To do this, we want to calculate the time of the Tishri 1 new moon
|
||||
|
@ -416,7 +424,7 @@ static const int32_t BAHARAD = 11*HOUR_PARTS + 204;
|
|||
* http://www.faqs.org/faqs/calendars/faq/</a>
|
||||
* </ul>
|
||||
*/
|
||||
int32_t HebrewCalendar::startOfYear(int32_t year, UErrorCode &status)
|
||||
int32_t startOfYear(int32_t year, UErrorCode &status)
|
||||
{
|
||||
ucln_i18n_registerCleanup(UCLN_I18N_HEBREW_CALENDAR, calendar_hebrew_cleanup);
|
||||
int64_t day = CalendarCache::get(&gCache, year, status);
|
||||
|
@ -440,13 +448,13 @@ int32_t HebrewCalendar::startOfYear(int32_t year, UErrorCode &status)
|
|||
day += 1;
|
||||
wd = (day % 7);
|
||||
}
|
||||
if (wd == 1 && frac > 15*HOUR_PARTS+204 && !isLeapYear(year) ) {
|
||||
if (wd == 1 && frac > 15*HOUR_PARTS+204 && !HebrewCalendar::isLeapYear(year) ) {
|
||||
// If the new moon falls after 3:11:20am (15h204p from the previous noon)
|
||||
// on a Tuesday and it is not a leap year, postpone by 2 days.
|
||||
// This prevents 356-day years.
|
||||
day += 2;
|
||||
}
|
||||
else if (wd == 0 && frac > 21*HOUR_PARTS+589 && isLeapYear(year-1) ) {
|
||||
else if (wd == 0 && frac > 21*HOUR_PARTS+589 && HebrewCalendar::isLeapYear(year-1) ) {
|
||||
// If the new moon falls after 9:32:43 1/3am (21h589p from yesterday noon)
|
||||
// on a Monday and *last* year was a leap year, postpone by 1 day.
|
||||
// Prevents 382-day years.
|
||||
|
@ -463,16 +471,11 @@ int32_t HebrewCalendar::startOfYear(int32_t year, UErrorCode &status)
|
|||
return day;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the day of the week for a given day
|
||||
*
|
||||
* @param day The # of days since the start of the Hebrew calendar,
|
||||
* 1-based (i.e. 1/1/1 AM is day 1).
|
||||
*/
|
||||
int32_t HebrewCalendar::absoluteDayToDayOfWeek(int32_t day)
|
||||
{
|
||||
// We know that 1/1/1 AM is a Monday, which makes the math easy...
|
||||
return (day % 7) + 1;
|
||||
int32_t daysInYear(int32_t eyear, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
return startOfYear(eyear+1, status) - startOfYear(eyear, status);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -481,9 +484,15 @@ int32_t HebrewCalendar::absoluteDayToDayOfWeek(int32_t day)
|
|||
* 1 "Normal" year with 354 or 384 days
|
||||
* 2 "Complete" year with 355 or 385 days
|
||||
*/
|
||||
int32_t HebrewCalendar::yearType(int32_t year) const
|
||||
int32_t yearType(int32_t year, UErrorCode& status)
|
||||
{
|
||||
int32_t yearLength = handleGetYearLength(year);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
int32_t yearLength = daysInYear(year, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (yearLength > 380) {
|
||||
yearLength -= 30; // Subtract length of leap month.
|
||||
|
@ -505,6 +514,8 @@ int32_t HebrewCalendar::yearType(int32_t year) const
|
|||
return type;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
//
|
||||
/**
|
||||
* Determine whether a given Hebrew year is a leap year
|
||||
*
|
||||
|
@ -517,10 +528,14 @@ UBool HebrewCalendar::isLeapYear(int32_t year) {
|
|||
return x >= ((x < 0) ? -7 : 12);
|
||||
}
|
||||
|
||||
int32_t HebrewCalendar::monthsInYear(int32_t year) {
|
||||
return isLeapYear(year) ? 13 : 12;
|
||||
namespace{
|
||||
|
||||
int32_t monthsInYear(int32_t year) {
|
||||
return HebrewCalendar::isLeapYear(year) ? 13 : 12;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Calendar framework
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -557,8 +572,14 @@ int32_t HebrewCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month
|
|||
switch (month) {
|
||||
case HESHVAN:
|
||||
case KISLEV:
|
||||
// These two month lengths can vary
|
||||
return MONTH_LENGTH[month][yearType(extendedYear)];
|
||||
{
|
||||
// These two month lengths can vary
|
||||
int32_t type = yearType(extendedYear, status);
|
||||
if(U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
return MONTH_LENGTH[month][type];
|
||||
}
|
||||
|
||||
default:
|
||||
// The rest are a fixed length
|
||||
|
@ -572,7 +593,11 @@ int32_t HebrewCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month
|
|||
*/
|
||||
int32_t HebrewCalendar::handleGetYearLength(int32_t eyear) const {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
return startOfYear(eyear+1, status) - startOfYear(eyear, status);
|
||||
int32_t len = daysInYear(eyear, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 12;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void HebrewCalendar::validateField(UCalendarDateFields field, UErrorCode &status) {
|
||||
|
@ -635,12 +660,16 @@ void HebrewCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
|
|||
}
|
||||
|
||||
// Now figure out which month we're in, and the date within that month
|
||||
int32_t type = yearType(year);
|
||||
int32_t type = yearType(year, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
UBool isLeap = isLeapYear(year);
|
||||
|
||||
int32_t month = 0;
|
||||
int32_t momax = UPRV_LENGTHOF(MONTH_START);
|
||||
while (month < momax && dayOfYear > ( isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type] ) ) {
|
||||
while (month < momax &&
|
||||
dayOfYear > ( isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type] ) ) {
|
||||
month++;
|
||||
}
|
||||
if (month >= momax || month<=0) {
|
||||
|
@ -663,25 +692,25 @@ void HebrewCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
|
|||
// Check out of bound year
|
||||
int32_t min_year = handleGetLimit(UCAL_EXTENDED_YEAR, UCAL_LIMIT_MINIMUM);
|
||||
if (year < min_year) {
|
||||
if (!isLenient()) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
year = min_year;
|
||||
if (!isLenient()) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
year = min_year;
|
||||
}
|
||||
int32_t max_year = handleGetLimit(UCAL_EXTENDED_YEAR, UCAL_LIMIT_MAXIMUM);
|
||||
if (max_year < year) {
|
||||
if (!isLenient()) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
year = max_year;
|
||||
if (!isLenient()) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
year = max_year;
|
||||
}
|
||||
internalSet(UCAL_YEAR, year);
|
||||
internalSet(UCAL_EXTENDED_YEAR, year);
|
||||
int32_t ordinal_month = month;
|
||||
if (!isLeap && ordinal_month > ADAR_1) {
|
||||
ordinal_month--;
|
||||
ordinal_month--;
|
||||
}
|
||||
internalSet(UCAL_ORDINAL_MONTH, ordinal_month);
|
||||
internalSet(UCAL_MONTH, month);
|
||||
|
@ -754,10 +783,14 @@ int64_t HebrewCalendar::handleComputeMonthStart(
|
|||
}
|
||||
|
||||
if (month != 0) {
|
||||
int32_t type = yearType(eyear, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
if (isLeapYear(eyear)) {
|
||||
day += LEAP_MONTH_START[month][yearType(eyear)];
|
||||
day += LEAP_MONTH_START[month][type];
|
||||
} else {
|
||||
day += MONTH_START[month][yearType(eyear)];
|
||||
day += MONTH_START[month][type];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -329,6 +329,7 @@ public:
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
virtual int32_t handleGetYearLength(int32_t eyear) const override;
|
||||
|
||||
/**
|
||||
* Subclasses may override this method to compute several fields
|
||||
* specific to each calendar system. These are:
|
||||
|
@ -427,44 +428,6 @@ public:
|
|||
|
||||
protected:
|
||||
virtual int32_t internalGetMonth(UErrorCode& status) const override;
|
||||
|
||||
private: // Calendar-specific implementation
|
||||
/**
|
||||
* Finds the day # of the first day in the given Hebrew year.
|
||||
* To do this, we want to calculate the time of the Tishri 1 new moon
|
||||
* in that year.
|
||||
* <p>
|
||||
* The algorithm here is similar to ones described in a number of
|
||||
* references, including:
|
||||
* <ul>
|
||||
* <li>"Calendrical Calculations", by Nachum Dershowitz & Edward Reingold,
|
||||
* Cambridge University Press, 1997, pages 85-91.
|
||||
*
|
||||
* <li>Hebrew Calendar Science and Myths,
|
||||
* <a href="http://www.geocities.com/Athens/1584/">
|
||||
* http://www.geocities.com/Athens/1584/</a>
|
||||
*
|
||||
* <li>The Calendar FAQ,
|
||||
* <a href="http://www.faqs.org/faqs/calendars/faq/">
|
||||
* http://www.faqs.org/faqs/calendars/faq/</a>
|
||||
* </ul>
|
||||
* @param year extended year
|
||||
* @return day number (JD)
|
||||
* @internal
|
||||
*/
|
||||
static int32_t startOfYear(int32_t year, UErrorCode& status);
|
||||
|
||||
static int32_t absoluteDayToDayOfWeek(int32_t day) ;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
int32_t yearType(int32_t year) const;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
static int32_t monthsInYear(int32_t year) ;
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
|
|
@ -303,7 +303,7 @@ inline bool civilLeapYear(int32_t year) {
|
|||
return (14 + 11 * year) % 30 < 11;
|
||||
}
|
||||
|
||||
int32_t trueMonthStart(int32_t month);
|
||||
int32_t trueMonthStart(int32_t month, UErrorCode& status);
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -311,8 +311,8 @@ int32_t trueMonthStart(int32_t month);
|
|||
* Return the day # on which the given year starts. Days are counted
|
||||
* from the Hijri epoch, origin 0.
|
||||
*/
|
||||
int64_t IslamicCalendar::yearStart(int32_t year) const{
|
||||
return trueMonthStart(12*(year-1));
|
||||
int64_t IslamicCalendar::yearStart(int32_t year, UErrorCode& status) const {
|
||||
return trueMonthStart(12*(year-1), status);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -334,7 +334,7 @@ int64_t IslamicCalendar::monthStart(int32_t year, int32_t month, UErrorCode& sta
|
|||
return 0;
|
||||
}
|
||||
|
||||
return trueMonthStart(month);
|
||||
return trueMonthStart(month, status);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -357,9 +357,11 @@ double moonAge(UDate time);
|
|||
*
|
||||
* @return The day number on which the given month starts.
|
||||
*/
|
||||
int32_t trueMonthStart(int32_t month) {
|
||||
int32_t trueMonthStart(int32_t month, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
ucln_i18n_registerCleanup(UCLN_I18N_ISLAMIC_CALENDAR, calendar_islamic_cleanup);
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int64_t start = CalendarCache::get(&gMonthCache, month, status);
|
||||
|
||||
if (U_SUCCESS(status) && start==0) {
|
||||
|
@ -417,18 +419,40 @@ double moonAge(UDate time) {
|
|||
* @draft ICU 2.4
|
||||
*/
|
||||
int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month,
|
||||
UErrorCode& /* status */) const {
|
||||
UErrorCode& status) const {
|
||||
month = 12*(extendedYear-1) + month;
|
||||
return trueMonthStart(month+1) - trueMonthStart(month) ;
|
||||
int32_t len = trueMonthStart(month+1, status) - trueMonthStart(month, status) ;
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
int32_t yearLength(int32_t extendedYear, UErrorCode& status) {
|
||||
int32_t month = 12*(extendedYear-1);
|
||||
int32_t length = trueMonthStart(month + 12, status) - trueMonthStart(month, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
} // namepsace
|
||||
/**
|
||||
* Return the number of days in the given Islamic year
|
||||
* @draft ICU 2.4
|
||||
*/
|
||||
int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear) const {
|
||||
int32_t month = 12*(extendedYear-1);
|
||||
return (trueMonthStart(month + 12) - trueMonthStart(month));
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int32_t length = yearLength(extendedYear, status);
|
||||
if (U_FAILURE(status)) {
|
||||
// fallback to normal Islamic calendar length 355 day a year if we
|
||||
// encounter error and cannot propagate.
|
||||
return 355;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -500,7 +524,9 @@ int32_t IslamicCalendar::handleGetExtendedYear(UErrorCode& /* status */) {
|
|||
* @draft ICU 2.4
|
||||
*/
|
||||
void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) return;
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
int32_t days = julianDay - getEpoc();
|
||||
|
||||
// Guess at the number of elapsed full months since the epoch
|
||||
|
@ -516,10 +542,16 @@ void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
|
|||
|
||||
// Find out the last time that the new moon was actually visible at this longitude
|
||||
// This returns midnight the night that the moon was visible at sunset.
|
||||
while ((startDate = trueMonthStart(month)) > days) {
|
||||
while ((startDate = trueMonthStart(month, status)) > days) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
// If it was after the date in question, back up a month and try again
|
||||
month--;
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t year = month >= 0 ? ((month / 12) + 1) : ((month + 1 ) / 12);
|
||||
month = ((month % 12) + 12 ) % 12;
|
||||
|
@ -636,7 +668,7 @@ IslamicCivilCalendar* IslamicCivilCalendar::clone() const {
|
|||
* Return the day # on which the given year starts. Days are counted
|
||||
* from the Hijri epoch, origin 0.
|
||||
*/
|
||||
int64_t IslamicCivilCalendar::yearStart(int32_t year) const{
|
||||
int64_t IslamicCivilCalendar::yearStart(int32_t year, UErrorCode& /* status */) const {
|
||||
return 354LL * (year-1LL) + ClockMath::floorDivideInt64(3 + 11LL * year, 30LL);
|
||||
}
|
||||
|
||||
|
@ -696,14 +728,19 @@ int32_t IslamicCivilCalendar::handleGetYearLength(int32_t extendedYear) const {
|
|||
* @draft ICU 2.4
|
||||
*/
|
||||
void IslamicCivilCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) return;
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
int32_t days = julianDay - getEpoc();
|
||||
|
||||
// Use the civil calendar approximation, which is just arithmetic
|
||||
int64_t year =
|
||||
ClockMath::floorDivideInt64(30LL * days + 10646LL, 10631LL);
|
||||
int32_t month = static_cast<int32_t>(
|
||||
uprv_ceil((days - 29 - yearStart(year)) / 29.5 ));
|
||||
uprv_ceil((days - 29 - yearStart(year, status)) / 29.5 ));
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
month = month<11?month:11;
|
||||
|
||||
int64_t dayOfMonth = (days - monthStart(year, month, status)) + 1;
|
||||
|
@ -781,9 +818,9 @@ IslamicUmalquraCalendar* IslamicUmalquraCalendar::clone() const {
|
|||
* Return the day # on which the given year starts. Days are counted
|
||||
* from the Hijri epoch, origin 0.
|
||||
*/
|
||||
int64_t IslamicUmalquraCalendar::yearStart(int32_t year) const {
|
||||
int64_t IslamicUmalquraCalendar::yearStart(int32_t year, UErrorCode& status) const {
|
||||
if (year < UMALQURA_YEAR_START || year > UMALQURA_YEAR_END) {
|
||||
return IslamicCivilCalendar::yearStart(year);
|
||||
return IslamicCivilCalendar::yearStart(year, status);
|
||||
}
|
||||
year -= UMALQURA_YEAR_START;
|
||||
// rounded least-squares fit of the dates previously calculated from UMALQURA_MONTHLENGTH iteration
|
||||
|
@ -801,10 +838,10 @@ int64_t IslamicUmalquraCalendar::yearStart(int32_t year) const {
|
|||
* @param month The hijri month, 0-based (assumed to be in range 0..11)
|
||||
*/
|
||||
int64_t IslamicUmalquraCalendar::monthStart(int32_t year, int32_t month, UErrorCode& status) const {
|
||||
int64_t ms = yearStart(year, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
int64_t ms = yearStart(year);
|
||||
for(int i=0; i< month; i++){
|
||||
ms+= handleGetMonthLength(year, i, status);
|
||||
if (U_FAILURE(status)) {
|
||||
|
@ -834,20 +871,32 @@ int32_t IslamicUmalquraCalendar::handleGetMonthLength(int32_t extendedYear, int3
|
|||
return length;
|
||||
}
|
||||
|
||||
int32_t IslamicUmalquraCalendar::yearLength(int32_t extendedYear, UErrorCode& status) const {
|
||||
if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
|
||||
return IslamicCivilCalendar::handleGetYearLength(extendedYear);
|
||||
}
|
||||
int length = 0;
|
||||
for(int i=0; i<12; i++) {
|
||||
length += handleGetMonthLength(extendedYear, i, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of days in the given Islamic year
|
||||
* @draft ICU 2.4
|
||||
*/
|
||||
int32_t IslamicUmalquraCalendar::handleGetYearLength(int32_t extendedYear) const {
|
||||
if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
|
||||
return IslamicCivilCalendar::handleGetYearLength(extendedYear);
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int32_t length = yearLength(extendedYear, status);
|
||||
if (U_FAILURE(status)) {
|
||||
// fallback to normal Islamic calendar length 355 day a year if we
|
||||
// encounter error and cannot propagate.
|
||||
return 355;
|
||||
}
|
||||
int length = 0;
|
||||
UErrorCode internalStatus = U_ZERO_ERROR;
|
||||
for(int i=0; i<12; i++) {
|
||||
length += handleGetMonthLength(extendedYear, i, internalStatus);
|
||||
}
|
||||
U_ASSERT(U_SUCCESS(internalStatus));
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -868,12 +917,17 @@ int32_t IslamicUmalquraCalendar::handleGetYearLength(int32_t extendedYear) const
|
|||
* @draft ICU 2.4
|
||||
*/
|
||||
void IslamicUmalquraCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
|
||||
if (U_FAILURE(status)) return;
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
int64_t year;
|
||||
int32_t month;
|
||||
int32_t days = julianDay - getEpoc();
|
||||
|
||||
static int64_t kUmalquraStart = yearStart(UMALQURA_YEAR_START);
|
||||
static int64_t kUmalquraStart = yearStart(UMALQURA_YEAR_START, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (days < kUmalquraStart) {
|
||||
IslamicCivilCalendar::handleComputeFields(julianDay, status);
|
||||
return;
|
||||
|
@ -886,13 +940,16 @@ void IslamicUmalquraCalendar::handleComputeFields(int32_t julianDay, UErrorCode
|
|||
int32_t d = 1;
|
||||
// need a slight correction to some
|
||||
while (d > 0) {
|
||||
d = days - yearStart(++year) + 1;
|
||||
int32_t yearLength = handleGetYearLength(year);
|
||||
if (d == yearLength) {
|
||||
d = days - yearStart(++year, status) + 1;
|
||||
int32_t length = yearLength(year, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (d == length) {
|
||||
month = 11;
|
||||
break;
|
||||
}
|
||||
if (d < yearLength){
|
||||
if (d < length){
|
||||
int32_t monthLen = handleGetMonthLength(year, month, status);
|
||||
for (month = 0;
|
||||
d > monthLen;
|
||||
|
|
|
@ -201,7 +201,7 @@ class U_I18N_API IslamicCalendar : public Calendar {
|
|||
* Return the day # on which the given year starts. Days are counted
|
||||
* from the Hijri epoch, origin 0.
|
||||
*/
|
||||
virtual int64_t yearStart(int32_t year) const;
|
||||
virtual int64_t yearStart(int32_t year, UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Return the day # on which the given month starts. Days are counted
|
||||
|
@ -413,7 +413,7 @@ class U_I18N_API IslamicCivilCalendar : public IslamicCalendar {
|
|||
* from the Hijri epoch, origin 0.
|
||||
* @internal
|
||||
*/
|
||||
virtual int64_t yearStart(int32_t year) const override;
|
||||
virtual int64_t yearStart(int32_t year, UErrorCode& status) const override;
|
||||
|
||||
/**
|
||||
* Return the day # on which the given month starts. Days are counted
|
||||
|
@ -596,7 +596,7 @@ class U_I18N_API IslamicUmalquraCalendar : public IslamicCivilCalendar {
|
|||
* from the Hijri epoch, origin 0.
|
||||
* @internal
|
||||
*/
|
||||
virtual int64_t yearStart(int32_t year) const override;
|
||||
virtual int64_t yearStart(int32_t year, UErrorCode& status) const override;
|
||||
|
||||
/**
|
||||
* Return the day # on which the given month starts. Days are counted
|
||||
|
@ -640,6 +640,9 @@ class U_I18N_API IslamicUmalquraCalendar : public IslamicCivilCalendar {
|
|||
* @internal
|
||||
*/
|
||||
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
|
||||
|
||||
private:
|
||||
virtual int32_t yearLength(int32_t extendedYear, UErrorCode& status) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -171,15 +171,19 @@ int32_t JapaneseCalendar::getDefaultMonthInYear(int32_t eyear, UErrorCode& statu
|
|||
return month;
|
||||
}
|
||||
|
||||
int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month)
|
||||
int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t eyear, int32_t month, UErrorCode& status)
|
||||
{
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
int32_t era = internalGetEra();
|
||||
int32_t day = 1;
|
||||
|
||||
int32_t eraStart[3] = { 0,0,0 };
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
gJapaneseEraRules->getStartDate(era, eraStart, status);
|
||||
U_ASSERT(U_SUCCESS(status));
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
if (eyear == eraStart[0] && (month == eraStart[1] - 1)) {
|
||||
return eraStart[2];
|
||||
}
|
||||
|
|
|
@ -195,6 +195,7 @@ protected:
|
|||
* taking year and era into account. Will return the first month of the given era, if
|
||||
* the current year is an ascension year.
|
||||
* @param eyear the extended year
|
||||
* @param status Indicates the status.
|
||||
* @internal
|
||||
*/
|
||||
virtual int32_t getDefaultMonthInYear(int32_t eyear, UErrorCode& status) override;
|
||||
|
@ -205,9 +206,10 @@ protected:
|
|||
* era, if the current month is an ascension year and month.
|
||||
* @param eyear the extended year
|
||||
* @param mon the month in the year
|
||||
* @param status Indicates the status.
|
||||
* @internal
|
||||
*/
|
||||
virtual int32_t getDefaultDayInMonth(int32_t eyear, int32_t month) override;
|
||||
virtual int32_t getDefaultDayInMonth(int32_t eyear, int32_t month, UErrorCode& status) override;
|
||||
|
||||
virtual bool isEra0CountingBackward() const override { return false; }
|
||||
};
|
||||
|
|
|
@ -1576,10 +1576,9 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
|
|||
case UDAT_MONTH_FIELD:
|
||||
case UDAT_STANDALONE_MONTH_FIELD:
|
||||
if (uprv_strcmp(cal.getType(),"hebrew") == 0) {
|
||||
HebrewCalendar *hc = (HebrewCalendar*)&cal;
|
||||
if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
|
||||
if (HebrewCalendar::isLeapYear(cal.get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
|
||||
value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar.
|
||||
if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 )
|
||||
if (!HebrewCalendar::isLeapYear(cal.get(UCAL_YEAR,status)) && value >= 6 && count < 3 )
|
||||
value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
|
||||
}
|
||||
{
|
||||
|
|
|
@ -2045,9 +2045,11 @@ protected:
|
|||
* taking currently-set year and era into account. Defaults to 1 for Gregorian.
|
||||
* @param eyear the extended year
|
||||
* @param month the month in the year
|
||||
* @param status Output param set to failure code on function return
|
||||
* when this function fails.
|
||||
* @internal
|
||||
*/
|
||||
virtual int32_t getDefaultDayInMonth(int32_t eyear, int32_t month);
|
||||
virtual int32_t getDefaultDayInMonth(int32_t eyear, int32_t month, UErrorCode& status);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Protected utility methods for use by subclasses. These are very handy
|
||||
|
|
|
@ -5651,7 +5651,7 @@ void CalendarTest::Test22633ChineseOverflow() {
|
|||
U_ASSERT(U_SUCCESS(status));
|
||||
cal->set(UCAL_EXTENDED_YEAR, -1594662558);
|
||||
cal->get(UCAL_YEAR, status);
|
||||
assertTrue("Should return success", U_SUCCESS(status));
|
||||
assertTrue("Should return failure", U_FAILURE(status));
|
||||
|
||||
cal->setTime(17000065021099877464213620139773683829419175940649608600213244013003611130029599692535053209683880603725167923910423116397083334648012657787978113960494455603744210944.000000, status);
|
||||
cal->add(UCAL_YEAR, 1935762034, status);
|
||||
|
|
Loading…
Add table
Reference in a new issue