Skip to content

Commit dcca6c1

Browse files
committed
ICU-23167 Change Chinese and Dangi calendar epoch to 1AD
See #3610
1 parent 793cecd commit dcca6c1

File tree

14 files changed

+409
-422
lines changed

14 files changed

+409
-422
lines changed

icu4c/source/i18n/chnsecal.cpp

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,18 @@ static icu::CalendarCache *gNewYearCache = nullptr;
6060
static icu::TimeZone *gAstronomerTimeZone = nullptr;
6161
static icu::UInitOnce gAstronomerTimeZoneInitOnce {};
6262

63+
/*
64+
* The start year of the Chinese calendar, 1CE.
65+
*/
66+
static const int32_t CHINESE_EPOCH_YEAR = 1; // Gregorian year
67+
//
6368
/**
64-
* The start year of the Chinese calendar, the 61st year of the reign
65-
* of Huang Di. Some sources use the first year of his reign,
66-
* resulting in EXTENDED_YEAR values 60 years greater and ERA (cycle)
67-
* values one greater.
69+
* The start year of the Chinese calendar for cycle calculation,
70+
* the 61st year of the reign of Huang Di.
71+
* Some sources use the first year of his reign,
72+
* resulting in ERA (cycle) values one greater.
6873
*/
69-
static const int32_t CHINESE_EPOCH_YEAR = -2636; // Gregorian year
74+
static const int32_t CYCLE_EPOCH = -2636; // Gregorian year
7075

7176
/**
7277
* The offset from GMT in milliseconds at which we perform astronomical
@@ -226,16 +231,12 @@ int32_t ChineseCalendar::handleGetExtendedYear(UErrorCode& status) {
226231
// adjust to the instance specific epoch
227232
int32_t cycle = internalGet(UCAL_ERA, 1);
228233
year = internalGet(UCAL_YEAR, 1);
229-
const Setting setting = getSetting(status);
230-
if (U_FAILURE(status)) {
231-
return 0;
232-
}
233234
// Handle int32 overflow calculation for
234-
// year = year + (cycle-1) * 60 -(fEpochYear - CHINESE_EPOCH_YEAR)
235+
// year = year + (cycle-1) * 60 + CYCLE_EPOCH - CHINESE_EPOCH_YEAR
235236
if (uprv_add32_overflow(cycle, -1, &cycle) || // 0-based cycle
236237
uprv_mul32_overflow(cycle, 60, &cycle) ||
237238
uprv_add32_overflow(year, cycle, &year) ||
238-
uprv_add32_overflow(year, -(setting.epochYear-CHINESE_EPOCH_YEAR),
239+
uprv_add32_overflow(year, CYCLE_EPOCH-CHINESE_EPOCH_YEAR,
239240
&year)) {
240241
status = U_ILLEGAL_ARGUMENT_ERROR;
241242
return 0;
@@ -362,12 +363,7 @@ int64_t ChineseCalendar::handleComputeMonthStartWithLeap(int32_t eyear, int32_t
362363
if (U_FAILURE(status)) {
363364
return 0;
364365
}
365-
int32_t gyear;
366-
if (uprv_add32_overflow(eyear, setting.epochYear - 1, &gyear)) {
367-
status = U_ILLEGAL_ARGUMENT_ERROR;
368-
return 0;
369-
}
370-
366+
int32_t gyear = eyear;
371367
int32_t theNewYear = newYear(setting, gyear, status);
372368
int32_t newMoon = newMoonNear(setting.zoneAstroCalc, theNewYear + month * 29, true, status);
373369
if (U_FAILURE(status)) {
@@ -791,10 +787,20 @@ struct MonthInfo computeMonthInfo(
791787
return output;
792788
}
793789
if (days < solsticeAfter) {
794-
solsticeBefore = winterSolstice(setting, gyear - 1, status);
790+
int32_t gprevious_year;
791+
if (uprv_add32_overflow(gyear, -1, &gprevious_year)) {
792+
status = U_ILLEGAL_ARGUMENT_ERROR;
793+
return output;
794+
}
795+
solsticeBefore = winterSolstice(setting, gprevious_year, status);
795796
} else {
796797
solsticeBefore = solsticeAfter;
797-
solsticeAfter = winterSolstice(setting, gyear + 1, status);
798+
int32_t gnext_year;
799+
if (uprv_add32_overflow(gyear, 1, &gnext_year)) {
800+
status = U_ILLEGAL_ARGUMENT_ERROR;
801+
return output;
802+
}
803+
solsticeAfter = winterSolstice(setting, gnext_year, status);
798804
}
799805
if (!(solsticeBefore <= days && days < solsticeAfter)) {
800806
status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -824,7 +830,12 @@ struct MonthInfo computeMonthInfo(
824830
return output;
825831
}
826832
if (days < theNewYear) {
827-
theNewYear = newYear(setting, gyear-1, status);
833+
int32_t gprevious_year;
834+
if (uprv_add32_overflow(gyear, -1, &gprevious_year)) {
835+
status = U_ILLEGAL_ARGUMENT_ERROR;
836+
return output;
837+
}
838+
theNewYear = newYear(setting, gprevious_year, status);
828839
if (U_FAILURE(status)) {
829840
return output;
830841
}
@@ -897,12 +908,21 @@ void ChineseCalendar::handleComputeFields(int32_t julianDay, UErrorCode & status
897908
hasLeapMonthBetweenWinterSolstices = monthInfo.hasLeapMonthBetweenWinterSolstices;
898909

899910
// Extended year and cycle year is based on the epoch year
900-
int32_t eyear = gyear - setting.epochYear;
901-
int32_t cycle_year = gyear - CHINESE_EPOCH_YEAR;
911+
int32_t eyear;
912+
int32_t cycle_year;
913+
if (uprv_add32_overflow(gyear, -CHINESE_EPOCH_YEAR, &eyear) ||
914+
uprv_add32_overflow(gyear, -CYCLE_EPOCH, &cycle_year)) {
915+
status = U_ILLEGAL_ARGUMENT_ERROR;
916+
return;
917+
}
902918
if (monthInfo.month < 11 ||
903919
gmonth >= UCAL_JULY) {
904-
eyear++;
905-
cycle_year++;
920+
// forward to next year
921+
if (uprv_add32_overflow(eyear, 1, &eyear) ||
922+
uprv_add32_overflow(cycle_year, 1, &cycle_year)) {
923+
status = U_ILLEGAL_ARGUMENT_ERROR;
924+
return;
925+
}
906926
}
907927
int32_t dayOfMonth = days - monthInfo.thisMoon + 1;
908928

@@ -919,7 +939,12 @@ void ChineseCalendar::handleComputeFields(int32_t julianDay, UErrorCode & status
919939
return;
920940
}
921941
if (days < theNewYear) {
922-
theNewYear = newYear(setting, gyear-1, status);
942+
int32_t gprevious_year;
943+
if (uprv_add32_overflow(gyear, -1, &gprevious_year)) {
944+
status = U_ILLEGAL_ARGUMENT_ERROR;
945+
return;
946+
}
947+
theNewYear = newYear(setting, gprevious_year, status);
923948
}
924949
if (U_FAILURE(status)) {
925950
return;
@@ -982,7 +1007,12 @@ int32_t newYear(const icu::ChineseCalendar::Setting& setting,
9821007

9831008
if (cacheValue == 0) {
9841009

985-
int32_t solsticeBefore= winterSolstice(setting, gyear - 1, status);
1010+
int32_t gprevious_year;
1011+
if (uprv_add32_overflow(gyear, -1, &gprevious_year)) {
1012+
status = U_ILLEGAL_ARGUMENT_ERROR;
1013+
return 0;
1014+
}
1015+
int32_t solsticeBefore= winterSolstice(setting, gprevious_year, status);
9861016
int32_t solsticeAfter = winterSolstice(setting, gyear, status);
9871017
int32_t newMoon1 = newMoonNear(timeZone, solsticeBefore + 1, true, status);
9881018
int32_t newMoon2 = newMoonNear(timeZone, newMoon1 + SYNODIC_GAP, true, status);
@@ -1074,10 +1104,6 @@ void ChineseCalendar::offsetMonth(int32_t newMoon, int32_t dayOfMonth, int32_t d
10741104
}
10751105
}
10761106

1077-
int32_t ChineseCalendar::getRelatedYearDifference() const {
1078-
return CHINESE_EPOCH_YEAR - 1;
1079-
}
1080-
10811107
IMPL_SYSTEM_DEFAULT_CENTURY(ChineseCalendar, "@calendar=chinese")
10821108

10831109
bool
@@ -1172,7 +1198,6 @@ int32_t ChineseCalendar::internalGetMonth(int32_t defaultValue, UErrorCode& stat
11721198

11731199
ChineseCalendar::Setting ChineseCalendar::getSetting(UErrorCode&) const {
11741200
return {
1175-
CHINESE_EPOCH_YEAR,
11761201
getAstronomerTimeZone(),
11771202
&gWinterSolsticeCache,
11781203
&gNewYearCache

icu4c/source/i18n/chnsecal.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,6 @@ class U_I18N_API ChineseCalendar : public Calendar {
204204
virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode &status) override;
205205
virtual void roll(EDateFields field, int32_t amount, UErrorCode &status) override;
206206

207-
protected:
208-
/**
209-
* @internal
210-
*/
211-
int32_t getRelatedYearDifference() const override;
212-
213207
//----------------------------------------------------------------------
214208
// Internal methods & astronomical calculations
215209
//----------------------------------------------------------------------
@@ -253,7 +247,6 @@ class U_I18N_API ChineseCalendar : public Calendar {
253247
virtual int32_t getActualMaximum(UCalendarDateFields field, UErrorCode& status) const override;
254248

255249
struct Setting {
256-
int32_t epochYear;
257250
const TimeZone* zoneAstroCalc;
258251
CalendarCache** winterSolsticeCache;
259252
CalendarCache** newYearCache;

icu4c/source/i18n/dangical.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,6 @@ static icu::CalendarCache *gNewYearCache = nullptr;
3232
static icu::TimeZone *gAstronomerTimeZone = nullptr;
3333
static icu::UInitOnce gAstronomerTimeZoneInitOnce {};
3434

35-
/**
36-
* The start year of the Korean traditional calendar (Dan-gi) is the inaugural
37-
* year of Dan-gun (BC 2333).
38-
*/
39-
static const int32_t DANGI_EPOCH_YEAR = -2332; // Gregorian year
40-
4135
U_CDECL_BEGIN
4236
static UBool calendar_dangi_cleanup() {
4337
if (gWinterSolsticeCache) {
@@ -158,12 +152,8 @@ const TimeZone* getAstronomerTimeZone(UErrorCode &status) {
158152
return gAstronomerTimeZone;
159153
}
160154

161-
int32_t DangiCalendar::getRelatedYearDifference() const {
162-
return DANGI_EPOCH_YEAR - 1;
163-
}
164-
165155
ChineseCalendar::Setting DangiCalendar::getSetting(UErrorCode& status) const {
166-
return { DANGI_EPOCH_YEAR,
156+
return {
167157
getAstronomerTimeZone(status),
168158
&gWinterSolsticeCache, &gNewYearCache
169159
};

icu4c/source/i18n/dangical.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,6 @@ class DangiCalendar : public ChineseCalendar {
103103
protected:
104104
virtual Setting getSetting(UErrorCode& status) const override;
105105

106-
/*
107-
* @internal
108-
*/
109-
int32_t getRelatedYearDifference() const override;
110-
111106
private:
112107

113108
DangiCalendar(); // default constructor not implemented

icu4c/source/i18n/gregoimp.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ const int8_t Grego::MONTH_LENGTH[24] =
106106

107107
int64_t Grego::fieldsToDay(int32_t year, int32_t month, int32_t dom) {
108108

109-
int64_t y = year - 1;
109+
int64_t y = year;
110+
y--;
110111

111112
int64_t julian = 365LL * y +
112113
ClockMath::floorDivideInt64(y, 4LL) + (JULIAN_1_CE - 3) + // Julian cal

0 commit comments

Comments
 (0)