Commit 2dd24c86 authored by tnagel@chromium.org's avatar tnagel@chromium.org

Fix rounding of time interval strings

Previously, text output for time intervals always was rounded
down. For example, a time interval of 1 min 59 sec was
displayed as "1 min", which was confusing users in some cases.
This CL implements rounding to nearest integer. Some example
outputs are given below.

0.49 sec --> "0 secs"
0.5  sec --> "1 sec"
59.4 sec --> "59 secs"
59.5 sec --> "1 min"
89.9 sec --> "1 min"
90.0 sec --> "2 mins"
59 min   --> "59 mins"
60 min   --> "1 hour"
89 min   --> "1 hour"
90 min   --> "2 hours"
...

BUG=338631
TEST=unit tests updated

Review URL: https://codereview.chromium.org/143633003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247948 0039d316-1c4b-4281-b951-d872f2087c98
parent 086e6d44
...@@ -282,41 +282,48 @@ icu::PluralFormat* TimeFormatter::createFallbackFormat( ...@@ -282,41 +282,48 @@ icu::PluralFormat* TimeFormatter::createFallbackFormat(
} }
base::string16 FormatTimeImpl(const TimeDelta& delta, FormatType format_type) { base::string16 FormatTimeImpl(const TimeDelta& delta, FormatType format_type) {
if (delta.ToInternalValue() < 0) { if (delta < TimeDelta::FromSeconds(0)) {
NOTREACHED() << "Negative duration"; NOTREACHED() << "Negative duration";
return base::string16(); return base::string16();
} }
int number;
const std::vector<icu::PluralFormat*>& formatters = const std::vector<icu::PluralFormat*>& formatters =
g_time_formatter.Get().formatter(format_type); g_time_formatter.Get().formatter(format_type);
UErrorCode error = U_ZERO_ERROR; UErrorCode error = U_ZERO_ERROR;
icu::UnicodeString time_string; icu::UnicodeString time_string;
// Less than a minute gets "X seconds left"
if (delta.ToInternalValue() < Time::kMicrosecondsPerMinute) { const TimeDelta one_minute(TimeDelta::FromMinutes(1));
number = static_cast<int>(delta.ToInternalValue() / const TimeDelta one_hour(TimeDelta::FromHours(1));
Time::kMicrosecondsPerSecond); const TimeDelta one_day(TimeDelta::FromDays(1));
time_string = formatters[0]->format(number, error);
const TimeDelta half_second(TimeDelta::FromMilliseconds(500));
// Less than 1 hour gets "X minutes left". const TimeDelta half_minute(TimeDelta::FromSeconds(30));
} else if (delta.ToInternalValue() < Time::kMicrosecondsPerHour) { const TimeDelta half_hour(TimeDelta::FromMinutes(30));
number = static_cast<int>(delta.ToInternalValue() / const TimeDelta half_day(TimeDelta::FromHours(12));
Time::kMicrosecondsPerMinute);
time_string = formatters[1]->format(number, error); // Less than 59.5 seconds gets "X seconds left", anything larger is
// rounded to minutes.
// Less than 1 day remaining gets "X hours left" if (delta < one_minute - half_second) {
} else if (delta.ToInternalValue() < Time::kMicrosecondsPerDay) { const int seconds = static_cast<int>((delta + half_second).InSeconds());
number = static_cast<int>(delta.ToInternalValue() / time_string = formatters[0]->format(seconds, error);
Time::kMicrosecondsPerHour);
time_string = formatters[2]->format(number, error); // Less than 59.5 minutes gets "X minutes left", anything larger is
// rounded to hours.
// Anything bigger gets "X days left" } else if (delta < one_hour - half_minute) {
const int minutes = (delta + half_minute).InMinutes();
time_string = formatters[1]->format(minutes, error);
// Less than 23.5 hours gets "X hours left", anything larger is
// rounded to days.
} else if (delta < one_day - half_hour) {
const int hours = (delta + half_hour).InHours();
time_string = formatters[2]->format(hours, error);
// Anything bigger gets "X days left".
} else { } else {
number = static_cast<int>(delta.ToInternalValue() / const int days = (delta + half_day).InDays();
Time::kMicrosecondsPerDay); time_string = formatters[3]->format(days, error);
time_string = formatters[3]->format(number, error);
} }
// With the fallback added, this should never fail. // With the fallback added, this should never fail.
......
...@@ -28,28 +28,31 @@ void TestTimeFormats(const TimeDelta& delta, const char* expected_ascii) { ...@@ -28,28 +28,31 @@ void TestTimeFormats(const TimeDelta& delta, const char* expected_ascii) {
TEST(TimeFormat, FormatTime) { TEST(TimeFormat, FormatTime) {
const TimeDelta one_day = TimeDelta::FromDays(1); const TimeDelta one_day = TimeDelta::FromDays(1);
const TimeDelta three_days = TimeDelta::FromDays(3);
const TimeDelta one_hour = TimeDelta::FromHours(1); const TimeDelta one_hour = TimeDelta::FromHours(1);
const TimeDelta four_hours = TimeDelta::FromHours(4);
const TimeDelta one_min = TimeDelta::FromMinutes(1); const TimeDelta one_min = TimeDelta::FromMinutes(1);
const TimeDelta three_mins = TimeDelta::FromMinutes(3); const TimeDelta one_second = TimeDelta::FromSeconds(1);
const TimeDelta one_sec = TimeDelta::FromSeconds(1); const TimeDelta one_millisecond = TimeDelta::FromMilliseconds(1);
const TimeDelta five_secs = TimeDelta::FromSeconds(5); const TimeDelta zero = TimeDelta::FromMilliseconds(0);
const TimeDelta twohundred_millisecs = TimeDelta::FromMilliseconds(200);
// TODO(jungshik) : These test only pass when the OS locale is 'en'. // TODO(jungshik) : These test only pass when the OS locale is 'en'.
// We need to add SetUp() and TearDown() to set the locale to 'en'. // We need to add SetUp() and TearDown() to set the locale to 'en'.
TestTimeFormats(twohundred_millisecs, "0 secs"); TestTimeFormats(zero, "0 secs");
TestTimeFormats(one_sec - twohundred_millisecs, "0 secs"); TestTimeFormats(499 * one_millisecond, "0 secs");
TestTimeFormats(one_sec + twohundred_millisecs, "1 sec"); TestTimeFormats(500 * one_millisecond, "1 sec");
TestTimeFormats(five_secs + twohundred_millisecs, "5 secs"); TestTimeFormats(1 * one_second + 499 * one_millisecond, "1 sec");
TestTimeFormats(one_min + five_secs, "1 min"); TestTimeFormats(1 * one_second + 500 * one_millisecond, "2 secs");
TestTimeFormats(three_mins + twohundred_millisecs, "3 mins"); TestTimeFormats(59 * one_second + 499 * one_millisecond, "59 secs");
TestTimeFormats(one_hour + five_secs, "1 hour"); TestTimeFormats(59 * one_second + 500 * one_millisecond, "1 min");
TestTimeFormats(four_hours + five_secs, "4 hours"); TestTimeFormats(1 * one_min + 30 * one_second - one_millisecond, "1 min");
TestTimeFormats(one_day + five_secs, "1 day"); TestTimeFormats(1 * one_min + 30 * one_second, "2 mins");
TestTimeFormats(three_days, "3 days"); TestTimeFormats(59 * one_min + 30 * one_second - one_millisecond, "59 mins");
TestTimeFormats(three_days + four_hours, "3 days"); TestTimeFormats(59 * one_min + 30 * one_second, "1 hour");
TestTimeFormats(1 * one_hour + 30 * one_min - one_millisecond, "1 hour");
TestTimeFormats(1 * one_hour + 30 * one_min, "2 hours");
TestTimeFormats(23 * one_hour + 30 * one_min - one_millisecond, "23 hours");
TestTimeFormats(23 * one_hour + 30 * one_min, "1 day");
TestTimeFormats(1 * one_day + 12 * one_hour - one_millisecond, "1 day");
TestTimeFormats(1 * one_day + 12 * one_hour, "2 days");
} }
// crbug.com/159388: This test fails when daylight savings time ends. // crbug.com/159388: This test fails when daylight savings time ends.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment