ICU-10274 Add compound duration formatting for C++

X-SVN-Rev: 33986
This commit is contained in:
Travis Keep 2013-07-25 16:36:25 +00:00
parent 4b1b47ddb0
commit ecd7ea193b
13 changed files with 999 additions and 33 deletions

2
.gitattributes vendored
View file

@ -82,6 +82,8 @@ icu4c/source/extra/uconv/uconv.vcxproj -text
icu4c/source/extra/uconv/uconv.vcxproj.filters -text
icu4c/source/i18n/i18n.vcxproj -text
icu4c/source/i18n/i18n.vcxproj.filters -text
icu4c/source/i18n/timeperiod.cpp -text
icu4c/source/i18n/unicode/timeperiod.h -text
icu4c/source/i18n/unicode/uregion.h -text
icu4c/source/i18n/uregion.cpp -text
icu4c/source/io/io.vcxproj -text

View file

@ -1,7 +1,7 @@
/*
*******************************************************************************
*
* Copyright (C) 2012, International Business Machines
* Copyright (C) 2013, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
@ -29,6 +29,7 @@ static Hashtable* listPatternHash = NULL;
static UMutex listFormatterMutex = U_MUTEX_INITIALIZER;
static UChar FIRST_PARAMETER[] = { 0x7b, 0x30, 0x7d }; // "{0}"
static UChar SECOND_PARAMETER[] = { 0x7b, 0x31, 0x7d }; // "{0}"
static const char *STANDARD_STYLE = "standard";
U_CDECL_BEGIN
static UBool U_CALLCONV uprv_listformatter_cleanup() {
@ -44,9 +45,17 @@ uprv_deleteListFormatData(void *obj) {
U_CDECL_END
static ListFormatData* loadListFormatData(const Locale& locale, UErrorCode& errorCode);
static ListFormatData* loadListFormatData(const Locale& locale, const char* style, UErrorCode& errorCode);
static void getStringByKey(const UResourceBundle* rb, const char* key, UnicodeString& result, UErrorCode& errorCode);
ListFormatter::ListFormatter(const ListFormatter& other) : data(other.data) {
}
ListFormatter& ListFormatter::operator=(const ListFormatter& other) {
data = other.data;
return *this;
}
void ListFormatter::initializeHash(UErrorCode& errorCode) {
if (U_FAILURE(errorCode)) {
return;
@ -64,11 +73,13 @@ void ListFormatter::initializeHash(UErrorCode& errorCode) {
}
const ListFormatData* ListFormatter::getListFormatData(
const Locale& locale, UErrorCode& errorCode) {
const Locale& locale, const char *style, UErrorCode& errorCode) {
if (U_FAILURE(errorCode)) {
return NULL;
}
UnicodeString key(locale.getName(), -1, US_INV);
CharString keyBuffer(locale.getName(), errorCode);
keyBuffer.append(':', errorCode).append(style, errorCode);
UnicodeString key(keyBuffer.data(), -1, US_INV);
ListFormatData* result = NULL;
{
Mutex m(&listFormatterMutex);
@ -83,7 +94,7 @@ const ListFormatData* ListFormatter::getListFormatData(
if (result != NULL) {
return result;
}
result = loadListFormatData(locale, errorCode);
result = loadListFormatData(locale, style, errorCode);
if (U_FAILURE(errorCode)) {
return NULL;
}
@ -104,14 +115,22 @@ const ListFormatData* ListFormatter::getListFormatData(
return result;
}
static ListFormatData* loadListFormatData(const Locale& locale, UErrorCode& errorCode) {
static ListFormatData* loadListFormatData(
const Locale& locale, const char * style, UErrorCode& errorCode) {
UResourceBundle* rb = ures_open(NULL, locale.getName(), &errorCode);
if (U_FAILURE(errorCode)) {
ures_close(rb);
return NULL;
}
rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode);
rb = ures_getByKeyWithFallback(rb, "standard", rb, &errorCode);
rb = ures_getByKeyWithFallback(rb, style, rb, &errorCode);
// TODO(Travis Keep): This is a hack until fallbacks can be added for
// listPattern/duration and listPattern/duration-narrow in CLDR.
if (errorCode == U_MISSING_RESOURCE_ERROR) {
errorCode = U_ZERO_ERROR;
rb = ures_getByKeyWithFallback(rb, "standard", rb, &errorCode);
}
if (U_FAILURE(errorCode)) {
ures_close(rb);
return NULL;
@ -148,12 +167,16 @@ ListFormatter* ListFormatter::createInstance(UErrorCode& errorCode) {
}
ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& errorCode) {
return createInstance(locale, STANDARD_STYLE, errorCode);
}
ListFormatter* ListFormatter::createInstance(const Locale& locale, const char *style, UErrorCode& errorCode) {
Locale tempLocale = locale;
const ListFormatData* listFormatData = getListFormatData(tempLocale, errorCode);
const ListFormatData* listFormatData = getListFormatData(tempLocale, style, errorCode);
if (U_FAILURE(errorCode)) {
return NULL;
}
ListFormatter* p = new ListFormatter(*listFormatData);
ListFormatter* p = new ListFormatter(listFormatData);
if (p == NULL) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
return NULL;
@ -161,7 +184,8 @@ ListFormatter* ListFormatter::createInstance(const Locale& locale, UErrorCode& e
return p;
}
ListFormatter::ListFormatter(const ListFormatData& listFormatterData) : data(listFormatterData) {
ListFormatter::ListFormatter(const ListFormatData* listFormatterData) : data(listFormatterData) {
}
ListFormatter::~ListFormatter() {}
@ -171,18 +195,22 @@ UnicodeString& ListFormatter::format(const UnicodeString items[], int32_t nItems
if (U_FAILURE(errorCode)) {
return appendTo;
}
if (data == NULL) {
errorCode = U_INVALID_STATE_ERROR;
return appendTo;
}
if (nItems > 0) {
UnicodeString newString = items[0];
if (nItems == 2) {
addNewString(data.twoPattern, newString, items[1], errorCode);
addNewString(data->twoPattern, newString, items[1], errorCode);
} else if (nItems > 2) {
addNewString(data.startPattern, newString, items[1], errorCode);
addNewString(data->startPattern, newString, items[1], errorCode);
int32_t i;
for (i = 2; i < nItems - 1; ++i) {
addNewString(data.middlePattern, newString, items[i], errorCode);
addNewString(data->middlePattern, newString, items[i], errorCode);
}
addNewString(data.endPattern, newString, items[nItems - 1], errorCode);
addNewString(data->endPattern, newString, items[nItems - 1], errorCode);
}
if (U_SUCCESS(errorCode)) {
appendTo += newString;

View file

@ -60,12 +60,26 @@ struct ListFormatData : public UMemory {
class U_COMMON_API ListFormatter : public UObject{
public:
/**
* Copy constructor.
* @draft ICU 52
*/
ListFormatter(const ListFormatter&);
/**
* Assignment operator.
* @draft ICU 52
*/
ListFormatter& operator=(const ListFormatter& other);
/**
* Creates a ListFormatter appropriate for the default locale.
*
* @param errorCode ICU error code, set if no data available for default locale.
* @return Pointer to a ListFormatter object for the default locale,
* created from internal data derived from CLDR data.
* @deprecated
* @draft ICU 50
*/
static ListFormatter* createInstance(UErrorCode& errorCode);
@ -77,10 +91,22 @@ class U_COMMON_API ListFormatter : public UObject{
* @param errorCode ICU error code, set if no data available for the given locale.
* @return A ListFormatter object created from internal data derived from
* CLDR data.
* @deprecated
* @draft ICU 50
*/
static ListFormatter* createInstance(const Locale& locale, UErrorCode& errorCode);
/**
* Creates a ListFormatter appropriate for a locale and style.
*
* @param locale The locale.
* @param style the style, either "standard", "duration", or "duration-short"
* @param errorCode ICU error code, set if no data available for the given locale.
* @return A ListFormatter object created from internal data derived from
* CLDR data.
* @internal
*/
static ListFormatter* createInstance(const Locale& locale, const char* style, UErrorCode& errorCode);
/**
* Destructor.
@ -106,20 +132,17 @@ class U_COMMON_API ListFormatter : public UObject{
/**
* @internal constructor made public for testing.
*/
ListFormatter(const ListFormatData& listFormatterData);
ListFormatter(const ListFormatData* listFormatterData);
private:
static void initializeHash(UErrorCode& errorCode);
static const ListFormatData* getListFormatData(const Locale& locale, UErrorCode& errorCode);
static const ListFormatData* getListFormatData(const Locale& locale, const char *style, UErrorCode& errorCode);
ListFormatter();
ListFormatter(const ListFormatter&);
ListFormatter& operator = (const ListFormatter&);
void addNewString(const UnicodeString& pattern, UnicodeString& originalString,
const UnicodeString& newString, UErrorCode& errorCode) const;
const ListFormatData& data;
const ListFormatData* data;
};
U_NAMESPACE_END

View file

@ -86,7 +86,9 @@ tmunit.o tmutamt.o tmutfmt.o currpinf.o \
uspoof.o uspoof_impl.o uspoof_build.o uspoof_conf.o uspoof_wsconf.o decfmtst.o smpdtfst.o \
ztrans.o zrule.o vzone.o fphdlimp.o fpositer.o locdspnm.o \
decNumber.o decContext.o alphaindex.o tznames.o tznames_impl.o tzgnames.o \
tzfmt.o compactdecimalformat.o gender.o region.o uregion.o scriptset.o identifier_info.o
tzfmt.o compactdecimalformat.o gender.o region.o scriptset.o identifier_info.o \
tzfmt.o compactdecimalformat.o gender.o region.o uregion.o scriptset.o \
identifier_info.o timeperiod.o
## Header files to install
HEADERS = $(srcdir)/unicode/*.h

View file

@ -330,6 +330,7 @@
<ClCompile Include="smpdtfmt.cpp" />
<ClCompile Include="smpdtfst.cpp" />
<ClCompile Include="taiwncal.cpp" />
<ClCompile Include="timeperiod.cpp" />
<ClCompile Include="timezone.cpp" />
<ClCompile Include="tmunit.cpp" />
<ClCompile Include="tmutamt.cpp" />
@ -1179,6 +1180,20 @@
</CustomBuild>
<ClInclude Include="smpdtfst.h" />
<ClInclude Include="taiwncal.h" />
<CustomBuild Include="unicode\timeperiod.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode
</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>
</CustomBuild>
<CustomBuild Include="unicode\timezone.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode
</Command>

View file

@ -249,6 +249,9 @@
<ClCompile Include="taiwncal.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="timeperiod.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="timezone.cpp">
<Filter>formatting</Filter>
</ClCompile>
@ -942,6 +945,9 @@
<CustomBuild Include="unicode\smpdtfmt.h">
<Filter>formatting</Filter>
</CustomBuild>
<CustomBuild Include="unicode\timeperiod.h">
<Filter>formatting</Filter>
</CustomBuild>
<CustomBuild Include="unicode\timezone.h">
<Filter>formatting</Filter>
</CustomBuild>

View file

@ -0,0 +1,119 @@
/*
*******************************************************************************
* Copyright (C) 2013-2013, Google, International Business Machines Corporation
* and others. All Rights Reserved.
*******************************************************************************
*/
#include <math.h>
#include "unicode/timeperiod.h"
#include "putilimp.h"
#if !UCONFIG_NO_FORMATTING
U_NAMESPACE_BEGIN
TimePeriod::TimePeriod(const TimePeriod& other) : fLength(other.fLength) {
for (int32_t i = 0; i < sizeof(fFields) / sizeof(fFields[0]); ++i) {
if (other.fFields[i] == NULL) {
fFields[i] = NULL;
} else {
fFields[i] = (TimeUnitAmount *) other.fFields[i]->clone();
}
}
}
TimePeriod::TimePeriod(
const TimeUnitAmount * const *timeUnitAmounts,
int32_t length,
UErrorCode& status) : fLength(0) {
int32_t fieldCount = sizeof(fFields) / sizeof(fFields[0]);
for (int32_t i = 0; i < fieldCount; ++i) {
fFields[i] = NULL;
}
if (U_FAILURE(status)) {
return;
}
for (int32_t i = 0; i < length; ++i) {
const TimeUnitAmount *tua = timeUnitAmounts[i];
int32_t idx = tua->getTimeUnitField();
if (fFields[idx] != NULL) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
fFields[idx] = (TimeUnitAmount *) tua->clone();
++fLength;
}
validate(status);
if (U_FAILURE(status)) {
return;
}
}
void TimePeriod::validate(UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
if (fLength == 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
int32_t fieldCount = sizeof(fFields) / sizeof(fFields[0]);
UBool fractionalFieldEncountered = FALSE;
for (int32_t i = 0; i < fieldCount; ++i) {
if (fFields[i] == NULL) {
continue;
}
if (fractionalFieldEncountered) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
UErrorCode doubleStatus = U_ZERO_ERROR;
double value = fFields[i]->getNumber().getDouble(doubleStatus);
if (value != uprv_floor(value)) {
fractionalFieldEncountered = TRUE;
}
}
}
TimePeriod::~TimePeriod() {
int32_t fieldCount = sizeof(fFields) / sizeof(fFields[0]);
for (int32_t i = 0; i < fieldCount; ++i) {
delete fFields[i];
}
}
UBool TimePeriod::operator==(const TimePeriod& other) const {
// If same object, they are equal
if (this == &other) {
return TRUE;
}
int32_t fieldCount = sizeof(fFields) / sizeof(fFields[0]);
for (int32_t i = 0; i < fieldCount; ++i) {
if (fFields[i] == other.fFields[i]) {
continue;
}
// One is NULL, the other isn't.
if (fFields[i] == NULL || other.fFields[i] == NULL) {
return FALSE;
}
if (*fFields[i] != *other.fFields[i]) {
return FALSE;
}
}
return TRUE;
}
UBool TimePeriod::operator!=(const TimePeriod& other) const {
return !(*this == other);
}
const TimeUnitAmount *TimePeriod::getAmount(
TimeUnit::UTimeUnitFields field) const {
return fFields[field];
}
U_NAMESPACE_END
#endif

View file

@ -17,7 +17,12 @@
#include "cstring.h"
#include "hash.h"
#include "uresimp.h"
#include "unicode/datefmt.h"
#include "unicode/listformatter.h"
#include "unicode/msgfmt.h"
#include "unicode/smpdtfmt.h"
#include "unicode/timeperiod.h"
#include "unicode/udat.h"
#include "uassert.h"
#define LEFT_CURLY_BRACKET ((UChar)0x007B)
@ -76,24 +81,48 @@ static const UChar PLURAL_COUNT_ZERO[] = {LOW_Z, LOW_E, LOW_R, LOW_O, 0};
static const UChar PLURAL_COUNT_ONE[] = {LOW_O, LOW_N, LOW_E, 0};
static const UChar PLURAL_COUNT_TWO[] = {LOW_T, LOW_W, LOW_O, 0};
static const TimeUnit::UTimeUnitFields FIELDS_BY_DURATION[] = {
TimeUnit::UTIMEUNIT_YEAR,
TimeUnit::UTIMEUNIT_MONTH,
TimeUnit::UTIMEUNIT_WEEK,
TimeUnit::UTIMEUNIT_DAY,
TimeUnit::UTIMEUNIT_HOUR,
TimeUnit::UTIMEUNIT_MINUTE,
TimeUnit::UTIMEUNIT_SECOND,
TimeUnit::UTIMEUNIT_FIELD_COUNT};
static void cloneDateFormat(DateFormat *&, const DateFormat *);
static double getAmountOrZero(const TimePeriod& timePeriod, TimeUnit::UTimeUnitFields field);
TimeUnitFormat::TimeUnitFormat(UErrorCode& status)
: fNumberFormat(NULL),
fPluralRules(NULL) {
fPluralRules(NULL),
fListFormatter(NULL),
fHourMinute(NULL),
fHourMinuteSecond(NULL),
fMinuteSecond(NULL) {
create(Locale::getDefault(), UTMUTFMT_FULL_STYLE, status);
}
TimeUnitFormat::TimeUnitFormat(const Locale& locale, UErrorCode& status)
: fNumberFormat(NULL),
fPluralRules(NULL) {
fPluralRules(NULL),
fListFormatter(NULL),
fHourMinute(NULL),
fHourMinuteSecond(NULL),
fMinuteSecond(NULL) {
create(locale, UTMUTFMT_FULL_STYLE, status);
}
TimeUnitFormat::TimeUnitFormat(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status)
: fNumberFormat(NULL),
fPluralRules(NULL) {
fPluralRules(NULL),
fListFormatter(NULL),
fHourMinute(NULL),
fHourMinuteSecond(NULL),
fMinuteSecond(NULL) {
create(locale, style, status);
}
@ -102,8 +131,11 @@ TimeUnitFormat::TimeUnitFormat(const TimeUnitFormat& other)
: MeasureFormat(other),
fNumberFormat(NULL),
fPluralRules(NULL),
fStyle(UTMUTFMT_FULL_STYLE)
{
fListFormatter(NULL),
fHourMinute(NULL),
fHourMinuteSecond(NULL),
fMinuteSecond(NULL),
fStyle(UTMUTFMT_FULL_STYLE) {
for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
i = (TimeUnit::UTimeUnitFields)(i+1)) {
@ -124,6 +156,14 @@ TimeUnitFormat::~TimeUnitFormat() {
}
delete fPluralRules;
fPluralRules = NULL;
delete fListFormatter;
fListFormatter = NULL;
delete fHourMinute;
fHourMinute = NULL;
delete fHourMinuteSecond;
fHourMinuteSecond = NULL;
delete fMinuteSecond;
fMinuteSecond = NULL;
}
@ -151,6 +191,16 @@ TimeUnitFormat::operator=(const TimeUnitFormat& other) {
} else {
fNumberFormat = NULL;
}
delete fListFormatter;
if (other.fListFormatter) {
fListFormatter = new ListFormatter(*other.fListFormatter);
} else {
fListFormatter = NULL;
}
cloneDateFormat(fHourMinute, other.fHourMinute);
cloneDateFormat(fHourMinuteSecond, other.fHourMinuteSecond);
cloneDateFormat(fMinuteSecond, other.fMinuteSecond);
fLocale = other.fLocale;
for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
@ -224,11 +274,17 @@ TimeUnitFormat::format(const Formattable& obj, UnicodeString& toAppendTo,
count.extract(0, count.length(), result, "UTF-8");
std::cout << "number: " << number << "; format plural count: " << result << "\n";
#endif
MessageFormat* pattern = ((MessageFormat**)countToPattern->get(count))[fStyle];
UTimeUnitFormatStyle effectiveStyle = (fStyle == UTMUTFMT_NUMERIC_STYLE) ?
UTMUTFMT_ABBREVIATED_STYLE : fStyle;
MessageFormat* pattern = ((MessageFormat**)countToPattern->get(count))[effectiveStyle];
Formattable formattable[1];
formattable[0].setDouble(number);
return pattern->format(formattable, 1, toAppendTo, pos, status);
}
const TimePeriod* period = dynamic_cast<const TimePeriod*>(formatObj);
if (period != NULL) {
return formatTimePeriod(*period, toAppendTo, status);
}
}
status = U_ILLEGAL_ARGUMENT_ERROR;
return toAppendTo;
@ -271,6 +327,10 @@ TimeUnitFormat::parseObject(const UnicodeString& source,
MessageFormat** patterns = (MessageFormat**)valueTok.pointer;
for (UTimeUnitFormatStyle style = UTMUTFMT_FULL_STYLE; style < UTMUTFMT_FORMAT_STYLE_COUNT;
style = (UTimeUnitFormatStyle)(style + 1)) {
// We don't support parsing of numeric styles, so skip it.
if (style == UTMUTFMT_NUMERIC_STYLE) {
continue;
}
MessageFormat* pattern = patterns[style];
pos.setErrorIndex(-1);
pos.setIndex(oldPos);
@ -356,13 +416,129 @@ TimeUnitFormat::parseObject(const UnicodeString& source,
}
}
UnicodeString&
TimeUnitFormat::formatTimePeriod(
const TimePeriod& timePeriod, UnicodeString& toAppendTo, UErrorCode& status) const {
if (U_FAILURE(status)) {
return toAppendTo;
}
if (fStyle == UTMUTFMT_NUMERIC_STYLE && formatTimePeriodAsNumeric(timePeriod, toAppendTo, status)) {
return toAppendTo;
}
UnicodeString *items = new UnicodeString[timePeriod.length()];
if (items == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return toAppendTo;
}
int32_t idx = 0;
for (int32_t fieldIndex = 0; FIELDS_BY_DURATION[fieldIndex] != TimeUnit::UTIMEUNIT_FIELD_COUNT; ++fieldIndex) {
const TimeUnitAmount *amount = timePeriod.getAmount(FIELDS_BY_DURATION[fieldIndex]);
if (amount == NULL) {
continue;
}
TimeUnitAmount *timeUnitAmountCopy = new TimeUnitAmount(*amount);
if (timeUnitAmountCopy == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
delete [] items;
return toAppendTo;
}
format(Formattable(timeUnitAmountCopy), items[idx], status);
if (U_FAILURE(status)) {
delete [] items;
return toAppendTo;
}
++idx;
}
UnicodeString& result = fListFormatter->format(items, timePeriod.length(), toAppendTo, status);
delete [] items;
return result;
}
UBool
TimeUnitFormat::formatTimePeriodAsNumeric(
const TimePeriod& timePeriod, UnicodeString& toAppendTo, UErrorCode& status) const {
if (U_FAILURE(status)) {
return TRUE;
}
TimeUnit::UTimeUnitFields biggestUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT;
TimeUnit::UTimeUnitFields smallestUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT;
const TimeUnitAmount *smallestAmount = NULL;
for (int32_t fieldIndex = 0; FIELDS_BY_DURATION[fieldIndex] != TimeUnit::UTIMEUNIT_FIELD_COUNT; ++fieldIndex) {
const TimeUnitAmount *amount = timePeriod.getAmount(FIELDS_BY_DURATION[fieldIndex]);
if (amount == NULL) {
continue;
}
if (biggestUnit == TimeUnit::UTIMEUNIT_FIELD_COUNT) {
biggestUnit = FIELDS_BY_DURATION[fieldIndex];
}
smallestUnit = FIELDS_BY_DURATION[fieldIndex];
smallestAmount = amount;
}
U_ASSERT(biggestUnit != TimeUnit::UTIMEUNIT_FIELD_COUNT);
U_ASSERT(smallestUnit != TimeUnit::UTIMEUNIT_FIELD_COUNT);
U_ASSERT(smallestAmount != NULL);
double millis = ((getAmountOrZero(timePeriod, TimeUnit::UTIMEUNIT_HOUR) * 60.0
+ getAmountOrZero(timePeriod, TimeUnit::UTIMEUNIT_MINUTE)) * 60.0
+ getAmountOrZero(timePeriod, TimeUnit::UTIMEUNIT_SECOND)) * 1000.0;
if (biggestUnit == TimeUnit::UTIMEUNIT_HOUR && smallestUnit == TimeUnit::UTIMEUNIT_SECOND) {
numericFormat(millis, *fHourMinuteSecond, UDAT_SECOND_FIELD, smallestAmount->getNumber(), toAppendTo, status);
return TRUE;
}
if (biggestUnit == TimeUnit::UTIMEUNIT_MINUTE && smallestUnit == TimeUnit::UTIMEUNIT_SECOND) {
numericFormat(millis, *fMinuteSecond, UDAT_SECOND_FIELD, smallestAmount->getNumber(), toAppendTo, status);
return TRUE;
}
if (biggestUnit == TimeUnit::UTIMEUNIT_HOUR && smallestUnit == TimeUnit::UTIMEUNIT_MINUTE) {
numericFormat(millis, *fHourMinute, UDAT_MINUTE_FIELD, smallestAmount->getNumber(), toAppendTo, status);
return TRUE;
}
return FALSE;
}
void
TimeUnitFormat::numericFormat(
double date,
const DateFormat &dateFormat,
int32_t smallestField,
const Formattable& smallestAmount,
UnicodeString& toAppendTo,
UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
UnicodeString smallestAmountFormatted;
fNumberFormat->format(smallestAmount, smallestAmountFormatted, status);
if (U_FAILURE(status)) {
return;
}
FieldPositionIterator fpi;
int32_t prevLength = toAppendTo.length();
dateFormat.format(Formattable(date, Formattable::kIsDate), toAppendTo, &fpi, status);
if (U_FAILURE(status)) {
return;
}
FieldPosition fp;
UBool substituted = FALSE;
while (fpi.next(fp)) {
if (fp.getField() == smallestField) {
toAppendTo.replace(
prevLength + fp.getBeginIndex(),
fp.getEndIndex() - fp.getBeginIndex(),
smallestAmountFormatted);
substituted = TRUE;
break;
}
}
U_ASSERT(substituted);
}
void
TimeUnitFormat::create(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
if (style < UTMUTFMT_FULL_STYLE || style > UTMUTFMT_ABBREVIATED_STYLE) {
if (style < UTMUTFMT_FULL_STYLE || style >= UTMUTFMT_FORMAT_STYLE_COUNT) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
@ -415,6 +591,18 @@ TimeUnitFormat::initDataMembers(UErrorCode& err){
}
delete fPluralRules;
fPluralRules = PluralRules::forLocale(fLocale, err);
delete fListFormatter;
if (fStyle == UTMUTFMT_FULL_STYLE) {
fListFormatter = ListFormatter::createInstance(fLocale, "duration", err);
} else {
fListFormatter = ListFormatter::createInstance(fLocale, "duration-short", err);
}
delete fHourMinute;
fHourMinute = loadNumericDurationFormat("hm", err);
delete fHourMinuteSecond;
fHourMinuteSecond = loadNumericDurationFormat("hms", err);
delete fMinuteSecond;
fMinuteSecond = loadNumericDurationFormat("ms", err);
for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR;
i < TimeUnit::UTIMEUNIT_FIELD_COUNT;
i = (TimeUnit::UTimeUnitFields)(i+1)) {
@ -423,8 +611,40 @@ TimeUnitFormat::initDataMembers(UErrorCode& err){
}
}
DateFormat *
TimeUnitFormat::loadNumericDurationFormat(const char *pattern, UErrorCode& status) const {
if (U_FAILURE(status)) {
return NULL;
}
UResourceBundle *rb, *unitsRes;
rb = ures_open(NULL, fLocale.getName(), &status);
if (U_FAILURE(status)) {
return NULL;
}
CharString path("durationUnits", status);
path.append('/', status).append(pattern, status);
int32_t fullPatternSize;
const UChar *fullPatternChars = ures_getStringByKeyWithFallback(rb, path.data(), &fullPatternSize, &status);
if (U_FAILURE(status)) {
ures_close(rb);
return NULL;
}
UnicodeString fullPattern(FALSE, fullPatternChars, fullPatternSize);
fullPattern.findAndReplace(UnicodeString("h"), UnicodeString("H"));
DateFormat *result = new SimpleDateFormat(fullPattern, status);
if (result == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
ures_close(rb);
return NULL;
}
if (U_FAILURE(status)) {
delete result;
return NULL;
}
result->setTimeZone(*TimeZone::getGMT());
return result;
}
void
TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, const char* key,
@ -900,6 +1120,25 @@ TimeUnitFormat::getTimeUnitName(TimeUnit::UTimeUnitFields unitField,
}
}
void cloneDateFormat(DateFormat *&dest, const DateFormat *src) {
delete dest;
if (src) {
dest = (DateFormat *) src->clone();
} else {
dest = NULL;
}
}
double getAmountOrZero(const TimePeriod& timePeriod, TimeUnit::UTimeUnitFields field) {
const TimeUnitAmount *amount = timePeriod.getAmount(field);
if (amount == NULL) {
return 0.0;
}
UErrorCode status = U_ZERO_ERROR;
return amount->getNumber().getDouble(status);
}
U_NAMESPACE_END
#endif

View file

@ -0,0 +1,113 @@
/*
*******************************************************************************
* Copyright (C) 2013-2013, Google, International Business Machines Corporation
* and others. All Rights Reserved.
*******************************************************************************
*/
#ifndef __TIMEPERIOD_H__
#define __TIMEPERIOD_H__
// TODO:
// 1. Add size() method and test.
// 2. testEquals() -> testTimePeriodEquals()
#include "unicode/utypes.h"
/**
* \file
* \brief C++ API: Format and parse duration in single time unit
*/
#if !UCONFIG_NO_FORMATTING
#include "unicode/tmunit.h"
#include "unicode/tmutamt.h"
U_NAMESPACE_BEGIN
class U_I18N_API TimePeriod: public UObject {
public:
// copy constructor.
TimePeriod(const TimePeriod& other);
/**
* Constructor.
* @param timeUnitAmounts an array of TimeUnitAmounts pointers. TimePeriod copies the
* data in this array. The caller is responsible for freeing the TimeUnitAmount objects
* and the array.
* @param length the number of timeUnitAmount pointers in timeUnitAmounts array.
* @param status error returned here if timeUnitAmounts is empty;
* timeUnitAmounts has duplicate time units; or any timeUnitAmount except the
* smallest has a non-integer value.
* @draft ICU 52
*/
TimePeriod(
const TimeUnitAmount * const *timeUnitAmounts, int32_t length, UErrorCode& status);
/**
* Destructor
* @draft ICU 52
*/
virtual ~TimePeriod();
/**
* Returns true if the given TimePeriod objects are semantically equal.
* For two TimePeriod objects to be equal, they must contain the same
* units, and the amount for each unit much be equal. For example,
* 5 hours, 37 minutes == 37 minutes, 5 hours,
* but 0 days, 5 hours != 5 hours.
* @param that the TimePeriod to compare with.
* @return true if the given TimePeriod objects are semantically equal.
* @draft ICU 52
*/
UBool operator==(const TimePeriod& that) const;
/**
* Returns true if the given TimePeriod objects are semantically
* unequal.
* @param that the TimePeriod to compare with.
* @return true if the given TimePeriod objects are semantically
* unequal.
* @draft ICU 52
*/
UBool operator!=(const TimePeriod& that) const;
/**
* Gets a specific field out of a time period.
* @param field is the field to fetch
* @return The desired field or NULL if it does not exist.
*/
const TimeUnitAmount* getAmount(TimeUnit::UTimeUnitFields field) const;
/**
* Returns the number of time units in this object.
* @draft ICU 52
*/
inline int32_t length() const {
return fLength;
}
private:
int32_t fLength;
TimeUnitAmount *fFields[TimeUnit::UTIMEUNIT_FIELD_COUNT];
// Clients use forAmount and never use ctor directly.
TimePeriod() {
}
/**
* No assignment operator needed because class is immutable.
*/
TimePeriod& operator=(const TimePeriod& other);
void validate(UErrorCode& status) const;
};
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif // __TMUTFMT_H__
//eof

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2008-2012, Google, International Business Machines Corporation
* Copyright (C) 2008-2013, Google, International Business Machines Corporation
* and others. All Rights Reserved.
*******************************************************************************
*/
@ -37,6 +37,8 @@ enum UTimeUnitFormatStyle {
UTMUTFMT_FULL_STYLE,
/** @stable ICU 4.8 */
UTMUTFMT_ABBREVIATED_STYLE,
/** @draft ICU 52 */
UTMUTFMT_NUMERIC_STYLE,
/** @stable ICU 4.8 */
UTMUTFMT_FORMAT_STYLE_COUNT
};
@ -44,8 +46,11 @@ typedef enum UTimeUnitFormatStyle UTimeUnitFormatStyle; /**< @stable ICU 4.8 */
U_NAMESPACE_BEGIN
class DateFormat;
class Hashtable;
class UVector;
class TimePeriod;
class ListFormatter;
/**
* Format or parse a TimeUnitAmount, using plural rules for the units where available.
@ -186,6 +191,18 @@ public:
Formattable& result,
ParsePosition& pos) const;
/**
* Format a time period.
* @param timePeriod the time period to format.
* @param toAppendTo where the formatted string is stored.
* @param status any error is stored here
* @return a reference to toAppendto
* @draft ICU 52
*/
UnicodeString& formatTimePeriod(const TimePeriod &timePeriod,
UnicodeString& toAppendTo,
UErrorCode& status) const;
/**
* Return the class ID for this class. This is useful only for comparing to
* a return value from getDynamicClassID(). For example:
@ -217,8 +234,15 @@ private:
Locale fLocale;
Hashtable* fTimeUnitToCountToPatterns[TimeUnit::UTIMEUNIT_FIELD_COUNT];
PluralRules* fPluralRules;
ListFormatter *fListFormatter;
DateFormat *fHourMinute;
DateFormat *fHourMinuteSecond;
DateFormat *fMinuteSecond;
UTimeUnitFormatStyle fStyle;
UBool formatTimePeriodAsNumeric(
const TimePeriod& timePeriod, UnicodeString& toAppendTo, UErrorCode& status) const;
void create(const Locale& locale, UTimeUnitFormatStyle style, UErrorCode& status);
// it might actually be simpler to make them Decimal Formats later.
@ -252,6 +276,19 @@ private:
// get time unit name, such as "year", from time unit field enum, such as
// UTIMEUNIT_YEAR.
static const char* getTimeUnitName(TimeUnit::UTimeUnitFields field, UErrorCode& status);
void numericFormat(
double date,
const DateFormat &dateFormat,
int32_t smallestField,
const Formattable& smallestAmount,
UnicodeString& toAppendto,
UErrorCode& status) const;
DateFormat *loadNumericDurationFormat(
const char *pattern,
UErrorCode& status) const;
};

View file

@ -175,7 +175,7 @@ void ListFormatterTest::TestOutOfOrderPatterns() {
ListFormatData data("{1} after {0}", "{1} after the first {0}",
"{1} after {0}", "{1} in the last after {0}");
ListFormatter formatter(data);
ListFormatter formatter(&data);
UnicodeString input1[] = {one};
CheckFormatting(&formatter, input1, 1, results[0]);

View file

@ -1,5 +1,5 @@
/********************************************************************
* Copyright (c) 2008-2012, International Business Machines Corporation and
* Copyright (c) 2008-2013, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@ -11,6 +11,7 @@
#include "unicode/tmutamt.h"
#include "unicode/tmutfmt.h"
#include "tufmtts.h"
#include "unicode/timeperiod.h"
#include "unicode/ustring.h"
//TODO: put as compilation flag
@ -20,6 +21,45 @@
#include <iostream>
#endif
struct TimePeriodResult {
TimePeriod timePeriod;
const char* result;
};
class TimeUnitAmountSubClass : public TimeUnitAmount {
public:
TimeUnitAmountSubClass(double amount, TimeUnit::UTimeUnitFields timeUnitField, int ex, UErrorCode &status) : TimeUnitAmount(amount, timeUnitField, status), extra(ex) { }
TimeUnitAmountSubClass(const TimeUnitAmountSubClass &that)
: TimeUnitAmount(that), extra(that.extra) { }
TimeUnitAmountSubClass &operator=(const TimeUnitAmountSubClass &that) {
TimeUnitAmount::operator=(that);
extra = that.extra;
return *this;
}
virtual UObject* clone() const {
return new TimeUnitAmountSubClass(*this);
}
virtual ~TimeUnitAmountSubClass() { }
int extra;
};
static TimePeriod create1m59_9996s(UErrorCode &status);
static TimePeriod create19m(UErrorCode &status);
static TimePeriod create19m28s(UErrorCode &status);
static TimePeriod create19m29s(UErrorCode &status);
static TimePeriod create1h23_5s(UErrorCode &status);
static TimePeriod create1h23s(UErrorCode &status);
static TimePeriod create1h23_5m(UErrorCode &status);
static TimePeriod create1h0m23s(UErrorCode &status);
static TimePeriod create5h17m(UErrorCode &status);
static TimePeriod create2y5M3w4d(UErrorCode &status);
static TimePeriod create0h0m17s(UErrorCode &status);
static TimePeriod create6h56_92m(UErrorCode &status);
void TimeUnitTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) {
if (exec) logln("TestSuite TimeUnitTest");
switch (index) {
@ -27,6 +67,11 @@ void TimeUnitTest::runIndexedTest( int32_t index, UBool exec, const char* &name,
TESTCASE(1, testAPI);
TESTCASE(2, testGreekWithFallback);
TESTCASE(3, testGreekWithSanitization);
TESTCASE(4, testFormatPeriodEn);
TESTCASE(5, testTimePeriodForAmounts);
TESTCASE(6, testTimeUnitAmountSubClass);
TESTCASE(7, testTimePeriodEquals);
TESTCASE(8, testTimePeriodLength);
default: name = ""; break;
}
}
@ -342,5 +387,315 @@ void TimeUnitTest::testGreekWithSanitization() {
delete timeUnitFormat;
}
void TimeUnitTest::testFormatPeriodEn() {
UErrorCode status = U_ZERO_ERROR;
TimePeriodResult fullResults[] = {
{create1m59_9996s(status), "1 minute, 59.9996 seconds"},
{create19m(status), "19 minutes"},
{create1h23_5s(status), "1 hour, 23.5 seconds"},
{create1h23_5m(status), "1 hour, 23.5 minutes"},
{create1h0m23s(status), "1 hour, 0 minutes, 23 seconds"},
{create2y5M3w4d(status), "2 years, 5 months, 3 weeks, 4 days"}};
TimePeriodResult abbrevResults[] = {
{create1m59_9996s(status), "1 min, 59.9996 secs"},
{create19m(status), "19 mins"},
{create1h23_5s(status), "1 hr, 23.5 secs"},
{create1h23_5m(status), "1 hr, 23.5 mins"},
{create1h0m23s(status), "1 hr, 0 mins, 23 secs"},
{create2y5M3w4d(status), "2 yrs, 5 mths, 3 wks, 4 days"}};
TimePeriodResult numericResults[] = {
{create1m59_9996s(status), "1:59.9996"},
{create19m(status), "19 mins"},
{create1h23_5s(status), "1:00:23.5"},
{create1h0m23s(status), "1:00:23"},
{create5h17m(status), "5:17"},
{create19m28s(status), "19:28"},
{create2y5M3w4d(status), "2 yrs, 5 mths, 3 wks, 4 days"},
{create0h0m17s(status), "0:00:17"},
{create6h56_92m(status), "6:56.92"}};
if (U_FAILURE(status)) {
dataerrln("Unable to create time periods - %s", u_errorName(status));
return;
}
LocalPointer<NumberFormat> nf(NumberFormat::createInstance(Locale::getEnglish(), status));
if (U_FAILURE(status)) {
dataerrln("Unable to create NumberFormat object - %s", u_errorName(status));
return;
}
nf->setMaximumFractionDigits(4);
{
TimeUnitFormat tuf(Locale::getEnglish(), UTMUTFMT_FULL_STYLE, status);
tuf.setNumberFormat(*nf, status);
if (U_FAILURE(status)) {
dataerrln("Unable to create TimeUnitFormat object - %s", u_errorName(status));
return;
}
verifyFormatTimePeriod(
tuf,
fullResults,
sizeof(fullResults) / sizeof(TimePeriodResult));
}
{
TimeUnitFormat tuf(Locale::getEnglish(), UTMUTFMT_ABBREVIATED_STYLE, status);
tuf.setNumberFormat(*nf, status);
if (U_FAILURE(status)) {
dataerrln("Unable to create TimeUnitFormat object - %s", u_errorName(status));
return;
}
verifyFormatTimePeriod(
tuf,
abbrevResults,
sizeof(abbrevResults) / sizeof(TimePeriodResult));
}
{
TimeUnitFormat tuf(Locale::getEnglish(), UTMUTFMT_NUMERIC_STYLE, status);
tuf.setNumberFormat(*nf, status);
if (U_FAILURE(status)) {
dataerrln("Unable to create TimeUnitFormat object - %s", u_errorName(status));
return;
}
verifyFormatTimePeriod(
tuf,
numericResults,
sizeof(numericResults) / sizeof(TimePeriodResult));
}
}
void TimeUnitTest::testTimePeriodLength() {
UErrorCode status = U_ZERO_ERROR;
int32_t actual = create1h23_5m(status).length();
if (U_FAILURE(status)) {
dataerrln("Unable to create time period object - %s", u_errorName(status));
return;
}
if (actual != 2) {
errln("Expected 2, got %d", actual);
}
}
void TimeUnitTest::testTimePeriodForAmounts() {
UErrorCode status = U_ZERO_ERROR;
TimeUnitAmount _5h(5.0, TimeUnit::UTIMEUNIT_HOUR, status);
TimeUnitAmount _3_5h(3.5, TimeUnit::UTIMEUNIT_HOUR, status);
TimeUnitAmount _3h(3.0, TimeUnit::UTIMEUNIT_HOUR, status);
TimeUnitAmount _5m(5.0, TimeUnit::UTIMEUNIT_MINUTE, status);
if (U_FAILURE(status)) {
dataerrln("Unable to alocate time unit amounts - %s", u_errorName(status));
return;
}
{
UErrorCode status = U_ZERO_ERROR;
TimeUnitAmount *amounts[] = {&_3h, &_5h};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
TimePeriod(amounts, len, status);
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
errln("Expected U_ILLEGAL_ARGUMENT_ERROR for 3h + 5h, got %s", u_errorName(status));
}
}
{
UErrorCode status = U_ZERO_ERROR;
TimePeriod(NULL, 0, status);
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
errln("Expected U_ILLEGAL_ARGUMENT_ERROR for empty time period, got %s", u_errorName(status));
}
}
{
UErrorCode status = U_ZERO_ERROR;
TimeUnitAmount *amounts[] = {&_3_5h, &_5m};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
TimePeriod(amounts, len, status);
if (status != U_ILLEGAL_ARGUMENT_ERROR) {
errln("Expected U_ILLEGAL_ARGUMENT_ERROR for 3.5h + 5m, got %s", u_errorName(status));
}
}
}
void TimeUnitTest::testTimePeriodEquals() {
UErrorCode status = U_ZERO_ERROR;
TimePeriod _1h23s = create1h23s(status);
// Same variable
verifyEquals(_1h23s, _1h23s);
// Different variables same value
verifyEquals(_1h23s, TimePeriod(_1h23s));
// Different fields
verifyNotEqual(_1h23s, create1h0m23s(status));
// Same fields different values
verifyNotEqual(create19m28s(status), create19m29s(status));
if (U_FAILURE(status)) {
errln("Failure creating TimePeriods, got %s", u_errorName(status));
}
}
void TimeUnitTest::testTimeUnitAmountSubClass() {
UErrorCode status = U_ZERO_ERROR;
TimeUnitAmountSubClass _6h(6.0, TimeUnit::UTIMEUNIT_HOUR, 1, status);
TimeUnitAmountSubClass _5m(5.0, TimeUnit::UTIMEUNIT_MINUTE, 2, status);
if (U_FAILURE(status)) {
dataerrln("Unable to alocate time unit amounts - %s", u_errorName(status));
return;
}
{
UErrorCode status = U_ZERO_ERROR;
TimeUnitAmount *amounts[] = {&_6h, &_5m};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
TimePeriod period(amounts, len, status);
if (2 != ((const TimeUnitAmountSubClass *) period.getAmount(TimeUnit::UTIMEUNIT_MINUTE))->extra) {
errln("Expected polymorphic behavior.");
}
}
}
void TimeUnitTest::verifyFormatTimePeriod(
const TimeUnitFormat& tuf,
const TimePeriodResult* timePeriodResults,
int32_t numResults) {
for (int32_t i = 0; i < numResults; i++) {
UnicodeString expected(timePeriodResults[i].result, -1, US_INV);
expected = expected.unescape();
UErrorCode status = U_ZERO_ERROR;
Formattable formattable(new TimePeriod(timePeriodResults[i].timePeriod));
UnicodeString actual;
FieldPosition pos(0);
tuf.format(formattable, actual, pos, status);
if (U_FAILURE(status)) {
dataerrln("Unable to format time period - %s", u_errorName(status));
return;
}
if (actual != expected) {
errln(UnicodeString("Fail: Expected: ") + expected
+ UnicodeString(" Got: ") + actual);
}
}
}
void TimeUnitTest::verifyEquals(const TimePeriod& lhs, const TimePeriod& rhs) {
if (lhs != rhs) {
errln("Expected equal.");
return;
}
if (!(lhs == rhs)) {
errln("Expected not not equal.");
}
}
void TimeUnitTest::verifyNotEqual(const TimePeriod& lhs, const TimePeriod& rhs) {
if (lhs == rhs) {
errln("Expected not equal.");
return;
}
if (!(lhs != rhs)) {
errln("Expected not not not equal.");
}
}
static TimePeriod create1m59_9996s(UErrorCode &status) {
TimeUnitAmount minutes(1.0, TimeUnit::UTIMEUNIT_MINUTE, status);
TimeUnitAmount seconds(59.9996, TimeUnit::UTIMEUNIT_SECOND, status);
TimeUnitAmount *amounts[] = {&minutes, &seconds};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create19m(UErrorCode &status) {
TimeUnitAmount minutes(19.0, TimeUnit::UTIMEUNIT_MINUTE, status);
TimeUnitAmount *amounts[] = {&minutes};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create19m28s(UErrorCode &status) {
TimeUnitAmount minutes(19.0, TimeUnit::UTIMEUNIT_MINUTE, status);
TimeUnitAmount seconds(28.0, TimeUnit::UTIMEUNIT_SECOND, status);
TimeUnitAmount *amounts[] = {&minutes, &seconds};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create19m29s(UErrorCode &status) {
TimeUnitAmount minutes(19.0, TimeUnit::UTIMEUNIT_MINUTE, status);
TimeUnitAmount seconds(29.0, TimeUnit::UTIMEUNIT_SECOND, status);
TimeUnitAmount *amounts[] = {&minutes, &seconds};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create1h23_5s(UErrorCode &status) {
TimeUnitAmount hours(1.0, TimeUnit::UTIMEUNIT_HOUR, status);
TimeUnitAmount seconds(23.5, TimeUnit::UTIMEUNIT_SECOND, status);
TimeUnitAmount *amounts[] = {&hours, &seconds};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create1h23_5m(UErrorCode &status) {
TimeUnitAmount hours(1.0, TimeUnit::UTIMEUNIT_HOUR, status);
TimeUnitAmount seconds(23.5, TimeUnit::UTIMEUNIT_MINUTE, status);
TimeUnitAmount *amounts[] = {&hours, &seconds};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create1h0m23s(UErrorCode &status) {
TimeUnitAmount hours(1.0, TimeUnit::UTIMEUNIT_HOUR, status);
TimeUnitAmount minutes(0.0, TimeUnit::UTIMEUNIT_MINUTE, status);
TimeUnitAmount seconds(23.0, TimeUnit::UTIMEUNIT_SECOND, status);
TimeUnitAmount *amounts[] = {&hours, &minutes, &seconds};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create1h23s(UErrorCode &status) {
TimeUnitAmount hours(1.0, TimeUnit::UTIMEUNIT_HOUR, status);
TimeUnitAmount seconds(23.0, TimeUnit::UTIMEUNIT_SECOND, status);
TimeUnitAmount *amounts[] = {&hours, &seconds};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create5h17m(UErrorCode &status) {
TimeUnitAmount hours(5.0, TimeUnit::UTIMEUNIT_HOUR, status);
TimeUnitAmount minutes(17.0, TimeUnit::UTIMEUNIT_MINUTE, status);
TimeUnitAmount *amounts[] = {&hours, &minutes};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create2y5M3w4d(UErrorCode &status) {
TimeUnitAmount years(2.0, TimeUnit::UTIMEUNIT_YEAR, status);
TimeUnitAmount months(5.0, TimeUnit::UTIMEUNIT_MONTH, status);
TimeUnitAmount weeks(3.0, TimeUnit::UTIMEUNIT_WEEK, status);
TimeUnitAmount days(4.0, TimeUnit::UTIMEUNIT_DAY, status);
TimeUnitAmount *amounts[] = {&years, &months, &weeks, &days};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create0h0m17s(UErrorCode &status) {
TimeUnitAmount hours(0.0, TimeUnit::UTIMEUNIT_HOUR, status);
TimeUnitAmount minutes(0.0, TimeUnit::UTIMEUNIT_MINUTE, status);
TimeUnitAmount seconds(17.0, TimeUnit::UTIMEUNIT_SECOND, status);
TimeUnitAmount *amounts[] = {&hours, &minutes, &seconds};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
static TimePeriod create6h56_92m(UErrorCode &status) {
TimeUnitAmount hours(6.0, TimeUnit::UTIMEUNIT_HOUR, status);
TimeUnitAmount minutes(56.92, TimeUnit::UTIMEUNIT_MINUTE, status);
TimeUnitAmount *amounts[] = {&hours, &minutes};
int32_t len = sizeof(amounts) / sizeof(TimeUnitAmount*);
return TimePeriod(amounts, len, status);
}
#endif

View file

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 2008-2012, International Business Machines Corporation
* Copyright (c) 2008-2013, International Business Machines Corporation
* and others. All Rights Reserved.
********************************************************************/
@ -14,6 +14,12 @@
#include "unicode/locid.h"
#include "intltest.h"
U_NAMESPACE_BEGIN
class TimeUnitFormat;
class TimePeriod;
U_NAMESPACE_END
struct TimePeriodResult;
/**
* Test basic functionality of various API functions
**/
@ -49,6 +55,27 @@ public:
* As of CLDR shiped in ICU4.8, Greek is one such language.
*/
void testGreekWithSanitization();
void testFormatPeriodEn();
void testTimePeriodLength();
void testTimePeriodEquals();
void testTimePeriodForAmounts();
void testTimeUnitAmountSubClass();
void verifyEquals(const TimePeriod&, const TimePeriod&);
void verifyNotEqual(const TimePeriod&, const TimePeriod&);
void verifyFormatTimePeriod(
const TimeUnitFormat& tuf,
const TimePeriodResult* timePeriodResults,
int32_t numResults);
};
#endif /* #if !UCONFIG_NO_FORMATTING */