Skip to content

Commit

Permalink
ICU-22736 Fix bug
Browse files Browse the repository at this point in the history
  • Loading branch information
FrankYFTang committed Nov 27, 2024
1 parent 6d1bfa0 commit 31c345b
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 23 deletions.
4 changes: 0 additions & 4 deletions icu4c/source/i18n/calendar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1639,14 +1639,11 @@ void Calendar::computeWeekFields(UErrorCode &ec) {
// to handle the case in which we are the first week of the
// next year.

printf("x1\n");
int32_t prevDoy = dayOfYear + handleGetYearLength(eyear - 1);
woy = weekNumber(prevDoy, dayOfWeek);
yearOfWeekOfYear--;
} else {
printf("x2\n");
int32_t lastDoy = handleGetYearLength(eyear);
printf("Last doy %d is %d\n", eyear, lastDoy);
// Fast check: For it to be week 1 of the next year, the DOY
// must be on or after L-5, where L is yearLength(), then it
// cannot possibly be week 1 of the next year:
Expand Down Expand Up @@ -2949,7 +2946,6 @@ void Calendar::validateField(UCalendarDateFields field, UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
printf("x3\n");
validateField(field, 1, handleGetYearLength(y), status);
break;
case UCAL_DAY_OF_WEEK_IN_MONTH:
Expand Down
4 changes: 1 addition & 3 deletions icu4c/source/i18n/persncal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,15 +200,13 @@ int32_t PersianCalendar::handleGetMonthLength(int32_t extendedYear, int32_t mont
extendedYear += ClockMath::floorDivide(month, 12, &month);
}

printf("call isLeapYear from handleGetMonthLength\n");
return isLeapYear(extendedYear) ? kPersianLeapMonthLength[month] : kPersianMonthLength[month];
}

/**
* Return the number of days in the given Persian year
*/
int32_t PersianCalendar::handleGetYearLength(int32_t extendedYear) const {
printf("call isLeapYear from handleGetYearLength\n");
return isLeapYear(extendedYear) ? 366 : 365;
}

Expand Down Expand Up @@ -277,9 +275,9 @@ int32_t PersianCalendar::handleGetExtendedYear(UErrorCode& status) {
* method is called.
*/
void PersianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) {
printf("handleComputeFields jd=%d\n", julianDay);
int64_t daysSinceEpoch = julianDay;
daysSinceEpoch -= PERSIAN_EPOCH;

int64_t year = ClockMath::floorDivideInt64(
33LL * daysSinceEpoch + 3LL, 12053LL) + 1LL;
if (year > INT32_MAX || year < INT32_MIN) {
Expand Down
58 changes: 43 additions & 15 deletions icu4c/source/test/intltest/incaltst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ void IntlCalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &n
TESTCASE_AUTO(TestJapanese3860);
TESTCASE_AUTO(TestForceGannenNumbering);
TESTCASE_AUTO(TestPersian);
TESTCASE_AUTO(TestPersianData);
TESTCASE_AUTO(TestPersianJulianDayToYMD);
TESTCASE_AUTO(TestPersianYMDToJulianDay);
TESTCASE_AUTO(TestPersianJan1ToGregorian);
TESTCASE_AUTO(TestGregorianToPersian);
TESTCASE_AUTO(TestPersianFormat);
TESTCASE_AUTO(TestTaiwan);
TESTCASE_AUTO(TestConsistencyGregorian);
Expand Down Expand Up @@ -896,17 +899,13 @@ void IntlCalendarTest::TestPersian() {
delete cal;
delete grego;
}
void IntlCalendarTest::TestPersianData() {
UErrorCode status = U_ZERO_ERROR;
std::unique_ptr<Calendar> gcal(Calendar::createInstance(TimeZone::createTimeZone("Asia/Tehran"), "en", status));
std::unique_ptr<Calendar> cal(Calendar::createInstance(TimeZone::createTimeZone("Asia/Tehran"), "fa_IR@calendar=persian", status));

struct TestCase1 {
static struct PersianTestCase1 {
int32_t rd;
int32_t year;
int32_t month;
int32_t day;
} testCases1[]{
} persianTestCases1[]{
{656786, 1178, 1, 1},
{664224, 1198, 5, 10},
{671401, 1218, 1, 7},
Expand Down Expand Up @@ -934,9 +933,14 @@ void IntlCalendarTest::TestPersianData() {
{1317874, 2988, 1, 1},
{1317875, 2988, 1, 2},
};
for (const auto &testCase : testCases1) {

void IntlCalendarTest::TestPersianJulianDayToYMD() {
UErrorCode status = U_ZERO_ERROR;
std::unique_ptr<Calendar> cal(Calendar::createInstance(TimeZone::createTimeZone("Asia/Tehran"), "fa_IR@calendar=persian", status));

for (const auto &testCase : persianTestCases1) {
status = U_ZERO_ERROR;
int32_t jday = testCase.rd + 1721424;
int32_t jday = testCase.rd + 1721425;
cal->clear();
cal->set(UCAL_JULIAN_DAY, jday);
int32_t actualYear = cal->get(UCAL_YEAR, status);
Expand All @@ -947,28 +951,37 @@ void IntlCalendarTest::TestPersianData() {
testCase.year + "/" + testCase.month + "/" + testCase.day + ") " +
"actual Persian(" + actualYear + "/" + actualMonth + "/" + actualDay + ")");
}
}
}

void IntlCalendarTest::TestPersianYMDToJulianDay() {
UErrorCode status = U_ZERO_ERROR;
std::unique_ptr<Calendar> cal(Calendar::createInstance(TimeZone::createTimeZone("Asia/Tehran"), "fa_IR@calendar=persian", status));

for (const auto &testCase : persianTestCases1) {
status = U_ZERO_ERROR;
cal->clear();
cal->set(UCAL_YEAR, testCase.year);
cal->set(UCAL_MONTH, testCase.month-1);
cal->set(UCAL_DAY_OF_MONTH, testCase.day-1);
cal->set(UCAL_DAY_OF_MONTH, testCase.day);
int32_t actualJday = cal->get(UCAL_JULIAN_DAY, status);
int32_t actualRD = actualJday - 1721424;
int32_t actualRD = actualJday - 1721425;
if (actualRD != testCase.rd) {
errln(UnicodeString("Persian(") + testCase.year + "/" + testCase.month + "/" + testCase.day + ") => "+
"expect rd " + testCase.rd + " but actual jd: " + actualJday + " = rd " + actualRD);
}
}
}

// From https://calendar.ut.ac.ir/Fa/News/Data/Doc/KabiseShamsi1206-1498-new.pdf
// Plain text version at https://github.com/roozbehp/persiancalendar/blob/main/kabise.txt
struct TestCase2 {
static struct PersianTestCase2 {
int32_t pYear;
bool pLeap;
int32_t year;
int32_t month;
int32_t day;
} testCases2[]{
} persianTestCases2[]{
{1206, false, 1827, 3, 22},
{1207, false, 1828, 3, 21},
{1208, false, 1829, 3, 21},
Expand Down Expand Up @@ -1263,7 +1276,14 @@ void IntlCalendarTest::TestPersianData() {
{1497, false, 2118, 3, 21},
{1498, true, 2119, 3, 21},
};
for (const auto &testCase : testCases2) {

void IntlCalendarTest::TestPersianJan1ToGregorian() {
UErrorCode status = U_ZERO_ERROR;
std::unique_ptr<Calendar> gcal(Calendar::createInstance(TimeZone::createTimeZone("Asia/Tehran"), "en", status));
std::unique_ptr<Calendar> cal(Calendar::createInstance(TimeZone::createTimeZone("Asia/Tehran"), "fa_IR@calendar=persian", status));

for (const auto &testCase : persianTestCases2) {
status = U_ZERO_ERROR;
cal->clear();
cal->set(UCAL_YEAR, testCase.pYear);
cal->set(UCAL_MONTH, 0);
Expand All @@ -1277,7 +1297,16 @@ void IntlCalendarTest::TestPersianData() {
"expect Gregorian(" + testCase.year + "/" + testCase.month + "/" + testCase.day + ") " +
"actual Gregorian(" + actualYear + "/" + actualMonth + "/" + actualDay + ")");
}
}
}

void IntlCalendarTest::TestGregorianToPersian() {
UErrorCode status = U_ZERO_ERROR;
std::unique_ptr<Calendar> gcal(Calendar::createInstance(TimeZone::createTimeZone("Asia/Tehran"), "en", status));
std::unique_ptr<Calendar> cal(Calendar::createInstance(TimeZone::createTimeZone("Asia/Tehran"), "fa_IR@calendar=persian", status));

for (const auto &testCase : persianTestCases2) {
status = U_ZERO_ERROR;
gcal->clear();
gcal->set(UCAL_YEAR, testCase.year);
gcal->set(UCAL_MONTH, testCase.month-1);
Expand All @@ -1294,7 +1323,6 @@ void IntlCalendarTest::TestPersianData() {
}
}


void IntlCalendarTest::TestPersianFormat() {
UErrorCode status = U_ZERO_ERROR;
SimpleDateFormat fmt(UnicodeString("MMMM d, yyyy G"), Locale(" en_US@calendar=persian"), status);
Expand Down
5 changes: 4 additions & 1 deletion icu4c/source/test/intltest/incaltst.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ class IntlCalendarTest: public CalendarTimeZoneTest {
void TestForceGannenNumbering();

void TestPersian();
void TestPersianData();
void TestPersianJulianDayToYMD();
void TestPersianYMDToJulianDay();
void TestPersianJan1ToGregorian();
void TestGregorianToPersian();
void TestPersianFormat();

void TestConsistencyGregorian();
Expand Down

0 comments on commit 31c345b

Please sign in to comment.