Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICU-22991 Reduce Calendar object size #3327

Merged
merged 1 commit into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions icu4c/source/i18n/basictz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,13 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
|| (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
&& (date + MILLIS_PER_YEAR > nextTransitionTime)) {

int32_t year, month, dom, dow, doy, mid;
int32_t year, mid;
int8_t month, dom, dow;
UDate d;

// Get local wall time for the next transition time
Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
year, month, dom, dow, doy, mid, status);
year, month, dom, dow, mid, status);
if (U_FAILURE(status)) return;
int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
// Create DOW rule
Expand Down Expand Up @@ -193,7 +194,7 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,

// Get local wall time for the next transition time
Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
year, month, dom, dow, doy, mid, status);
year, month, dom, dow, mid, status);
if (U_FAILURE(status)) return;
weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
// Generate another DOW rule
Expand Down Expand Up @@ -225,7 +226,7 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,

// Generate another DOW rule
Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
year, month, dom, dow, doy, mid, status);
year, month, dom, dow, mid, status);
if (U_FAILURE(status)) return;
weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
Expand Down Expand Up @@ -486,8 +487,7 @@ BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial,
}
} else {
// Calculate the transition year
int32_t year, month, dom, dow, doy, mid;
Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid, status);
int32_t year = Grego::timeToYear(tzt.getTime(), status);
if (U_FAILURE(status)) {
return;
}
Expand Down
3 changes: 1 addition & 2 deletions icu4c/source/i18n/calendar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1524,14 +1524,13 @@ void Calendar::computeGregorianFields(int32_t julianDay, UErrorCode& ec) {
if (U_FAILURE(ec)) {
return;
}
int32_t gregorianDayOfWeekUnused;
if (uprv_add32_overflow(
julianDay, -kEpochStartAsJulianDay, &julianDay)) {
ec = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
Grego::dayToFields(julianDay, fGregorianYear, fGregorianMonth,
fGregorianDayOfMonth, gregorianDayOfWeekUnused,
fGregorianDayOfMonth,
fGregorianDayOfYear, ec);
}

Expand Down
8 changes: 2 additions & 6 deletions icu4c/source/i18n/chnsecal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,13 +369,9 @@ int64_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
isLeapMonth = internalGet(UCAL_IS_LEAP_MONTH) != 0;
}

int32_t unusedMonth;
int32_t unusedDayOfWeek;
int32_t unusedDayOfMonth;
int32_t unusedDayOfYear;
Grego::dayToFields(newMoon, gyear, unusedMonth, unusedDayOfWeek, unusedDayOfMonth, unusedDayOfYear, status);
int32_t newMonthYear = Grego::dayToYear(newMoon, status);

struct MonthInfo monthInfo = computeMonthInfo(setting, gyear, newMoon, status);
struct MonthInfo monthInfo = computeMonthInfo(setting, newMonthYear, newMoon, status);
if (U_FAILURE(status)) {
return 0;
}
Expand Down
5 changes: 3 additions & 2 deletions icu4c/source/i18n/erarules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,9 @@ void EraRules::initCurrentEra() {
localMillis += (rawOffset + dstOffset);
}

int year, month0, dom, dow, doy, mid;
Grego::timeToFields(localMillis, year, month0, dom, dow, doy, mid, ec);
int32_t year, mid;
int8_t month0, dom;
Grego::timeToFields(localMillis, year, month0, dom, mid, ec);
if (U_FAILURE(ec)) return;
int currentEncodedDate = encodeDate(year, month0 + 1 /* changes to 1-base */, dom);
int eraIdx = numEras - 1;
Expand Down
98 changes: 73 additions & 25 deletions icu4c/source/i18n/gregoimp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,57 +117,105 @@ int64_t Grego::fieldsToDay(int32_t year, int32_t month, int32_t dom) {
return julian - JULIAN_1970_CE; // JD => epoch day
}

void Grego::dayToFields(int32_t day, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow, int32_t& doy, UErrorCode& status) {

void Grego::dayToFields(int32_t day, int32_t& year, int8_t& month,
int8_t& dom, int8_t& dow, int16_t& doy, UErrorCode& status) {
year = dayToYear(day, doy, status); // one-based doy
if (U_FAILURE(status)) return;

// Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
if (uprv_add32_overflow(day, JULIAN_1970_CE - JULIAN_1_CE, &day)) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}

// Convert from the day number to the multiple radix
// representation. We use 400-year, 100-year, and 4-year cycles.
// For example, the 4-year cycle has 4 years + 1 leap day; giving
// 1461 == 365*4 + 1 days.
int32_t n400 = ClockMath::floorDivide(day, 146097, &doy); // 400-year cycle length
int32_t n100 = ClockMath::floorDivide(doy, 36524, &doy); // 100-year cycle length
int32_t n4 = ClockMath::floorDivide(doy, 1461, &doy); // 4-year cycle length
int32_t n1 = ClockMath::floorDivide(doy, 365, &doy);
year = 400*n400 + 100*n100 + 4*n4 + n1;
if (n100 == 4 || n1 == 4) {
doy = 365; // Dec 31 at end of 4- or 400-year cycle
} else {
++year;
}

UBool isLeap = isLeapYear(year);

// Gregorian day zero is a Monday.
dow = (day + 1) % 7;
dow += (dow < 0) ? (UCAL_SUNDAY + 7) : UCAL_SUNDAY;

// Common Julian/Gregorian calculation
int32_t correction = 0;
bool isLeap = isLeapYear(year);
int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
if (doy >= march1) {
if (doy > march1) {
correction = isLeap ? 1 : 2;
}
month = (12 * (doy + correction) + 6) / 367; // zero-based month
dom = doy - DAYS_BEFORE[month + (isLeap ? 12 : 0)] + 1; // one-based DOM
month = (12 * (doy - 1 + correction) + 6) / 367; // zero-based month
dom = doy - DAYS_BEFORE[month + (isLeap ? 12 : 0)]; // one-based DOM
}

int32_t Grego::dayToYear(int32_t day, UErrorCode& status) {
int16_t unusedDOY;
return dayToYear(day, unusedDOY, status);
}

int32_t Grego::dayToYear(int32_t day, int16_t& doy, UErrorCode& status) {
if (U_FAILURE(status)) return 0;
// Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
if (uprv_add32_overflow(day, JULIAN_1970_CE - JULIAN_1_CE, &day)) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}

// Convert from the day number to the multiple radix
// representation. We use 400-year, 100-year, and 4-year cycles.
// For example, the 4-year cycle has 4 years + 1 leap day; giving
// 1461 == 365*4 + 1 days.
int32_t doy32;
int32_t n400 = ClockMath::floorDivide(day, 146097, &doy32); // 400-year cycle length
int32_t n100 = ClockMath::floorDivide(doy32, 36524, &doy32); // 100-year cycle length
int32_t n4 = ClockMath::floorDivide(doy32, 1461, &doy32); // 4-year cycle length
int32_t n1 = ClockMath::floorDivide(doy32, 365, &doy32);
int32_t year = 400*n400 + 100*n100 + 4*n4 + n1;
if (n100 == 4 || n1 == 4) {
doy = 365; // Dec 31 at end of 4- or 400-year cycle
} else {
doy = doy32;
++year;
}
doy++; // one-based doy
return year;
}

void Grego::dayToFields(int32_t day, int32_t& year, int8_t& month,
int8_t& dom, int8_t& dow, UErrorCode& status) {
int16_t unusedDOY;
dayToFields(day, year, month, dom, dow, unusedDOY, status);
}

void Grego::dayToFields(int32_t day, int32_t& year, int8_t& month,
int8_t& dom, int16_t& doy, UErrorCode& status) {
int8_t unusedDOW;
dayToFields(day, year, month, dom, unusedDOW, doy, status);
}

void Grego::timeToFields(UDate time, int32_t& year, int8_t& month,
int8_t& dom, int32_t& mid, UErrorCode& status) {
int8_t unusedDOW;
timeToFields(time, year, month, dom, unusedDOW, mid, status);
}

void Grego::timeToFields(UDate time, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid, UErrorCode& status) {
void Grego::timeToFields(UDate time, int32_t& year, int8_t& month,
int8_t& dom, int8_t& dow, int32_t& mid, UErrorCode& status) {
int16_t unusedDOY;
timeToFields(time, year, month, dom, dow, unusedDOY, mid, status);
}

void Grego::timeToFields(UDate time, int32_t& year, int8_t& month,
int8_t& dom, int8_t& dow, int16_t& doy, int32_t& mid, UErrorCode& status) {
if (U_FAILURE(status)) return;
double millisInDay;
double day = ClockMath::floorDivide(static_cast<double>(time), static_cast<double>(U_MILLIS_PER_DAY), &millisInDay);
mid = static_cast<int32_t>(millisInDay);
dayToFields(day, year, month, dom, dow, doy, status);
}

int32_t Grego::timeToYear(UDate time, UErrorCode& status) {
if (U_FAILURE(status)) return 0;
double millisInDay;
int32_t day = ClockMath::floorDivide(static_cast<double>(time), static_cast<double>(U_MILLIS_PER_DAY), &millisInDay);
return Grego::dayToYear(day, status);
}

int32_t Grego::dayOfWeek(int32_t day) {
int32_t dow;
ClockMath::floorDivide(day + int{UCAL_THURSDAY}, 7, &dow);
Expand Down
82 changes: 70 additions & 12 deletions icu4c/source/i18n/gregoimp.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,21 @@ class Grego {
* @param doy output parameter to receive day-of-year (1-based)
* @param status error code.
*/
static void dayToFields(int32_t day, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow, int32_t& doy, UErrorCode& status);
static void dayToFields(int32_t day, int32_t& year, int8_t& month,
int8_t& dom, int8_t& dow, int16_t& doy, UErrorCode& status);

/**
* Convert a 1970-epoch day number to proleptic Gregorian year,
* month, day-of-month, and day-of-week.
* @param day 1970-epoch day
* @param year output parameter to receive year
* @param month output parameter to receive month (0-based, 0==Jan)
* @param dom output parameter to receive day-of-month (1-based)
* @param doy output parameter to receive day-of-year (1-based)
* @param status error code.
*/
static void dayToFields(int32_t day, int32_t& year, int8_t& month,
int8_t& dom, int16_t& doy, UErrorCode& status);

/**
* Convert a 1970-epoch day number to proleptic Gregorian year,
Expand All @@ -223,8 +236,24 @@ class Grego {
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
* @param status error code.
*/
static inline void dayToFields(int32_t day, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow, UErrorCode& status);
static void dayToFields(int32_t day, int32_t& year, int8_t& month,
int8_t& dom, int8_t& dow, UErrorCode& status);

/**
* Convert a 1970-epoch day number to proleptic Gregorian year.
* @param day 1970-epoch day
* @param status error code.
* @return year.
*/
static int32_t dayToYear(int32_t day, UErrorCode& status);
/**
* Convert a 1970-epoch day number to proleptic Gregorian year.
* @param day 1970-epoch day
* @param doy output parameter to receive day-of-year (1-based)
* @param status error code.
* @return year.
*/
static int32_t dayToYear(int32_t day, int16_t& doy, UErrorCode& status);

/**
* Convert a 1970-epoch milliseconds to proleptic Gregorian year,
Expand All @@ -238,8 +267,43 @@ class Grego {
* @param mid output parameter to receive millis-in-day
* @param status error code.
*/
static void timeToFields(UDate time, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid, UErrorCode& status);
static void timeToFields(UDate time, int32_t& year, int8_t& month,
int8_t& dom, int8_t& dow, int16_t& doy, int32_t& mid, UErrorCode& status);

/**
* Convert a 1970-epoch milliseconds to proleptic Gregorian year,
* month, day-of-month, and day-of-week, day of year and millis-in-day.
* @param time 1970-epoch milliseconds
* @param year output parameter to receive year
* @param month output parameter to receive month (0-based, 0==Jan)
* @param dom output parameter to receive day-of-month (1-based)
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
* @param mid output parameter to receive millis-in-day
* @param status error code.
*/
static void timeToFields(UDate time, int32_t& year, int8_t& month,
int8_t& dom, int8_t& dow, int32_t& mid, UErrorCode& status);

/**
* Convert a 1970-epoch milliseconds to proleptic Gregorian year,
* month, day-of-month, and day-of-week, day of year and millis-in-day.
* @param time 1970-epoch milliseconds
* @param year output parameter to receive year
* @param month output parameter to receive month (0-based, 0==Jan)
* @param dom output parameter to receive day-of-month (1-based)
* @param mid output parameter to receive millis-in-day
* @param status error code.
*/
static void timeToFields(UDate time, int32_t& year, int8_t& month,
int8_t& dom, int32_t& mid, UErrorCode& status);

/**
* Convert a 1970-epoch milliseconds to proleptic Gregorian year.
* @param time 1970-epoch milliseconds
* @param status error code.
* @return year.
*/
static int32_t timeToYear(UDate time, UErrorCode& status);

/**
* Return the day of week on the 1970-epoch day
Expand Down Expand Up @@ -305,12 +369,6 @@ Grego::previousMonthLength(int y, int m) {
return (m > 0) ? monthLength(y, m-1) : 31;
}

inline void Grego::dayToFields(int32_t day, int32_t& year, int32_t& month,
int32_t& dom, int32_t& dow, UErrorCode& status) {
int32_t doy_unused;
dayToFields(day,year,month,dom,dow,doy_unused, status);
}

inline double Grego::julianDayToMillis(int32_t julian)
{
return (static_cast<double>(julian) - kEpochStartAsJulianDay) * kOneDay;
Expand Down
17 changes: 2 additions & 15 deletions icu4c/source/i18n/indiancal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,6 @@ static double gregorianToJD(int32_t year, int32_t month, int32_t date) {
return Grego::fieldsToDay(year, month, date) + kEpochStartAsJulianDay - 0.5;
}

/*
* Returns the Gregorian Date corresponding to a given Julian Day
* Month is 0 based.
* @param jd The Julian Day
*/
static int32_t* jdToGregorian(double jd, int32_t gregorianDate[3], UErrorCode& status) {
int32_t gdow;
Grego::dayToFields(jd - kEpochStartAsJulianDay,
gregorianDate[0], gregorianDate[1], gregorianDate[2], gdow, status);
return gregorianDate;
}


//-------------------------------------------------------------------------
// Functions for converting from field values to milliseconds....
Expand Down Expand Up @@ -265,10 +253,9 @@ int32_t IndianCalendar::handleGetExtendedYear(UErrorCode& status) {
void IndianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) {
double jdAtStartOfGregYear;
int32_t leapMonth, IndianYear, yday, IndianMonth, IndianDayOfMonth, mday;
int32_t gregorianYear; // Stores gregorian date corresponding to Julian day;
int32_t gd[3];
// Stores gregorian date corresponding to Julian day;
int32_t gregorianYear = Grego::dayToYear(julianDay - kEpochStartAsJulianDay, status);

gregorianYear = jdToGregorian(julianDay, gd, status)[0]; // Gregorian date for Julian day
if (U_FAILURE(status)) return;
IndianYear = gregorianYear - INDIAN_ERA_START; // Year in Saka era
jdAtStartOfGregYear = gregorianToJD(gregorianYear, 0, 1); // JD at start of Gregorian year
Expand Down
3 changes: 1 addition & 2 deletions icu4c/source/i18n/olsontz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,9 +568,8 @@ UBool OlsonTimeZone::useDaylightTime() const {
return finalZone->useDaylightTime();
}

int32_t year, month, dom, dow, doy, mid;
UErrorCode status = U_ZERO_ERROR;
Grego::timeToFields(current, year, month, dom, dow, doy, mid, status);
int32_t year = Grego::timeToYear(current, status);
U_ASSERT(U_SUCCESS(status));
if (U_FAILURE(status)) return false; // If error, just return false.

Expand Down
3 changes: 2 additions & 1 deletion icu4c/source/i18n/simpletz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,8 @@ SimpleTimeZone::getOffsetFromLocal(UDate date, UTimeZoneLocalOption nonExistingT
}

rawOffsetGMT = getRawOffset();
int32_t year, month, dom, dow, millis;
int32_t year, millis;
int8_t month, dom, dow;
double dday = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);
if (dday > INT32_MAX || dday < INT32_MIN) {
status = U_ILLEGAL_ARGUMENT_ERROR;
Expand Down
3 changes: 2 additions & 1 deletion icu4c/source/i18n/timezone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,8 @@ void TimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
// (with 7 args) twice when local == true and DST is
// detected in the initial call.
for (int32_t pass=0; ; ++pass) {
int32_t year, month, dom, dow, millis;
int32_t year, millis;
int8_t month, dom, dow;
double day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);

// out of the range
Expand Down
Loading
Loading