mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-10 15:42:14 +00:00
parent
6d8b63ce84
commit
7153a3db52
8 changed files with 126 additions and 12 deletions
|
@ -253,11 +253,16 @@ int32_t ChineseCalendar::handleGetExtendedYear(UErrorCode& status) {
|
|||
* @stable ICU 2.8
|
||||
*/
|
||||
int32_t ChineseCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month, UErrorCode& status) const {
|
||||
bool isLeapMonth = internalGet(UCAL_IS_LEAP_MONTH) == 1;
|
||||
return handleGetMonthLengthWithLeap(extendedYear, month, isLeapMonth, status);
|
||||
}
|
||||
|
||||
int32_t ChineseCalendar::handleGetMonthLengthWithLeap(int32_t extendedYear, int32_t month, bool leap, UErrorCode& status) const {
|
||||
const Setting setting = getSetting(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
int32_t thisStart = handleComputeMonthStart(extendedYear, month, true, status);
|
||||
int32_t thisStart = handleComputeMonthStartWithLeap(extendedYear, month, leap, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -333,6 +338,14 @@ struct MonthInfo computeMonthInfo(
|
|||
* @stable ICU 2.8
|
||||
*/
|
||||
int64_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth, UErrorCode& status) const {
|
||||
bool isLeapMonth = false;
|
||||
if (useMonth) {
|
||||
isLeapMonth = internalGet(UCAL_IS_LEAP_MONTH) != 0;
|
||||
}
|
||||
return handleComputeMonthStartWithLeap(eyear, month, isLeapMonth, status);
|
||||
}
|
||||
|
||||
int64_t ChineseCalendar::handleComputeMonthStartWithLeap(int32_t eyear, int32_t month, bool isLeapMonth, UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -361,12 +374,6 @@ int64_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Ignore IS_LEAP_MONTH field if useMonth is false
|
||||
bool isLeapMonth = false;
|
||||
if (useMonth) {
|
||||
isLeapMonth = internalGet(UCAL_IS_LEAP_MONTH) != 0;
|
||||
}
|
||||
|
||||
int32_t newMonthYear = Grego::dayToYear(newMoon, status);
|
||||
|
||||
struct MonthInfo monthInfo = computeMonthInfo(setting, newMonthYear, newMoon, status);
|
||||
|
@ -1182,6 +1189,27 @@ ChineseCalendar::Setting ChineseCalendar::getSetting(UErrorCode&) const {
|
|||
};
|
||||
}
|
||||
|
||||
int32_t
|
||||
ChineseCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const
|
||||
{
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
if (field == UCAL_DATE) {
|
||||
LocalPointer<ChineseCalendar> cal(clone(), status);
|
||||
if(U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
cal->setLenient(true);
|
||||
cal->prepareGetActual(field,false,status);
|
||||
int32_t year = cal->get(UCAL_EXTENDED_YEAR, status);
|
||||
int32_t month = cal->get(UCAL_MONTH, status);
|
||||
bool leap = cal->get(UCAL_IS_LEAP_MONTH, status) != 0;
|
||||
return handleGetMonthLengthWithLeap(year, month, leap, status);
|
||||
}
|
||||
return Calendar::getActualMaximum(field, status);
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -194,6 +194,10 @@ class U_I18N_API ChineseCalendar : public Calendar {
|
|||
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
|
||||
virtual const UFieldResolutionTable* getFieldResolutionTable() const override;
|
||||
|
||||
private:
|
||||
int32_t handleGetMonthLengthWithLeap(int32_t extendedYear, int32_t month, bool isLeap, UErrorCode& status) const;
|
||||
int64_t handleComputeMonthStartWithLeap(int32_t eyear, int32_t month, bool isLeap, UErrorCode& status) const;
|
||||
|
||||
public:
|
||||
virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode &status) override;
|
||||
virtual void add(EDateFields field, int32_t amount, UErrorCode &status) override;
|
||||
|
@ -254,6 +258,8 @@ class U_I18N_API ChineseCalendar : public Calendar {
|
|||
*/
|
||||
virtual const char * getType() const override;
|
||||
|
||||
virtual int32_t getActualMaximum(UCalendarDateFields field, UErrorCode& status) const override;
|
||||
|
||||
struct Setting {
|
||||
int32_t epochYear;
|
||||
const TimeZone* zoneAstroCalc;
|
||||
|
|
|
@ -2433,7 +2433,7 @@ void CalendarRegressionTest::TestT5555()
|
|||
|
||||
// Should be set to Wednesday, February 24, 2010
|
||||
if (U_FAILURE(ec) || yy != 2010 || mm != UCAL_FEBRUARY || dd != 24 || ee != UCAL_WEDNESDAY) {
|
||||
errln("FAIL: got date %4d/%02d/%02d, expected 210/02/24: ", yy, mm + 1, dd);
|
||||
errln("FAIL: got date %4d/%02d/%02d (wd=%d), expected 2010/02/24: ", yy, mm + 1, dd, ee);
|
||||
}
|
||||
delete cal;
|
||||
}
|
||||
|
|
|
@ -183,6 +183,7 @@ void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name,
|
|||
TESTCASE_AUTO(TestCalendarRollOrdinalMonth);
|
||||
TESTCASE_AUTO(TestLimitsOrdinalMonth);
|
||||
TESTCASE_AUTO(TestActualLimitsOrdinalMonth);
|
||||
TESTCASE_AUTO(TestMaxActualLimitsWithoutGet23006);
|
||||
TESTCASE_AUTO(TestChineseCalendarMonthInSpecialYear);
|
||||
TESTCASE_AUTO(TestClearMonth);
|
||||
|
||||
|
@ -5354,6 +5355,30 @@ void CalendarTest::TestLimitsOrdinalMonth() {
|
|||
}
|
||||
}
|
||||
|
||||
void CalendarTest::TestMaxActualLimitsWithoutGet23006() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
GregorianCalendar gc(status);
|
||||
gc.set(2025, UCAL_AUGUST, 8);
|
||||
LocalPointer<Calendar> cal(Calendar::createInstance(Locale("en@calendar=chinese"), status), status);
|
||||
cal->setTime(gc.getTime(status), status);
|
||||
int32_t beforeCallingGet = cal->getActualMaximum(UCAL_DAY_OF_MONTH, status);
|
||||
cal->get(UCAL_DAY_OF_MONTH, status);
|
||||
int32_t afterCallingGet = cal->getActualMaximum(UCAL_DAY_OF_MONTH, status);
|
||||
assertEquals("getActualMaximum() should return same value before/after calling get()",
|
||||
beforeCallingGet, afterCallingGet);
|
||||
assertEquals("getActualMaximum() should return 29 before calling get()",
|
||||
29, beforeCallingGet);
|
||||
|
||||
gc.set(2026, UCAL_AUGUST, 8);
|
||||
cal->setTime(gc.getTime(status), status);
|
||||
beforeCallingGet = cal->getActualMaximum(UCAL_DAY_OF_MONTH, status);
|
||||
cal->get(UCAL_DAY_OF_MONTH, status);
|
||||
afterCallingGet = cal->getActualMaximum(UCAL_DAY_OF_MONTH, status);
|
||||
assertEquals("getActualMaximum() should return same value before/after calling get()",
|
||||
beforeCallingGet, afterCallingGet);
|
||||
assertEquals("getActualMaximum() should return 29 before calling get()",
|
||||
30, beforeCallingGet);
|
||||
}
|
||||
void CalendarTest::TestActualLimitsOrdinalMonth() {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
GregorianCalendar gc(status);
|
||||
|
|
|
@ -329,6 +329,7 @@ public: // package
|
|||
void TestCalendarRollOrdinalMonth();
|
||||
void TestLimitsOrdinalMonth();
|
||||
void TestActualLimitsOrdinalMonth();
|
||||
void TestMaxActualLimitsWithoutGet23006();
|
||||
void TestDangiOverflowIsLeapMonthBetween22507();
|
||||
|
||||
void TestFWWithISO8601();
|
||||
|
|
|
@ -6157,6 +6157,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
|
|||
* @stable ICU 2.0
|
||||
*/
|
||||
protected int handleGetMonthLength(int extendedYear, int month) {
|
||||
System.out.printf("handleGetMonthLength(ey=%d, m=%d)", extendedYear, month);
|
||||
return handleComputeMonthStart(extendedYear, month+1, true) -
|
||||
handleComputeMonthStart(extendedYear, month, true);
|
||||
}
|
||||
|
|
|
@ -456,7 +456,12 @@ public class ChineseCalendar extends Calendar {
|
|||
* @stable ICU 2.8
|
||||
*/
|
||||
protected int handleGetMonthLength(int extendedYear, int month) {
|
||||
int thisStart = handleComputeMonthStart(extendedYear, month, true) -
|
||||
int isLeapMonth = internalGet(IS_LEAP_MONTH);
|
||||
return handleGetMonthLengthWithLeap(extendedYear, month, isLeapMonth);
|
||||
}
|
||||
|
||||
private int handleGetMonthLengthWithLeap(int extendedYear, int month, int isLeap) {
|
||||
int thisStart = handleComputeMonthStartWithLeap(extendedYear, month, isLeap) -
|
||||
EPOCH_JULIAN_DAY + 1; // Julian day -> local days
|
||||
int nextStart = newMoonNear(thisStart + SYNODIC_GAP, true);
|
||||
return nextStart - thisStart;
|
||||
|
@ -971,6 +976,14 @@ public class ChineseCalendar extends Calendar {
|
|||
* @stable ICU 2.8
|
||||
*/
|
||||
protected int handleComputeMonthStart(int eyear, int month, boolean useMonth) {
|
||||
int isLeapMonth = 0;
|
||||
if (useMonth) {
|
||||
isLeapMonth = internalGet(IS_LEAP_MONTH);
|
||||
}
|
||||
return handleComputeMonthStartWithLeap(eyear, month, isLeapMonth);
|
||||
}
|
||||
|
||||
private int handleComputeMonthStartWithLeap(int eyear, int month, int isLeapMonth) {
|
||||
|
||||
// If the month is out of range, adjust it into range, and
|
||||
// modify the extended year value accordingly.
|
||||
|
@ -991,9 +1004,6 @@ public class ChineseCalendar extends Calendar {
|
|||
int saveOrdinalMonth = internalGet(ORDINAL_MONTH);
|
||||
int saveIsLeapMonth = internalGet(IS_LEAP_MONTH);
|
||||
|
||||
// Ignore IS_LEAP_MONTH field if useMonth is false
|
||||
int isLeapMonth = useMonth ? saveIsLeapMonth : 0;
|
||||
|
||||
computeGregorianFields(julianDay);
|
||||
|
||||
// This will modify the MONTH and IS_LEAP_MONTH fields (only)
|
||||
|
@ -1161,6 +1171,21 @@ public class ChineseCalendar extends Calendar {
|
|||
return internalGetMonth();
|
||||
}
|
||||
|
||||
public int getActualMaximum(int field) {
|
||||
if (field == DAY_OF_MONTH) {
|
||||
Calendar cal = (Calendar) clone();
|
||||
cal.setLenient(true);
|
||||
cal.prepareGetActual(field, false);
|
||||
int eyear = cal.get(EXTENDED_YEAR);
|
||||
int month = cal.get(MONTH);
|
||||
int isLeap = cal.get(IS_LEAP_MONTH);
|
||||
|
||||
return handleGetMonthLengthWithLeap(eyear, month, isLeap);
|
||||
}
|
||||
return super.getActualMaximum(field);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
private static CalendarFactory factory;
|
||||
public static CalendarFactory factory() {
|
||||
|
|
|
@ -2718,5 +2718,33 @@ public class CalendarRegressionTest extends CoreTestFmwk {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestMaxActualLimitsWithoutGet23006() {
|
||||
Calendar calendar = Calendar.getInstance(new Locale("zh_zh@calendar=chinese"));
|
||||
// set day equal to 8th August 2025 in Gregorian calendar
|
||||
// this is a leap month in Chinese calendar
|
||||
GregorianCalendar gc = new GregorianCalendar(TimeZone.GMT_ZONE);
|
||||
gc.clear();
|
||||
gc.set(2025, Calendar.AUGUST, 8);
|
||||
calendar.setTimeInMillis(gc.getTimeInMillis());
|
||||
int actualMaximumBeforeCallingGet = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
assertTrue("get(ERA)", calendar.get(Calendar.ERA) > 0); // calling get will cause to compute fields
|
||||
int actualMaximumAfterCallingGet = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
assertEquals("calling getActualMaximum before/after calling get should be the same",
|
||||
actualMaximumBeforeCallingGet, actualMaximumAfterCallingGet);
|
||||
assertEquals("calling getActualMaximum before should return 29",
|
||||
29, actualMaximumBeforeCallingGet);
|
||||
|
||||
gc.set(2026, Calendar.AUGUST, 8);
|
||||
calendar.setTimeInMillis(gc.getTimeInMillis());
|
||||
actualMaximumBeforeCallingGet = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
assertTrue("get(ERA)", calendar.get(Calendar.ERA) > 0); // calling get will cause to compute fields
|
||||
actualMaximumAfterCallingGet = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
assertEquals("calling getActualMaximum before/after calling get should be the same",
|
||||
actualMaximumBeforeCallingGet, actualMaximumAfterCallingGet);
|
||||
assertEquals("calling getActualMaximum before should return 30",
|
||||
30, actualMaximumBeforeCallingGet);
|
||||
|
||||
}
|
||||
}
|
||||
//eof
|
||||
|
|
Loading…
Add table
Reference in a new issue