ICU-10640 Fix various bugs around duration formatting e.g 3:45:23

X-SVN-Rev: 35186
This commit is contained in:
Travis Keep 2014-02-20 22:41:13 +00:00
parent d09b746a61
commit 7fb4b7bcf6
2 changed files with 97 additions and 22 deletions

View File

@ -385,31 +385,36 @@ static int32_t toHMS(
if (U_FAILURE(status)) {
return 0;
}
int32_t count = 0;
for (int32_t i = 0; i < measureCount; ++i) {
if (measures[i].getUnit() == *hourUnit) {
if ((result & 1) == 0) {
++count;
} else {
// hour must come first
if (result >= 1) {
return 0;
}
hms[0] = measures[i].getNumber();
if (hms[0].getDouble() < 0.0) {
return 0;
}
result |= 1;
} else if (measures[i].getUnit() == *minuteUnit) {
if ((result & 2) == 0) {
++count;
} else {
// minute must come after hour
if (result >= 2) {
return 0;
}
hms[1] = measures[i].getNumber();
if (hms[1].getDouble() < 0.0) {
return 0;
}
result |= 2;
} else if (measures[i].getUnit() == *secondUnit) {
if ((result & 4) == 0) {
++count;
} else {
// second must come after hour and minute
if (result >= 4) {
return 0;
}
hms[2] = measures[i].getNumber();
if (hms[2].getDouble() < 0.0) {
return 0;
}
result |= 4;
} else {
return 0;
@ -734,9 +739,9 @@ UnicodeString &MeasureFormat::formatNumeric(
return appendTo;
}
UDate millis =
(UDate) (((hms[0].getDouble(status) * 60.0
+ hms[1].getDouble(status)) * 60.0
+ hms[2].getDouble(status)) * 1000.0);
(UDate) (((uprv_trunc(hms[0].getDouble(status)) * 60.0
+ uprv_trunc(hms[1].getDouble(status))) * 60.0
+ uprv_trunc(hms[2].getDouble(status))) * 1000.0);
switch (bitMap) {
case 5: // hs
case 7: // hms
@ -774,9 +779,24 @@ UnicodeString &MeasureFormat::formatNumeric(
return appendTo;
}
static void appendRange(
const UnicodeString &src,
int32_t start,
int32_t end,
UnicodeString &dest) {
dest.append(src, start, end - start);
}
static void appendRange(
const UnicodeString &src,
int32_t end,
UnicodeString &dest) {
dest.append(src, end, src.length() - end);
}
UnicodeString &MeasureFormat::formatNumeric(
UDate date,
const DateFormat &dateFmt,
UDate date, // Time since epoch 1:30:00 would be 5400000
const DateFormat &dateFmt, // h:mm, m:ss, or h:mm:ss
UDateFormatField smallestField,
const Formattable &smallestAmount,
UnicodeString &appendTo,
@ -784,20 +804,53 @@ UnicodeString &MeasureFormat::formatNumeric(
if (U_FAILURE(status)) {
return appendTo;
}
// Format the smallest amount with this object's NumberFormat
UnicodeString smallestAmountFormatted;
// We keep track of the integer part of smallest amount so that
// we can replace it later so that we get '0:00:09.3' instead of
// '0:00:9.3'
FieldPosition intFieldPosition(UNUM_INTEGER_FIELD);
(*numberFormat)->format(
smallestAmount, smallestAmountFormatted, status);
smallestAmount, smallestAmountFormatted, intFieldPosition, status);
if (
intFieldPosition.getBeginIndex() == 0 &&
intFieldPosition.getEndIndex() == 0) {
status = U_INTERNAL_PROGRAM_ERROR;
return appendTo;
}
// Format time. draft becomes something like '5:30:45'
FieldPosition smallestFieldPosition(smallestField);
UnicodeString draft;
dateFmt.format(date, draft, smallestFieldPosition, status);
// If we find field for smallest amount replace it with the formatted
// smallest amount from above taking care to replace the integer part
// with what is in original time. For example, If smallest amount
// is 9.35s and the formatted time is 0:00:09 then 9.35 becomes 09.35
// and replacing yields 0:00:09.35
if (smallestFieldPosition.getBeginIndex() != 0 ||
smallestFieldPosition.getEndIndex() != 0) {
appendTo.append(draft, 0, smallestFieldPosition.getBeginIndex());
appendTo.append(smallestAmountFormatted);
appendTo.append(
smallestFieldPosition.getEndIndex() != 0) {
appendRange(draft, 0, smallestFieldPosition.getBeginIndex(), appendTo);
appendRange(
smallestAmountFormatted,
0,
intFieldPosition.getBeginIndex(),
appendTo);
appendRange(
draft,
smallestFieldPosition.getBeginIndex(),
smallestFieldPosition.getEndIndex(),
appendTo);
appendRange(
smallestAmountFormatted,
intFieldPosition.getEndIndex(),
appendTo);
appendRange(
draft,
smallestFieldPosition.getEndIndex(),
draft.length());
appendTo);
} else {
appendTo.append(draft);
}

View File

@ -314,10 +314,19 @@ void MeasureFormatTest::TestFormatPeriodEn() {
Measure(5.0, MeasureUnit::createHour(status), status),
Measure(17.0, MeasureUnit::createMinute(status), status)
};
Measure t_neg5h_17m[] = {
Measure(-5.0, MeasureUnit::createHour(status), status),
Measure(17.0, MeasureUnit::createMinute(status), status)
};
Measure t_19m_28s[] = {
Measure(19.0, MeasureUnit::createMinute(status), status),
Measure(28.0, MeasureUnit::createSecond(status), status)
};
Measure t_0h_0m_9s[] = {
Measure(0.0, MeasureUnit::createHour(status), status),
Measure(0.0, MeasureUnit::createMinute(status), status),
Measure(9.0, MeasureUnit::createSecond(status), status)
};
Measure t_0h_0m_17s[] = {
Measure(0.0, MeasureUnit::createHour(status), status),
Measure(0.0, MeasureUnit::createMinute(status), status),
@ -327,6 +336,16 @@ void MeasureFormatTest::TestFormatPeriodEn() {
Measure(6.0, MeasureUnit::createHour(status), status),
Measure(56.92, MeasureUnit::createMinute(status), status)
};
Measure t_3h_4s_5m[] = {
Measure(3.0, MeasureUnit::createHour(status), status),
Measure(4.0, MeasureUnit::createSecond(status), status),
Measure(5.0, MeasureUnit::createMinute(status), status)
};
Measure t_6_7h_56_92m[] = {
Measure(6.7, MeasureUnit::createHour(status), status),
Measure(56.92, MeasureUnit::createMinute(status), status)
};
Measure t_3h_5h[] = {
Measure(3.0, MeasureUnit::createHour(status), status),
Measure(5.0, MeasureUnit::createHour(status), status)
@ -367,10 +386,13 @@ void MeasureFormatTest::TestFormatPeriodEn() {
{t_1h_23_5m, LENGTHOF(t_1h_23_5m), "1:23.5"},
{t_1h_0m_23s, LENGTHOF(t_1h_0m_23s), "1:00:23"},
{t_5h_17m, LENGTHOF(t_5h_17m), "5:17"},
{t_neg5h_17m, LENGTHOF(t_neg5h_17m), "-5h 17m"},
{t_19m_28s, LENGTHOF(t_19m_28s), "19:28"},
{t_2y_5M_3w_4d, LENGTHOF(t_2y_5M_3w_4d), "2y 5m 3w 4d"},
{t_0h_0m_17s, LENGTHOF(t_0h_0m_17s), "0:00:17"},
{t_0h_0m_9s, LENGTHOF(t_0h_0m_9s), "0:00:09"},
{t_6h_56_92m, LENGTHOF(t_6h_56_92m), "6:56.92"},
{t_6_7h_56_92m, LENGTHOF(t_6_7h_56_92m), "6:56.92"},
{t_3h_4s_5m, LENGTHOF(t_3h_4s_5m), "3h 4s 5m"},
{t_3h_5h, LENGTHOF(t_3h_5h), "3h 5h"}};
ExpectedResult fullDataDe[] = {