diff --git a/.gitattributes b/.gitattributes index bc31d74c884..064b997efa2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -71,6 +71,7 @@ icu4c/source/data/region/pool.res -text icu4c/source/data/unit/pool.res -text icu4c/source/data/zone/pool.res -text icu4c/source/extra/uconv/uconv.vcxproj -text +icu4c/source/i18n/unicode/ureldatefmt.h -text icu4c/source/samples/break/break.vcxproj -text icu4c/source/samples/case/case.vcxproj -text icu4c/source/samples/citer/citer.vcxproj -text @@ -98,6 +99,7 @@ icu4c/source/samples/ugrep/ugrep.vcxproj -text icu4c/source/samples/uresb/resources.vcxproj -text icu4c/source/samples/uresb/uresb.vcxproj -text icu4c/source/samples/ustring/ustring.vcxproj -text +icu4c/source/test/cintltst/crelativedateformattest.c -text icu4c/source/test/depstest/icu-dependencies-mode.el -text icu4c/source/test/iotest/iotest.vcxproj -text icu4c/source/test/letest/cletest.vcxproj -text diff --git a/icu4c/source/i18n/i18n.vcxproj b/icu4c/source/i18n/i18n.vcxproj index 99c53dc14ec..d91d7dd563c 100644 --- a/icu4c/source/i18n/i18n.vcxproj +++ b/icu4c/source/i18n/i18n.vcxproj @@ -1546,6 +1546,20 @@ ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) copy "%(FullPath)" ..\..\include\unicode + + ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) + + + copy "%(FullPath)" ..\..\include\unicode + + ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) + copy "%(FullPath)" ..\..\include\unicode + + ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) + copy "%(FullPath)" ..\..\include\unicode + + ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) + copy "%(FullPath)" ..\..\include\unicode ..\..\include\unicode\%(Filename)%(Extension);%(Outputs) diff --git a/icu4c/source/i18n/i18n.vcxproj.filters b/icu4c/source/i18n/i18n.vcxproj.filters index 9164f5a3cca..a1040f59921 100644 --- a/icu4c/source/i18n/i18n.vcxproj.filters +++ b/icu4c/source/i18n/i18n.vcxproj.filters @@ -1238,6 +1238,9 @@ formatting + + formatting + formatting diff --git a/icu4c/source/i18n/reldatefmt.cpp b/icu4c/source/i18n/reldatefmt.cpp index 4d8ca06f98a..d8fdb3b375e 100644 --- a/icu4c/source/i18n/reldatefmt.cpp +++ b/icu4c/source/i18n/reldatefmt.cpp @@ -1,6 +1,6 @@ /* ****************************************************************************** -* Copyright (C) 2014-2015, International Business Machines Corporation and +* Copyright (C) 2014-2016, International Business Machines Corporation and * others. All Rights Reserved. ****************************************************************************** * @@ -12,6 +12,9 @@ #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION +#include "unicode/ureldatefmt.h" +#include "unicode/udisplaycontext.h" +#include "unicode/unum.h" #include "unicode/localpointer.h" #include "quantityformatter.h" #include "unicode/plurrule.h" @@ -805,6 +808,37 @@ UnicodeString& RelativeDateTimeFormatter::format( return appendTo.append(result); } +UnicodeString& RelativeDateTimeFormatter::formatNumeric( + double offset, URelativeDateTimeUnit unit, + UnicodeString& appendTo, UErrorCode& status) const { + if (U_FAILURE(status)) { + return appendTo; + } + // For a quick bringup just call the above method; this leaves some + // holes (e.g. for handling quarter). Need to redo the data structure + // to support all necessary data items, and to be indexed by the + // newer enum. + UDateRelativeUnit relunit = UDAT_RELATIVE_UNIT_COUNT; + switch (unit) { + case UDAT_REL_UNIT_YEAR: relunit = UDAT_RELATIVE_YEARS; break; + case UDAT_REL_UNIT_MONTH: relunit = UDAT_RELATIVE_MONTHS; break; + case UDAT_REL_UNIT_WEEK: relunit = UDAT_RELATIVE_WEEKS; break; + case UDAT_REL_UNIT_DAY: relunit = UDAT_RELATIVE_DAYS; break; + case UDAT_REL_UNIT_HOUR: relunit = UDAT_RELATIVE_HOURS; break; + case UDAT_REL_UNIT_MINUTE: relunit = UDAT_RELATIVE_MINUTES; break; + case UDAT_REL_UNIT_SECOND: relunit = UDAT_RELATIVE_SECONDS; break; + default: // a unit that the above method does not handle + status = U_MISSING_RESOURCE_ERROR; + return appendTo; + } + UDateDirection direction = UDAT_DIRECTION_NEXT; + if (offset < 0) { + direction = UDAT_DIRECTION_LAST; + offset = -offset; + } + return format(offset, direction, relunit, appendTo, status); +} + UnicodeString& RelativeDateTimeFormatter::format( UDateDirection direction, UDateAbsoluteUnit unit, UnicodeString& appendTo, UErrorCode& status) const { @@ -823,6 +857,61 @@ UnicodeString& RelativeDateTimeFormatter::format( return appendTo.append(result); } +UnicodeString& RelativeDateTimeFormatter::format( + double offset, URelativeDateTimeUnit unit, + UnicodeString& appendTo, UErrorCode& status) const { + if (U_FAILURE(status)) { + return appendTo; + } + // For a quick bringup just use the existing data structure; this leaves + // some holes (e.g. for handling quarter). Need to redo the data structure + // to support all necessary data items, and to be indexed by the + // newer enum. + UDateDirection direction = UDAT_DIRECTION_COUNT; + int32_t intoffset = (offset < 0)? (int32_t)(offset-0.5) : (int32_t)(offset+0.5); + switch (intoffset) { + case -2: direction = UDAT_DIRECTION_LAST_2; break; + case -1: direction = UDAT_DIRECTION_LAST; break; + case 0: direction = UDAT_DIRECTION_THIS; break; + case 1: direction = UDAT_DIRECTION_NEXT; break; + case 2: direction = UDAT_DIRECTION_NEXT_2; break; + default: break; + } + UDateAbsoluteUnit absunit = UDAT_ABSOLUTE_UNIT_COUNT; + switch (unit) { + case UDAT_REL_UNIT_YEAR: absunit = UDAT_ABSOLUTE_YEAR; break; + case UDAT_REL_UNIT_MONTH: absunit = UDAT_ABSOLUTE_MONTH; break; + case UDAT_REL_UNIT_WEEK: absunit = UDAT_ABSOLUTE_WEEK; break; + case UDAT_REL_UNIT_DAY: absunit = UDAT_ABSOLUTE_DAY; break; + case UDAT_REL_UNIT_MINUTE: + case UDAT_REL_UNIT_SECOND: + if (direction == UDAT_DIRECTION_THIS) { + absunit = UDAT_ABSOLUTE_NOW; + direction = UDAT_DIRECTION_PLAIN; + } + break; + case UDAT_REL_UNIT_SUNDAY: absunit = UDAT_ABSOLUTE_SUNDAY; break; + case UDAT_REL_UNIT_MONDAY: absunit = UDAT_ABSOLUTE_MONDAY; break; + case UDAT_REL_UNIT_TUESDAY: absunit = UDAT_ABSOLUTE_TUESDAY; break; + case UDAT_REL_UNIT_WEDNESDAY: absunit = UDAT_ABSOLUTE_WEDNESDAY; break; + case UDAT_REL_UNIT_THURSDAY: absunit = UDAT_ABSOLUTE_THURSDAY; break; + case UDAT_REL_UNIT_FRIDAY: absunit = UDAT_ABSOLUTE_FRIDAY; break; + case UDAT_REL_UNIT_SATURDAY: absunit = UDAT_ABSOLUTE_SATURDAY; break; + default: break; + } + if (direction != UDAT_DIRECTION_COUNT && absunit != UDAT_ABSOLUTE_UNIT_COUNT) { + UnicodeString result(fCache->absoluteUnits[fStyle][absunit][direction]); + if (result.length() > 0) { + if (fOptBreakIterator != NULL) { + adjustForContext(result); + } + return appendTo.append(result); + } + } + // otherwise fallback to formatNumeric + return formatNumeric(offset, unit, appendTo, status); +} + UnicodeString& RelativeDateTimeFormatter::combineDateAndTime( const UnicodeString& relativeDateString, const UnicodeString& timeString, UnicodeString& appendTo, UErrorCode& status) const { @@ -894,8 +983,126 @@ void RelativeDateTimeFormatter::init( } } - U_NAMESPACE_END +// Plain C API + +U_NAMESPACE_USE + +U_CAPI URelativeDateTimeFormatter* U_EXPORT2 +ureldatefmt_open( const char* locale, + UNumberFormat* nfToAdopt, + UDateRelativeDateTimeFormatterStyle width, + UDisplayContext capitalizationContext, + UErrorCode* status ) +{ + if (U_FAILURE(*status)) { + return NULL; + } + LocalPointer formatter(new RelativeDateTimeFormatter(Locale(locale), + (NumberFormat*)nfToAdopt, width, + capitalizationContext, *status)); + if (U_FAILURE(*status)) { + return NULL; + } + return (URelativeDateTimeFormatter*)formatter.orphan(); +} + +U_CAPI void U_EXPORT2 +ureldatefmt_close(URelativeDateTimeFormatter *reldatefmt) +{ + delete (RelativeDateTimeFormatter*)reldatefmt; +} + +U_CAPI int32_t U_EXPORT2 +ureldatefmt_formatNumeric( const URelativeDateTimeFormatter* reldatefmt, + double offset, + URelativeDateTimeUnit unit, + UChar* result, + int32_t resultCapacity, + UErrorCode* status) +{ + if (U_FAILURE(*status)) { + return 0; + } + if (result == NULL ? resultCapacity != 0 : resultCapacity < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + UnicodeString res; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer (copied from udat_format) + res.setTo(result, 0, resultCapacity); + } + ((RelativeDateTimeFormatter*)reldatefmt)->formatNumeric(offset, unit, res, *status); + if (U_FAILURE(*status)) { + return 0; + } + return res.extract(result, resultCapacity, *status); +} + +U_CAPI int32_t U_EXPORT2 +ureldatefmt_format( const URelativeDateTimeFormatter* reldatefmt, + double offset, + URelativeDateTimeUnit unit, + UChar* result, + int32_t resultCapacity, + UErrorCode* status) +{ + if (U_FAILURE(*status)) { + return 0; + } + if (result == NULL ? resultCapacity != 0 : resultCapacity < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + UnicodeString res; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer (copied from udat_format) + res.setTo(result, 0, resultCapacity); + } + ((RelativeDateTimeFormatter*)reldatefmt)->format(offset, unit, res, *status); + if (U_FAILURE(*status)) { + return 0; + } + return res.extract(result, resultCapacity, *status); +} + +U_CAPI int32_t U_EXPORT2 +ureldatefmt_combineDateAndTime( const URelativeDateTimeFormatter* reldatefmt, + const UChar * relativeDateString, + int32_t relativeDateStringLen, + const UChar * timeString, + int32_t timeStringLen, + UChar* result, + int32_t resultCapacity, + UErrorCode* status ) +{ + if (U_FAILURE(*status)) { + return 0; + } + if (result == NULL ? resultCapacity != 0 : resultCapacity < 0 || + relativeDateString == NULL || relativeDateStringLen < 1 || + timeString == NULL || timeStringLen < -1) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + UnicodeString relDateStr((UBool)(relativeDateStringLen == -1), relativeDateString, relativeDateStringLen); + UnicodeString timeStr((UBool)(timeStringLen == -1), timeString, timeStringLen); + UnicodeString res; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer (copied from udat_format) + res.setTo(result, 0, resultCapacity); + } + ((RelativeDateTimeFormatter*)reldatefmt)->combineDateAndTime(relDateStr, timeStr, res, *status); + if (U_FAILURE(*status)) { + return 0; + } + return res.extract(result, resultCapacity, *status); +} + #endif /* !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/i18n/unicode/reldatefmt.h b/icu4c/source/i18n/unicode/reldatefmt.h index c3350c516c4..ffd485ec127 100644 --- a/icu4c/source/i18n/unicode/reldatefmt.h +++ b/icu4c/source/i18n/unicode/reldatefmt.h @@ -1,6 +1,6 @@ /* ***************************************************************************** -* Copyright (C) 2014-2015, International Business Machines Corporation and +* Copyright (C) 2014-2016, International Business Machines Corporation and * others. * All Rights Reserved. ***************************************************************************** @@ -15,6 +15,7 @@ #include "unicode/utypes.h" #include "unicode/uobject.h" #include "unicode/udisplaycontext.h" +#include "unicode/ureldatefmt.h" #include "unicode/locid.h" /** @@ -24,36 +25,6 @@ #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION -/** - * The formatting style - * @stable ICU 54 - */ -typedef enum UDateRelativeDateTimeFormatterStyle { - /** - * Everything spelled out. - * @stable ICU 54 - */ - UDAT_STYLE_LONG, - - /** - * Abbreviations used when possible. - * @stable ICU 54 - */ - UDAT_STYLE_SHORT, - - /** - * Use the shortest possible form. - * @stable ICU 54 - */ - UDAT_STYLE_NARROW, - - /** - * The number of styles. - * @stable ICU 54 - */ - UDAT_STYLE_COUNT -} UDateRelativeDateTimeFormatterStyle; - /** * Represents the unit for formatting a relative date. e.g "in 5 days" * or "in 3 months" @@ -434,6 +405,54 @@ public: UnicodeString& appendTo, UErrorCode& status) const; +#ifndef U_HIDE_DRAFT_API + /** + * Format a combination of URelativeDateTimeUnit and numeric offset + * using a numeric style, e.g. "1 week ago", "in 1 week", + * "5 weeks ago", "in 5 weeks". + * + * @param offset The signed offset for the specified unit. This + * will be formatted according to this object's + * NumberFormat object. + * @param unit The unit to use when formatting the relative + * date, e.g. UDAT_REL_UNIT_WEEK, + * UDAT_REL_UNIT_FRIDAY. + * @param appendTo The string to which the formatted result will be + * appended. + * @param status ICU error code returned here. + * @return appendTo + * @draft ICU 57 + */ + UnicodeString& formatNumeric( + double offset, + URelativeDateTimeUnit unit, + UnicodeString& appendTo, + UErrorCode& status) const; + + /** + * Format a combination of URelativeDateTimeUnit and numeric offset + * using a text style if possible, e.g. "last week", "this week", + * "next week", "yesterday", "tomorrow". Falls back to numeric + * style if no appropriate text term is available for the specified + * offset in the object’s locale. + * + * @param offset The signed offset for the specified unit. + * @param unit The unit to use when formatting the relative + * date, e.g. UDAT_REL_UNIT_WEEK, + * UDAT_REL_UNIT_FRIDAY. + * @param appendTo The string to which the formatted result will be + * appended. + * @param status ICU error code returned here. + * @return appendTo + * @draft ICU 57 + */ + UnicodeString& format( + double offset, + URelativeDateTimeUnit unit, + UnicodeString& appendTo, + UErrorCode& status) const; +#endif /* U_HIDE_DRAFT_API */ + /** * Combines a relative date string and a time string in this object's * locale. This is done with the same date-time separator used for the diff --git a/icu4c/source/i18n/unicode/ureldatefmt.h b/icu4c/source/i18n/unicode/ureldatefmt.h new file mode 100644 index 00000000000..ba4f989e434 --- /dev/null +++ b/icu4c/source/i18n/unicode/ureldatefmt.h @@ -0,0 +1,302 @@ +/* +***************************************************************************************** +* Copyright (C) 2016, International Business Machines +* Corporation and others. All Rights Reserved. +***************************************************************************************** +*/ + +#ifndef URELDATEFMT_H +#define URELDATEFMT_H + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION + +#include "unicode/unum.h" +#include "unicode/udisplaycontext.h" +#include "unicode/localpointer.h" + +/** + * \file + * \brief C API: URelativeDateTimeFormatter, relative date formatting of unit + numeric offset. + * + * Provides simple formatting of relative dates, in two ways + * + *

+ * This does not provide compound formatting for multiple units, + * other than the ability to combine a time string with a relative date, + * as in "next Tuesday at 3:45 PM". It also does not provide support + * for determining which unit to use, such as deciding between "in 7 days" + * and "in 1 week". + * + * @draft ICU 57 + */ + +/** + * The formatting style + * @stable ICU 54 + */ +typedef enum UDateRelativeDateTimeFormatterStyle { + /** + * Everything spelled out. + * @stable ICU 54 + */ + UDAT_STYLE_LONG, + + /** + * Abbreviations used when possible. + * @stable ICU 54 + */ + UDAT_STYLE_SHORT, + + /** + * Use the shortest possible form. + * @stable ICU 54 + */ + UDAT_STYLE_NARROW, + + /** + * The number of styles. + * @stable ICU 54 + */ + UDAT_STYLE_COUNT +} UDateRelativeDateTimeFormatterStyle; + +#ifndef U_HIDE_DRAFT_API +/** + * Represents the unit for formatting a relative date. e.g "in 5 days" + * or "next year" + * @draft ICU 57 + */ +typedef enum URelativeDateTimeUnit { + /** @draft ICU 57 */ + UDAT_REL_UNIT_YEAR, + /** @draft ICU 57 */ + UDAT_REL_UNIT_QUARTER, + /** @draft ICU 57 */ + UDAT_REL_UNIT_MONTH, + /** @draft ICU 57 */ + UDAT_REL_UNIT_WEEK, + /** @draft ICU 57 */ + UDAT_REL_UNIT_DAY, + /** @draft ICU 57 */ + UDAT_REL_UNIT_HOUR, + /** @draft ICU 57 */ + UDAT_REL_UNIT_MINUTE, + /** @draft ICU 57 */ + UDAT_REL_UNIT_SECOND, + /** @draft ICU 57 */ + UDAT_REL_UNIT_SUNDAY, + /** @draft ICU 57 */ + UDAT_REL_UNIT_MONDAY, + /** @draft ICU 57 */ + UDAT_REL_UNIT_TUESDAY, + /** @draft ICU 57 */ + UDAT_REL_UNIT_WEDNESDAY, + /** @draft ICU 57 */ + UDAT_REL_UNIT_THURSDAY, + /** @draft ICU 57 */ + UDAT_REL_UNIT_FRIDAY, + /** @draft ICU 57 */ + UDAT_REL_UNIT_SATURDAY, + /** @draft ICU 57 */ + UDAT_REL_UNIT_COUNT +} URelativeDateTimeUnit; +#endif /* U_HIDE_DRAFT_API */ + +#ifndef U_HIDE_DRAFT_API + +/** + * Opaque URelativeDateTimeFormatter object for use in C programs. + * @draft ICU 57 + */ +struct URelativeDateTimeFormatter; +typedef struct URelativeDateTimeFormatter URelativeDateTimeFormatter; /**< C typedef for struct URelativeDateTimeFormatter. @draft ICU 57 */ + + +/** + * Open a new URelativeDateTimeFormatter object for a given locale using the + * specified width and capitalizationContext, along with a number formatter + * (if desired) to override the default formatter that would be used for + * display of numeric field offsets. The default formatter typically rounds + * toward 0 and has a minimum of 0 fraction digits and a maximum of 3 + * fraction digits (i.e. it will show as many decimal places as necessary + * up to 3, without showing trailing 0s). + * + * @param locale + * The locale + * @param nfToAdopt + * A number formatter to set for this URelativeDateTimeFormatter + * object (instead of the default decimal formatter). Ownership of + * this UNumberFormat object will pass to the URelativeDateTimeFormatter + * object (the URelativeDateTimeFormatter adopts the UNumberFormat), + * which becomes responsible for closing it. If the caller wishes to + * retain ownership of the UNumberFormat object, the caller must clone + * it (with unum_clone) and pass the clone to ureldatefmt_open. May be + * NULL to use the default decimal formatter. + * @param width + * The width - wide, short, narrow, etc. + * @param capitalizationContext + * A value from UDisplayContext that pertains to capitalization, e.g. + * UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE. + * @param status + * A pointer to a UErrorCode to receive any errors. + * @return + * A pointer to a URelativeDateTimeFormatter object for the specified locale, + * or NULL if an error occurred. + * @draft ICU 57 + */ +U_DRAFT URelativeDateTimeFormatter* U_EXPORT2 +ureldatefmt_open( const char* locale, + UNumberFormat* nfToAdopt, + UDateRelativeDateTimeFormatterStyle width, + UDisplayContext capitalizationContext, + UErrorCode* status ); + +/** + * Close a URelativeDateTimeFormatter object. Once closed it may no longer be used. + * @param reldatefmt + * The URelativeDateTimeFormatter object to close. + * @draft ICU 57 + */ +U_DRAFT void U_EXPORT2 +ureldatefmt_close(URelativeDateTimeFormatter *reldatefmt); + +#if U_SHOW_CPLUSPLUS_API + +U_NAMESPACE_BEGIN + +/** + * \class LocalURelativeDateTimeFormatterPointer + * "Smart pointer" class, closes a URelativeDateTimeFormatter via ureldatefmt_close(). + * For most methods see the LocalPointerBase base class. + * + * @see LocalPointerBase + * @see LocalPointer + * @draft ICU 57 + */ +U_DEFINE_LOCAL_OPEN_POINTER(LocalURelativeDateTimeFormatterPointer, URelativeDateTimeFormatter, ureldatefmt_close); + +U_NAMESPACE_END + +#endif + +/** + * Format a combination of URelativeDateTimeUnit and numeric + * offset using a numeric style, e.g. "1 week ago", "in 1 week", + * "5 weeks ago", "in 5 weeks". + * + * @param reldatefmt + * The URelativeDateTimeFormatter object specifying the + * format conventions. + * @param offset + * The signed offset for the specified unit. This will + * be formatted according to this object's UNumberFormat + * object. + * @param unit + * The unit to use when formatting the relative + * date, e.g. UDAT_REL_UNIT_WEEK, UDAT_REL_UNIT_FRIDAY. + * @param result + * A pointer to a buffer to receive the formatted result. + * @param resultCapacity + * The maximum size of result. + * @param status + * A pointer to a UErrorCode to receive any errors. In + * case of error status, the contents of result are + * undefined. + * @return + * The length of the formatted result; may be greater + * than resultCapacity, in which case an error is returned. + * @draft ICU 57 + */ +U_DRAFT int32_t U_EXPORT2 +ureldatefmt_formatNumeric( const URelativeDateTimeFormatter* reldatefmt, + double offset, + URelativeDateTimeUnit unit, + UChar* result, + int32_t resultCapacity, + UErrorCode* status); + +/** + * Format a combination of URelativeDateTimeUnit and numeric offset + * using a text style if possible, e.g. "last week", "this week", + * "next week", "yesterday", "tomorrow". Falls back to numeric + * style if no appropriate text term is available for the specified + * offset in the object’s locale. + * + * @param reldatefmt + * The URelativeDateTimeFormatter object specifying the + * format conventions. + * @param offset + * The signed offset for the specified unit. + * @param unit + * The unit to use when formatting the relative + * date, e.g. UDAT_REL_UNIT_WEEK, UDAT_REL_UNIT_FRIDAY. + * @param result + * A pointer to a buffer to receive the formatted result. + * @param resultCapacity + * The maximum size of result. + * @param status + * A pointer to a UErrorCode to receive any errors. In + * case of error status, the contents of result are + * undefined. + * @return + * The length of the formatted result; may be greater + * than resultCapacity, in which case an error is returned. + * @draft ICU 57 + */ +U_DRAFT int32_t U_EXPORT2 +ureldatefmt_format( const URelativeDateTimeFormatter* reldatefmt, + double offset, + URelativeDateTimeUnit unit, + UChar* result, + int32_t resultCapacity, + UErrorCode* status); + +/** + * Combines a relative date string and a time string in this object's + * locale. This is done with the same date-time separator used for the + * default calendar in this locale to produce a result such as + * "yesterday at 3:45 PM". + * + * @param reldatefmt + * The URelativeDateTimeFormatter object specifying the format conventions. + * @param relativeDateString + * The relative date string. + * @param relativeDateStringLen + * The length of relativeDateString; may be -1 if relativeDateString + * is zero-terminated. + * @param timeString + * The time string. + * @param timeStringLen + * The length of timeString; may be -1 if timeString is zero-terminated. + * @param result + * A pointer to a buffer to receive the formatted result. + * @param resultCapacity + * The maximum size of result. + * @param status + * A pointer to a UErrorCode to receive any errors. In case of error status, + * the contents of result are undefined. + * @return + * The length of the formatted result; may be greater than resultCapacity, + * in which case an error is returned. + * @draft ICU 57 + */ +U_DRAFT int32_t U_EXPORT2 +ureldatefmt_combineDateAndTime( const URelativeDateTimeFormatter* reldatefmt, + const UChar * relativeDateString, + int32_t relativeDateStringLen, + const UChar * timeString, + int32_t timeStringLen, + UChar* result, + int32_t resultCapacity, + UErrorCode* status ); + +#endif /* U_HIDE_DRAFT_API */ + +#endif /* !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION */ + +#endif diff --git a/icu4c/source/test/cintltst/Makefile.in b/icu4c/source/test/cintltst/Makefile.in index b15274ca755..e19874f74fb 100644 --- a/icu4c/source/test/cintltst/Makefile.in +++ b/icu4c/source/test/cintltst/Makefile.in @@ -1,6 +1,6 @@ #****************************************************************************** # -# Copyright (C) 1999-2015, International Business Machines +# Copyright (C) 1999-2016, International Business Machines # Corporation and others. All Rights Reserved. # #****************************************************************************** @@ -42,7 +42,7 @@ ccaltst.o ucnvseltst.o cctest.o ccapitst.o ccolltst.o encoll.o cconvtst.o ccurrt cdateintervalformattest.o cdattst.o cdetst.o cdtdptst.o cdtrgtst.o cestst.o cfintst.o \ cformtst.o cfrtst.o cg7coll.o chashtst.o cintltst.o citertst.o cjaptst.o cloctst.o \ cmsccoll.o cmsgtst.o cpluralrulestest.o cposxtst.o cldrtest.o \ -cnmdptst.o cnormtst.o cnumtst.o crestst.o creststn.o cturtst.o \ +cnmdptst.o cnormtst.o cnumtst.o crelativedateformattest.o crestst.o creststn.o cturtst.o \ cucdapi.o cucdtst.o custrtst.o cstrcase.o cutiltst.o nucnvtst.o nccbtst.o bocu1tst.o \ cbiditst.o cbididat.o eurocreg.o udatatst.o utf16tst.o utransts.o \ ncnvfbts.o ncnvtst.o putiltst.o cstrtest.o udatpg_test.o utf8tst.o \ diff --git a/icu4c/source/test/cintltst/cformtst.c b/icu4c/source/test/cintltst/cformtst.c index bf8d4018695..4fe5c0f7697 100644 --- a/icu4c/source/test/cintltst/cformtst.c +++ b/icu4c/source/test/cintltst/cformtst.c @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2015, International Business Machines + * Copyright (c) 1997-2016, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************/ /******************************************************************************** @@ -26,6 +26,7 @@ void addCalTest(TestNode**); void addDateForTest(TestNode**); void addDateTimePatternGeneratorTest(TestNode**); void addDateIntervalFormatTest(TestNode**); +void addRelativeDateFormatTest(TestNode**); void addNumForTest(TestNode**); void addMsgForTest(TestNode**); void addDateForRgrTest(TestNode**); @@ -45,6 +46,7 @@ void addFormatTest(TestNode** root) addDateForTest(root); addDateTimePatternGeneratorTest(root); addDateIntervalFormatTest(root); + addRelativeDateFormatTest(root); addNumForTest(root); addNumFrDepTest(root); addMsgForTest(root); diff --git a/icu4c/source/test/cintltst/cintltst.vcxproj b/icu4c/source/test/cintltst/cintltst.vcxproj index 33b93b9b320..07943e8df6a 100644 --- a/icu4c/source/test/cintltst/cintltst.vcxproj +++ b/icu4c/source/test/cintltst/cintltst.vcxproj @@ -287,6 +287,7 @@ + diff --git a/icu4c/source/test/cintltst/cintltst.vcxproj.filters b/icu4c/source/test/cintltst/cintltst.vcxproj.filters index 95e48ed2c31..b8a340e76c9 100644 --- a/icu4c/source/test/cintltst/cintltst.vcxproj.filters +++ b/icu4c/source/test/cintltst/cintltst.vcxproj.filters @@ -198,6 +198,9 @@ formatting + + formatting + formatting diff --git a/icu4c/source/test/cintltst/crelativedateformattest.c b/icu4c/source/test/cintltst/crelativedateformattest.c new file mode 100644 index 00000000000..f0ef247f57a --- /dev/null +++ b/icu4c/source/test/cintltst/crelativedateformattest.c @@ -0,0 +1,111 @@ +/******************************************************************** + * Copyright (c) 2016, International Business Machines Corporation + * and others. All Rights Reserved. + ********************************************************************/ +/* C API TEST FOR DATE INTERVAL FORMAT */ + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION + +#include "unicode/ureldatefmt.h" +#include "unicode/unum.h" +#include "unicode/udisplaycontext.h" +#include "unicode/ustring.h" +#include "cintltst.h" +#include "cmemory.h" + +static void TestRelDateFmtx(void); + +#define LEN(a) (sizeof(a)/sizeof(a[0])) + +void addRelativeDateFormatTest(TestNode** root); + +#define TESTCASE(x) addTest(root, &x, "tsformat/crelativedateformattest/" #x) + +void addRelativeDateFormatTest(TestNode** root) +{ + TESTCASE(TestRelDateFmtx); +} + +static const double offsets[] = { -5.0, -2.2, -1.0, -0.7, 0.0, 0.7, 1.0, 2.2, 5.0 }; +enum { kNumOffsets = UPRV_LENGTHOF(offsets) }; + +static const char* en_defNum_long_midSent_week[kNumOffsets*2] = { +/* text numeric */ + "5 weeks ago", "5 weeks ago", + "2.2 weeks ago", "2.2 weeks ago", + "last week", "1 week ago", + "last week", "0.7 weeks ago", + "this week", "in 0 weeks", + "next week", "in 0.7 weeks", + "next week", "in 1 week", + "in 2.2 weeks", "in 2.2 weeks", + "in 5 weeks", "in 5 weeks", +}; + +typedef struct { + const char* locale; + int32_t decPlaces; /* fixed decimal places; -1 to use default num formatter */ + UDateRelativeDateTimeFormatterStyle width; + UDisplayContext capContext; + URelativeDateTimeUnit unit; + const char ** expectedResults; /* for the various offsets */ +} RelDateTimeFormatTestItem; + +static const RelDateTimeFormatTestItem testItems[] = { + { "en", -1, UDAT_STYLE_LONG, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDAT_REL_UNIT_WEEK, en_defNum_long_midSent_week }, + { NULL, 0, (UDateRelativeDateTimeFormatterStyle)0, (UDisplayContext)0, (URelativeDateTimeUnit)0, NULL } /* terminator */ +}; + +enum { kMaxUBuf = 64 }; + +static void TestRelDateFmtx() +{ + const RelDateTimeFormatTestItem *itemPtr; + log_verbose("\nTesting ureldatefmt_open(), ureldatefmt_format(), ureldatefmt_formatNumeric() with various parameters\n"); + for (itemPtr = testItems; itemPtr->locale != NULL; itemPtr++) { + URelativeDateTimeFormatter *reldatefmt = NULL; + UNumberFormat* nfToAdopt = NULL; + UErrorCode status = U_ZERO_ERROR; + int32_t iOffset; + + if (itemPtr->decPlaces >= 0) { + nfToAdopt = unum_open(UNUM_DECIMAL, NULL, 0, itemPtr->locale, NULL, &status); + if ( U_FAILURE(status) ) { + log_data_err("FAIL: unum_open(UNUM_DECIMAL, ...) for locale %s: %s\n", itemPtr->locale, myErrorName(status)); + } + unum_setAttribute(nfToAdopt, UNUM_MIN_FRACTION_DIGITS, itemPtr->decPlaces); + unum_setAttribute(nfToAdopt, UNUM_MAX_FRACTION_DIGITS, itemPtr->decPlaces); + unum_setAttribute(nfToAdopt, UNUM_ROUNDING_MODE, UNUM_ROUND_DOWN); + } + reldatefmt = ureldatefmt_open(itemPtr->locale, nfToAdopt, itemPtr->width, itemPtr->capContext, &status); + if ( U_FAILURE(status) ) { + log_data_err("FAIL: ureldatefmt_open() for locale %s: %s\n", itemPtr->locale, myErrorName(status)); + } + + for (iOffset = 0; iOffset < kNumOffsets; iOffset++) { + UChar ubuf[kMaxUBuf]; + int32_t ulen; + + status = U_ZERO_ERROR; + ulen = ureldatefmt_format(reldatefmt, offsets[iOffset], itemPtr->unit, ubuf, kMaxUBuf, &status); + /* check results */ + + status = U_ZERO_ERROR; + ulen = ureldatefmt_formatNumeric(reldatefmt, offsets[iOffset], itemPtr->unit, ubuf, kMaxUBuf, &status); + /* check results */ + } + + ureldatefmt_close(reldatefmt); + } + + +/* +log_err("ERROR: udtitvfmt_format for locale %s, skeleton %s, tzid %s, from %.1f, to %.1f: expect %s, get %s\n", +log_err("FAIL: udtitvfmt_format for locale %s, skeleton %s, tzid %s, from %.1f, to %.1f: %s\n", +log_data_err("FAIL: udtitvfmt_open for locale %s, skeleton %s, tzid %s - %s\n", +*/ +} + +#endif /* #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION */