diff --git a/icu4c/source/i18n/chnsecal.cpp b/icu4c/source/i18n/chnsecal.cpp index 8257bbafb677..fdb8915105ab 100644 --- a/icu4c/source/i18n/chnsecal.cpp +++ b/icu4c/source/i18n/chnsecal.cpp @@ -339,12 +339,10 @@ int64_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U // If the month is out of range, adjust it into range, and // modify the extended year value accordingly. if (month < 0 || month > 11) { - double m = month; - if (uprv_add32_overflow(eyear, ClockMath::floorDivide(m, 12.0, &m), &eyear)) { + if (uprv_add32_overflow(eyear, ClockMath::floorDivide(month, 12, &month), &eyear)) { status = U_ILLEGAL_ARGUMENT_ERROR; return 0; } - month = static_cast(m); } const Setting setting = getSetting(status); diff --git a/icu4c/source/i18n/gregoimp.cpp b/icu4c/source/i18n/gregoimp.cpp index 161897b027a2..25df0fc38a12 100644 --- a/icu4c/source/i18n/gregoimp.cpp +++ b/icu4c/source/i18n/gregoimp.cpp @@ -57,11 +57,11 @@ double ClockMath::floorDivide(double numerator, int32_t denominator, } double ClockMath::floorDivide(double dividend, double divisor, - double* remainder) { + int32_t* remainder) { // Only designed to work for positive divisors U_ASSERT(divisor > 0); double quotient = floorDivide(dividend, divisor); - double r = dividend - (quotient * divisor); + int32_t r = dividend - (quotient * divisor); // N.B. For certain large dividends, on certain platforms, there // is a bug such that the quotient is off by one. If you doubt // this to be true, set a breakpoint below and run cintltst. @@ -203,16 +203,21 @@ void Grego::timeToFields(UDate time, int32_t& year, int8_t& month, 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(time), static_cast(U_MILLIS_PER_DAY), &millisInDay); - mid = static_cast(millisInDay); + double day = ClockMath::floorDivide(time, U_MILLIS_PER_DAY, &mid); + if (day > INT32_MAX || day < INT32_MIN) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } 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(time), static_cast(U_MILLIS_PER_DAY), &millisInDay); + double day = ClockMath::floorDivide(time, U_MILLIS_PER_DAY, nullptr); + if (day > INT32_MAX || day < INT32_MIN) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } return Grego::dayToYear(day, status); } diff --git a/icu4c/source/i18n/gregoimp.h b/icu4c/source/i18n/gregoimp.h index 39881c0eefbe..bc76a5a1f90f 100644 --- a/icu4c/source/i18n/gregoimp.h +++ b/icu4c/source/i18n/gregoimp.h @@ -110,7 +110,7 @@ class ClockMath { * Calling with a divisor <= 0 is disallowed. */ static double floorDivide(double dividend, double divisor, - double* remainder); + int32_t* remainder); }; // Useful millisecond constants diff --git a/icu4c/source/i18n/olsontz.cpp b/icu4c/source/i18n/olsontz.cpp index c795e9a38fee..7826d47a7d06 100644 --- a/icu4c/source/i18n/olsontz.cpp +++ b/icu4c/source/i18n/olsontz.cpp @@ -436,11 +436,11 @@ int32_t OlsonTimeZone::getRawOffset() const { #if defined U_DEBUG_TZ void printTime(double ms) { - int32_t year, month, dom, dow; - double millis=0; - double days = ClockMath::floorDivide(((double)ms), (double)U_MILLIS_PER_DAY, millis); - - Grego::dayToFields(days, year, month, dom, dow); + int32_t year; + int8_t month, dom, dow; + int32_t millis=0; + UErrorCode status = U_ZERO_ERROR; + Grego::timeToFields(ms, year, month, dom, dow, millis, status); U_DEBUG_TZ_MSG((" getHistoricalOffset: time %.1f (%04d.%02d.%02d+%.1fh)\n", ms, year, month+1, dom, (millis/kOneHour))); } diff --git a/icu4c/source/i18n/simpletz.cpp b/icu4c/source/i18n/simpletz.cpp index ec80db440938..3f3b236ea45c 100644 --- a/icu4c/source/i18n/simpletz.cpp +++ b/icu4c/source/i18n/simpletz.cpp @@ -520,14 +520,8 @@ SimpleTimeZone::getOffsetFromLocal(UDate date, UTimeZoneLocalOption nonExistingT rawOffsetGMT = getRawOffset(); 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; - return; - } - int32_t day = dday; - Grego::dayToFields(day, year, month, dom, dow, status); + Grego::timeToFields(date, year, month, dom, dow, millis, status); if (U_FAILURE(status)) return; savingsDST = getOffset(GregorianCalendar::AD, year, month, dom, @@ -555,8 +549,7 @@ SimpleTimeZone::getOffsetFromLocal(UDate date, UTimeZoneLocalOption nonExistingT } } if (recalc) { - day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis); - Grego::dayToFields(day, year, month, dom, dow, status); + Grego::timeToFields(date, year, month, dom, dow, millis, status); if (U_FAILURE(status)) return; savingsDST = getOffset(GregorianCalendar::AD, year, month, dom, static_cast(dow), millis, diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp index e2cf35992f4a..bc3a6420831e 100644 --- a/icu4c/source/i18n/timezone.cpp +++ b/icu4c/source/i18n/timezone.cpp @@ -732,14 +732,7 @@ void TimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset, for (int32_t pass=0; ; ++pass) { int32_t year, millis; int8_t month, dom, dow; - double day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis); - - // out of the range - if (day < INT32_MIN || day > INT32_MAX) { - ec = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - Grego::dayToFields(day, year, month, dom, dow, ec); + Grego::timeToFields(date, year, month, dom, dow, millis, ec); if (U_FAILURE(ec)) return; dstOffset = getOffset(GregorianCalendar::AD, year, month, dom,