Index: source/i18n/reldatefmt.cpp |
diff --git a/source/i18n/reldatefmt.cpp b/source/i18n/reldatefmt.cpp |
index 4d8ca06f98a75242475ee71953ea2050fbd2929d..dd4894e95e2e4b6b97d10521c5c1ffa23bff70dc 100644 |
--- a/source/i18n/reldatefmt.cpp |
+++ b/source/i18n/reldatefmt.cpp |
@@ -1,6 +1,8 @@ |
+// Copyright (C) 2016 and later: Unicode, Inc. and others. |
+// License & terms of use: http://www.unicode.org/copyright.html |
/* |
****************************************************************************** |
-* Copyright (C) 2014-2015, International Business Machines Corporation and |
+* Copyright (C) 2014-2016, International Business Machines Corporation and |
* others. All Rights Reserved. |
****************************************************************************** |
* |
@@ -12,13 +14,17 @@ |
#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION |
+#include "unicode/dtfmtsym.h" |
+#include "unicode/ureldatefmt.h" |
+#include "unicode/udisplaycontext.h" |
+#include "unicode/unum.h" |
#include "unicode/localpointer.h" |
-#include "quantityformatter.h" |
#include "unicode/plurrule.h" |
-#include "unicode/msgfmt.h" |
+#include "unicode/simpleformatter.h" |
#include "unicode/decimfmt.h" |
#include "unicode/numfmt.h" |
#include "unicode/brkiter.h" |
+#include "unicode/simpleformatter.h" |
#include "uresimp.h" |
#include "unicode/ures.h" |
#include "cstring.h" |
@@ -26,10 +32,12 @@ |
#include "mutex.h" |
#include "charstr.h" |
#include "uassert.h" |
- |
+#include "quantityformatter.h" |
+#include "resource.h" |
#include "sharedbreakiterator.h" |
#include "sharedpluralrules.h" |
#include "sharednumberformat.h" |
+#include "standardplural.h" |
#include "unifiedcache.h" |
// Copied from uscript_props.cpp |
@@ -41,65 +49,110 @@ U_NAMESPACE_BEGIN |
// RelativeDateTimeFormatter specific data for a single locale |
class RelativeDateTimeCacheData: public SharedObject { |
public: |
- RelativeDateTimeCacheData() : combinedDateAndTime(NULL) { } |
+ RelativeDateTimeCacheData() : combinedDateAndTime(NULL) { |
+ // Initialize the cache arrays |
+ for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) { |
+ for (int32_t relUnit = 0; relUnit < UDAT_RELATIVE_UNIT_COUNT; ++relUnit) { |
+ for (int32_t pl = 0; pl < StandardPlural::COUNT; ++pl) { |
+ relativeUnitsFormatters[style][relUnit][0][pl] = NULL; |
+ relativeUnitsFormatters[style][relUnit][1][pl] = NULL; |
+ } |
+ } |
+ } |
+ for (int32_t i = 0; i < UDAT_STYLE_COUNT; ++i) { |
+ fallBackCache[i] = -1; |
+ } |
+ } |
virtual ~RelativeDateTimeCacheData(); |
// no numbers: e.g Next Tuesday; Yesterday; etc. |
UnicodeString absoluteUnits[UDAT_STYLE_COUNT][UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT]; |
- // has numbers: e.g Next Tuesday; Yesterday; etc. For second index, 0 |
- // means past e.g 5 days ago; 1 means future e.g in 5 days. |
- QuantityFormatter relativeUnits[UDAT_STYLE_COUNT][UDAT_RELATIVE_UNIT_COUNT][2]; |
+ // SimpleFormatter pointers for relative unit format, |
+ // e.g., Next Tuesday; Yesterday; etc. For third index, 0 |
+ // means past, e.g., 5 days ago; 1 means future, e.g., in 5 days. |
+ SimpleFormatter *relativeUnitsFormatters[UDAT_STYLE_COUNT] |
+ [UDAT_RELATIVE_UNIT_COUNT][2][StandardPlural::COUNT]; |
+ |
+ const UnicodeString& getAbsoluteUnitString(int32_t fStyle, |
+ UDateAbsoluteUnit unit, |
+ UDateDirection direction) const; |
+ const SimpleFormatter* getRelativeUnitFormatter(int32_t fStyle, |
+ UDateRelativeUnit unit, |
+ int32_t pastFutureIndex, |
+ int32_t pluralUnit) const; |
+ |
+ const UnicodeString emptyString; |
+ |
+ // Mappping from source to target styles for alias fallback. |
+ int32_t fallBackCache[UDAT_STYLE_COUNT]; |
- void adoptCombinedDateAndTime(MessageFormat *mfToAdopt) { |
+ void adoptCombinedDateAndTime(SimpleFormatter *fmtToAdopt) { |
delete combinedDateAndTime; |
- combinedDateAndTime = mfToAdopt; |
+ combinedDateAndTime = fmtToAdopt; |
} |
- const MessageFormat *getCombinedDateAndTime() const { |
+ const SimpleFormatter *getCombinedDateAndTime() const { |
return combinedDateAndTime; |
} |
+ |
private: |
- MessageFormat *combinedDateAndTime; |
+ SimpleFormatter *combinedDateAndTime; |
RelativeDateTimeCacheData(const RelativeDateTimeCacheData &other); |
RelativeDateTimeCacheData& operator=( |
const RelativeDateTimeCacheData &other); |
}; |
RelativeDateTimeCacheData::~RelativeDateTimeCacheData() { |
+ // clear out the cache arrays |
+ for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) { |
+ for (int32_t relUnit = 0; relUnit < UDAT_RELATIVE_UNIT_COUNT; ++relUnit) { |
+ for (int32_t pl = 0; pl < StandardPlural::COUNT; ++pl) { |
+ delete relativeUnitsFormatters[style][relUnit][0][pl]; |
+ delete relativeUnitsFormatters[style][relUnit][1][pl]; |
+ } |
+ } |
+ } |
delete combinedDateAndTime; |
} |
-static UBool getStringWithFallback( |
- const UResourceBundle *resource, |
- const char *key, |
- UnicodeString &result, |
- UErrorCode &status) { |
- int32_t len = 0; |
- const UChar *resStr = ures_getStringByKeyWithFallback( |
- resource, key, &len, &status); |
- if (U_FAILURE(status)) { |
- return FALSE; |
- } |
- result.setTo(TRUE, resStr, len); |
- return TRUE; |
+ |
+// Use fallback cache for absolute units. |
+const UnicodeString& RelativeDateTimeCacheData::getAbsoluteUnitString( |
+ int32_t fStyle, UDateAbsoluteUnit unit, UDateDirection direction) const { |
+ int32_t style = fStyle; |
+ do { |
+ if (!absoluteUnits[style][unit][direction].isEmpty()) { |
+ return absoluteUnits[style][unit][direction]; |
+ } |
+ style = fallBackCache[style]; |
+ } while (style != -1); |
+ return emptyString; |
} |
-static UBool getOptionalStringWithFallback( |
- const UResourceBundle *resource, |
+ // Use fallback cache for SimpleFormatter relativeUnits. |
+ const SimpleFormatter* RelativeDateTimeCacheData::getRelativeUnitFormatter( |
+ int32_t fStyle, |
+ UDateRelativeUnit unit, |
+ int32_t pastFutureIndex, |
+ int32_t pluralUnit) const { |
+ int32_t style = fStyle; |
+ do { |
+ if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != NULL) { |
+ return relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit]; |
+ } |
+ style = fallBackCache[style]; |
+ } while (style != -1); |
+ return NULL; // No formatter found. |
+ } |
+ |
+static UBool getStringWithFallback( |
+ const UResourceBundle *resource, |
const char *key, |
UnicodeString &result, |
UErrorCode &status) { |
- if (U_FAILURE(status)) { |
- return FALSE; |
- } |
int32_t len = 0; |
- const UChar *resStr = ures_getStringByKey( |
+ const UChar *resStr = ures_getStringByKeyWithFallback( |
resource, key, &len, &status); |
- if (status == U_MISSING_RESOURCE_ERROR) { |
- result.remove(); |
- status = U_ZERO_ERROR; |
- return TRUE; |
- } |
if (U_FAILURE(status)) { |
return FALSE; |
} |
@@ -107,21 +160,9 @@ static UBool getOptionalStringWithFallback( |
return TRUE; |
} |
-static UBool getString( |
- const UResourceBundle *resource, |
- UnicodeString &result, |
- UErrorCode &status) { |
- int32_t len = 0; |
- const UChar *resStr = ures_getString(resource, &len, &status); |
- if (U_FAILURE(status)) { |
- return FALSE; |
- } |
- result.setTo(TRUE, resStr, len); |
- return TRUE; |
-} |
static UBool getStringByIndex( |
- const UResourceBundle *resource, |
+ const UResourceBundle *resource, |
int32_t idx, |
UnicodeString &result, |
UErrorCode &status) { |
@@ -135,452 +176,426 @@ static UBool getStringByIndex( |
return TRUE; |
} |
-static void initAbsoluteUnit( |
- const UResourceBundle *resource, |
- const UnicodeString &unitName, |
- UnicodeString *absoluteUnit, |
- UErrorCode &status) { |
- getStringWithFallback( |
- resource, |
- "-1", |
- absoluteUnit[UDAT_DIRECTION_LAST], |
- status); |
- getStringWithFallback( |
- resource, |
- "0", |
- absoluteUnit[UDAT_DIRECTION_THIS], |
- status); |
- getStringWithFallback( |
- resource, |
- "1", |
- absoluteUnit[UDAT_DIRECTION_NEXT], |
- status); |
- getOptionalStringWithFallback( |
- resource, |
- "-2", |
- absoluteUnit[UDAT_DIRECTION_LAST_2], |
- status); |
- getOptionalStringWithFallback( |
- resource, |
- "2", |
- absoluteUnit[UDAT_DIRECTION_NEXT_2], |
- status); |
- absoluteUnit[UDAT_DIRECTION_PLAIN] = unitName; |
-} |
+namespace { |
-static void initQuantityFormatter( |
- const UResourceBundle *resource, |
- QuantityFormatter &formatter, |
- UErrorCode &status) { |
- if (U_FAILURE(status)) { |
- return; |
+/** |
+ * Sink for enumerating all of the measurement unit display names. |
+ * |
+ * More specific bundles (en_GB) are enumerated before their parents (en_001, en, root): |
+ * Only store a value if it is still missing, that is, it has not been overridden. |
+ */ |
+struct RelDateTimeFmtDataSink : public ResourceSink { |
+ |
+ /** |
+ * Sink for patterns for relative dates and times. For example, |
+ * fields/relative/... |
+ */ |
+ |
+ // Generic unit enum for storing Unit info. |
+ typedef enum RelAbsUnit { |
+ INVALID_UNIT = -1, |
+ SECOND, |
+ MINUTE, |
+ HOUR, |
+ DAY, |
+ WEEK, |
+ MONTH, |
+ QUARTER, |
+ YEAR, |
+ SUNDAY, |
+ MONDAY, |
+ TUESDAY, |
+ WEDNESDAY, |
+ THURSDAY, |
+ FRIDAY, |
+ SATURDAY |
+ } RelAbsUnit; |
+ |
+ static int32_t relUnitFromGeneric(RelAbsUnit genUnit) { |
+ // Converts the generic units to UDAT_RELATIVE version. |
+ switch (genUnit) { |
+ case SECOND: |
+ return UDAT_RELATIVE_SECONDS; |
+ case MINUTE: |
+ return UDAT_RELATIVE_MINUTES; |
+ case HOUR: |
+ return UDAT_RELATIVE_HOURS; |
+ case DAY: |
+ return UDAT_RELATIVE_DAYS; |
+ case WEEK: |
+ return UDAT_RELATIVE_WEEKS; |
+ case MONTH: |
+ return UDAT_RELATIVE_MONTHS; |
+ /* |
+ * case QUARTER: |
+ * return UDATE_RELATIVE_QUARTERS; |
+ */ |
+ case YEAR: |
+ return UDAT_RELATIVE_YEARS; |
+ default: |
+ return -1; |
+ } |
} |
- int32_t size = ures_getSize(resource); |
- for (int32_t i = 0; i < size; ++i) { |
- LocalUResourceBundlePointer pluralBundle( |
- ures_getByIndex(resource, i, NULL, &status)); |
- if (U_FAILURE(status)) { |
- return; |
+ |
+ static int32_t absUnitFromGeneric(RelAbsUnit genUnit) { |
+ // Converts the generic units to UDAT_RELATIVE version. |
+ switch (genUnit) { |
+ case DAY: |
+ return UDAT_ABSOLUTE_DAY; |
+ case WEEK: |
+ return UDAT_ABSOLUTE_WEEK; |
+ case MONTH: |
+ return UDAT_ABSOLUTE_MONTH; |
+ /* TODO: Add in QUARTER |
+ * case QUARTER: |
+ * return UDAT_ABSOLUTE_QUARTER; |
+ */ |
+ case YEAR: |
+ return UDAT_ABSOLUTE_YEAR; |
+ case SUNDAY: |
+ return UDAT_ABSOLUTE_SUNDAY; |
+ case MONDAY: |
+ return UDAT_ABSOLUTE_MONDAY; |
+ case TUESDAY: |
+ return UDAT_ABSOLUTE_TUESDAY; |
+ case WEDNESDAY: |
+ return UDAT_ABSOLUTE_WEDNESDAY; |
+ case THURSDAY: |
+ return UDAT_ABSOLUTE_THURSDAY; |
+ case FRIDAY: |
+ return UDAT_ABSOLUTE_FRIDAY; |
+ case SATURDAY: |
+ return UDAT_ABSOLUTE_SATURDAY; |
+ default: |
+ return -1; |
} |
- UnicodeString rawPattern; |
- if (!getString(pluralBundle.getAlias(), rawPattern, status)) { |
- return; |
+ } |
+ |
+ static int32_t keyToDirection(const char* key) { |
+ if (uprv_strcmp(key, "-2") == 0) { |
+ return UDAT_DIRECTION_LAST_2; |
} |
- if (!formatter.addIfAbsent( |
- ures_getKey(pluralBundle.getAlias()), |
- rawPattern, |
- status)) { |
- return; |
+ if (uprv_strcmp(key, "-1") == 0) { |
+ return UDAT_DIRECTION_LAST; |
} |
+ if (uprv_strcmp(key, "0") == 0) { |
+ return UDAT_DIRECTION_THIS; |
+ } |
+ if (uprv_strcmp(key, "1") == 0) { |
+ return UDAT_DIRECTION_NEXT; |
+ } |
+ if (uprv_strcmp(key, "2") == 0) { |
+ return UDAT_DIRECTION_NEXT_2; |
+ } |
+ return -1; |
} |
-} |
-static void initRelativeUnit( |
- const UResourceBundle *resource, |
- QuantityFormatter *relativeUnit, |
- UErrorCode &status) { |
- LocalUResourceBundlePointer topLevel( |
- ures_getByKeyWithFallback( |
- resource, "relativeTime", NULL, &status)); |
- if (U_FAILURE(status)) { |
- return; |
- } |
- LocalUResourceBundlePointer futureBundle(ures_getByKeyWithFallback( |
- topLevel.getAlias(), "future", NULL, &status)); |
- if (U_FAILURE(status)) { |
- return; |
- } |
- initQuantityFormatter( |
- futureBundle.getAlias(), |
- relativeUnit[1], |
- status); |
- LocalUResourceBundlePointer pastBundle(ures_getByKeyWithFallback( |
- topLevel.getAlias(), "past", NULL, &status)); |
- if (U_FAILURE(status)) { |
- return; |
- } |
- initQuantityFormatter( |
- pastBundle.getAlias(), |
- relativeUnit[0], |
- status); |
-} |
+ // Values kept between levels of parsing the CLDR data. |
+ int32_t pastFutureIndex; // 0 == past or 1 == future |
+ UDateRelativeDateTimeFormatterStyle style; // {LONG, SHORT, NARROW} |
+ RelAbsUnit genericUnit; |
-static void initRelativeUnit( |
- const UResourceBundle *resource, |
- const char *path, |
- QuantityFormatter *relativeUnit, |
- UErrorCode &status) { |
- LocalUResourceBundlePointer topLevel( |
- ures_getByKeyWithFallback(resource, path, NULL, &status)); |
- if (U_FAILURE(status)) { |
- return; |
- } |
- initRelativeUnit(topLevel.getAlias(), relativeUnit, status); |
-} |
+ RelativeDateTimeCacheData &outputData; |
-static void addTimeUnit( |
- const UResourceBundle *resource, |
- const char *path, |
- QuantityFormatter *relativeUnit, |
- UnicodeString *absoluteUnit, |
- UErrorCode &status) { |
- LocalUResourceBundlePointer topLevel( |
- ures_getByKeyWithFallback(resource, path, NULL, &status)); |
- if (U_FAILURE(status)) { |
- return; |
+ // Constructor |
+ RelDateTimeFmtDataSink(RelativeDateTimeCacheData& cacheData) |
+ : outputData(cacheData) { |
+ // Clear cacheData.fallBackCache |
+ cacheData.fallBackCache[UDAT_STYLE_LONG] = -1; |
+ cacheData.fallBackCache[UDAT_STYLE_SHORT] = -1; |
+ cacheData.fallBackCache[UDAT_STYLE_NARROW] = -1; |
} |
- initRelativeUnit(topLevel.getAlias(), relativeUnit, status); |
- UnicodeString unitName; |
- if (!getStringWithFallback(topLevel.getAlias(), "dn", unitName, status)) { |
- return; |
- } |
- // TODO(Travis Keep): This is a hack to get around CLDR bug 6818. |
- const char *localeId = ures_getLocaleByType( |
- topLevel.getAlias(), ULOC_ACTUAL_LOCALE, &status); |
- if (U_FAILURE(status)) { |
- return; |
- } |
- Locale locale(localeId); |
- if (uprv_strcmp("en", locale.getLanguage()) == 0) { |
- unitName.toLower(); |
+ |
+ ~RelDateTimeFmtDataSink(); |
+ |
+ // Utility functions |
+ static UDateRelativeDateTimeFormatterStyle styleFromString(const char *s) { |
+ int32_t len = uprv_strlen(s); |
+ if (len >= 7 && uprv_strcmp(s + len - 7, "-narrow") == 0) { |
+ return UDAT_STYLE_NARROW; |
+ } |
+ if (len >= 6 && uprv_strcmp(s + len - 6, "-short") == 0) { |
+ return UDAT_STYLE_SHORT; |
+ } |
+ return UDAT_STYLE_LONG; |
} |
- // end hack |
- ures_getByKeyWithFallback( |
- topLevel.getAlias(), "relative", topLevel.getAlias(), &status); |
- if (U_FAILURE(status)) { |
- return; |
+ |
+ static int32_t styleSuffixLength(UDateRelativeDateTimeFormatterStyle style) { |
+ switch (style) { |
+ case UDAT_STYLE_NARROW: |
+ return 7; |
+ case UDAT_STYLE_SHORT: |
+ return 6; |
+ default: |
+ return 0; |
+ } |
} |
- initAbsoluteUnit( |
- topLevel.getAlias(), |
- unitName, |
- absoluteUnit, |
- status); |
-} |
-static void readDaysOfWeek( |
- const UResourceBundle *resource, |
- const char *path, |
- UnicodeString *daysOfWeek, |
- UErrorCode &status) { |
- LocalUResourceBundlePointer topLevel( |
- ures_getByKeyWithFallback(resource, path, NULL, &status)); |
- if (U_FAILURE(status)) { |
- return; |
+ // Utility functions |
+ static UDateRelativeDateTimeFormatterStyle styleFromAliasUnicodeString(UnicodeString s) { |
+ static const UChar narrow[7] = {0x002D, 0x006E, 0x0061, 0x0072, 0x0072, 0x006F, 0x0077}; |
+ static const UChar sshort[6] = {0x002D, 0x0073, 0x0068, 0x006F, 0x0072, 0x0074,}; |
+ if (s.endsWith(narrow, 7)) { |
+ return UDAT_STYLE_NARROW; |
+ } |
+ if (s.endsWith(sshort, 6)) { |
+ return UDAT_STYLE_SHORT; |
+ } |
+ return UDAT_STYLE_LONG; |
} |
- int32_t size = ures_getSize(topLevel.getAlias()); |
- if (size != 7) { |
- status = U_INTERNAL_PROGRAM_ERROR; |
- return; |
+ |
+ static RelAbsUnit unitOrNegativeFromString(const char* keyword, int32_t length) { |
+ // Quick check from string to enum. |
+ switch (length) { |
+ case 3: |
+ if (uprv_strncmp(keyword, "day", length) == 0) { |
+ return DAY; |
+ } else if (uprv_strncmp(keyword, "sun", length) == 0) { |
+ return SUNDAY; |
+ } else if (uprv_strncmp(keyword, "mon", length) == 0) { |
+ return MONDAY; |
+ } else if (uprv_strncmp(keyword, "tue", length) == 0) { |
+ return TUESDAY; |
+ } else if (uprv_strncmp(keyword, "wed", length) == 0) { |
+ return WEDNESDAY; |
+ } else if (uprv_strncmp(keyword, "thu", length) == 0) { |
+ return THURSDAY; |
+ } else if (uprv_strncmp(keyword, "fri", length) == 0) { |
+ return FRIDAY; |
+ } else if (uprv_strncmp(keyword, "sat", length) == 0) { |
+ return SATURDAY; |
+ } |
+ break; |
+ case 4: |
+ if (uprv_strncmp(keyword, "hour", length) == 0) { |
+ return HOUR; |
+ } else if (uprv_strncmp(keyword, "week", length) == 0) { |
+ return WEEK; |
+ } else if (uprv_strncmp(keyword, "year", length) == 0) { |
+ return YEAR; |
+ } |
+ break; |
+ case 5: |
+ if (uprv_strncmp(keyword, "month", length) == 0) { |
+ return MONTH; |
+ } |
+ break; |
+ case 6: |
+ if (uprv_strncmp(keyword, "minute", length) == 0) { |
+ return MINUTE; |
+ } else if (uprv_strncmp(keyword, "second", length) == 0) { |
+ return SECOND; |
+ } |
+ break; |
+ case 7: |
+ if (uprv_strncmp(keyword, "quarter", length) == 0) { |
+ return QUARTER; // TODO: Check @provisional |
+ } |
+ break; |
+ default: |
+ break; |
+ } |
+ return INVALID_UNIT; |
} |
- for (int32_t i = 0; i < size; ++i) { |
- if (!getStringByIndex(topLevel.getAlias(), i, daysOfWeek[i], status)) { |
+ |
+ void handlePlainDirection(ResourceValue &value, UErrorCode &errorCode) { |
+ // Handle Display Name for PLAIN direction for some units. |
+ if (U_FAILURE(errorCode)) { return; } |
+ |
+ int32_t absUnit = absUnitFromGeneric(genericUnit); |
+ if (absUnit < 0) { |
+ return; // Not interesting. |
+ } |
+ |
+ // Store displayname if not set. |
+ if (outputData.absoluteUnits[style] |
+ [absUnit][UDAT_DIRECTION_PLAIN].isEmpty()) { |
+ outputData.absoluteUnits[style] |
+ [absUnit][UDAT_DIRECTION_PLAIN].fastCopyFrom(value.getUnicodeString(errorCode)); |
return; |
} |
} |
-} |
-static void addWeekDay( |
- const UResourceBundle *resource, |
- const char *path, |
- const UnicodeString *daysOfWeek, |
- UDateAbsoluteUnit absoluteUnit, |
- UnicodeString absoluteUnits[][UDAT_DIRECTION_COUNT], |
- UErrorCode &status) { |
- LocalUResourceBundlePointer topLevel( |
- ures_getByKeyWithFallback(resource, path, NULL, &status)); |
- if (U_FAILURE(status)) { |
- return; |
+ void consumeTableRelative(const char *key, ResourceValue &value, UErrorCode &errorCode) { |
+ ResourceTable unitTypesTable = value.getTable(errorCode); |
+ if (U_FAILURE(errorCode)) { return; } |
+ |
+ for (int32_t i = 0; unitTypesTable.getKeyAndValue(i, key, value); ++i) { |
+ if (value.getType() == URES_STRING) { |
+ int32_t direction = keyToDirection(key); |
+ if (direction < 0) { |
+ continue; |
+ } |
+ |
+ int32_t relUnitIndex = relUnitFromGeneric(genericUnit); |
+ if (relUnitIndex == UDAT_RELATIVE_SECONDS && uprv_strcmp(key, "0") == 0 && |
+ outputData.absoluteUnits[style][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN].isEmpty()) { |
+ // Handle "NOW" |
+ outputData.absoluteUnits[style][UDAT_ABSOLUTE_NOW] |
+ [UDAT_DIRECTION_PLAIN].fastCopyFrom(value.getUnicodeString(errorCode)); |
+ } |
+ |
+ int32_t absUnitIndex = absUnitFromGeneric(genericUnit); |
+ if (absUnitIndex < 0) { |
+ continue; |
+ } |
+ // Only reset if slot is empty. |
+ if (outputData.absoluteUnits[style][absUnitIndex][direction].isEmpty()) { |
+ outputData.absoluteUnits[style][absUnitIndex] |
+ [direction].fastCopyFrom(value.getUnicodeString(errorCode)); |
+ } |
+ } |
+ } |
} |
- initAbsoluteUnit( |
- topLevel.getAlias(), |
- daysOfWeek[absoluteUnit - UDAT_ABSOLUTE_SUNDAY], |
- absoluteUnits[absoluteUnit], |
- status); |
-} |
-static void addTimeUnits( |
- const UResourceBundle *resource, |
- const char *path, const char *pathShort, const char *pathNarrow, |
- UDateRelativeUnit relativeUnit, |
- UDateAbsoluteUnit absoluteUnit, |
- RelativeDateTimeCacheData &cacheData, |
- UErrorCode &status) { |
- addTimeUnit( |
- resource, |
- path, |
- cacheData.relativeUnits[UDAT_STYLE_LONG][relativeUnit], |
- cacheData.absoluteUnits[UDAT_STYLE_LONG][absoluteUnit], |
- status); |
- addTimeUnit( |
- resource, |
- pathShort, |
- cacheData.relativeUnits[UDAT_STYLE_SHORT][relativeUnit], |
- cacheData.absoluteUnits[UDAT_STYLE_SHORT][absoluteUnit], |
- status); |
- if (U_FAILURE(status)) { |
- return; |
+ void consumeTimeDetail(int32_t relUnitIndex, |
+ const char *key, ResourceValue &value, UErrorCode &errorCode) { |
+ ResourceTable unitTypesTable = value.getTable(errorCode); |
+ if (U_FAILURE(errorCode)) { return; } |
+ |
+ for (int32_t i = 0; unitTypesTable.getKeyAndValue(i, key, value); ++i) { |
+ if (value.getType() == URES_STRING) { |
+ int32_t pluralIndex = StandardPlural::indexOrNegativeFromString(key); |
+ if (pluralIndex >= 0) { |
+ SimpleFormatter **patterns = |
+ outputData.relativeUnitsFormatters[style][relUnitIndex] |
+ [pastFutureIndex]; |
+ // Only set if not already established. |
+ if (patterns[pluralIndex] == NULL) { |
+ patterns[pluralIndex] = new SimpleFormatter( |
+ value.getUnicodeString(errorCode), 0, 1, errorCode); |
+ if (patterns[pluralIndex] == NULL) { |
+ errorCode = U_MEMORY_ALLOCATION_ERROR; |
+ } |
+ } |
+ } |
+ } |
+ } |
} |
- addTimeUnit( |
- resource, |
- pathNarrow, |
- cacheData.relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
- cacheData.absoluteUnits[UDAT_STYLE_NARROW][absoluteUnit], |
- status); |
- if (status == U_MISSING_RESOURCE_ERROR) { |
- // retry addTimeUnit for UDAT_STYLE_NARROW using pathShort |
- status = U_ZERO_ERROR; |
- addTimeUnit( |
- resource, |
- pathShort, |
- cacheData.relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
- cacheData.absoluteUnits[UDAT_STYLE_NARROW][absoluteUnit], |
- status); |
+ |
+ void consumeTableRelativeTime(const char *key, ResourceValue &value, UErrorCode &errorCode) { |
+ ResourceTable relativeTimeTable = value.getTable(errorCode); |
+ if (U_FAILURE(errorCode)) { return; } |
+ |
+ int32_t relUnitIndex = relUnitFromGeneric(genericUnit); |
+ if (relUnitIndex < 0) { |
+ return; |
+ } |
+ for (int32_t i = 0; relativeTimeTable.getKeyAndValue(i, key, value); ++i) { |
+ if (uprv_strcmp(key, "past") == 0) { |
+ pastFutureIndex = 0; |
+ } else if (uprv_strcmp(key, "future") == 0) { |
+ pastFutureIndex = 1; |
+ } else { |
+ // Unknown key. |
+ continue; |
+ } |
+ consumeTimeDetail(relUnitIndex, key, value, errorCode); |
+ } |
} |
-} |
-static void initRelativeUnits( |
- const UResourceBundle *resource, |
- const char *path, const char *pathShort, const char *pathNarrow, |
- UDateRelativeUnit relativeUnit, |
- QuantityFormatter relativeUnits[][UDAT_RELATIVE_UNIT_COUNT][2], |
- UErrorCode &status) { |
- initRelativeUnit( |
- resource, |
- path, |
- relativeUnits[UDAT_STYLE_LONG][relativeUnit], |
- status); |
- initRelativeUnit( |
- resource, |
- pathShort, |
- relativeUnits[UDAT_STYLE_SHORT][relativeUnit], |
- status); |
- if (U_FAILURE(status)) { |
- return; |
+ void consumeAlias(const char *key, const ResourceValue &value, UErrorCode &errorCode) { |
+ |
+ UDateRelativeDateTimeFormatterStyle sourceStyle = styleFromString(key); |
+ const UnicodeString valueStr = value.getAliasUnicodeString(errorCode); |
+ if (U_FAILURE(errorCode)) { return; } |
+ |
+ UDateRelativeDateTimeFormatterStyle targetStyle = |
+ styleFromAliasUnicodeString(valueStr); |
+ |
+ if (sourceStyle == targetStyle) { |
+ errorCode = U_INVALID_FORMAT_ERROR; |
+ return; |
+ } |
+ if (outputData.fallBackCache[sourceStyle] != -1 && |
+ outputData.fallBackCache[sourceStyle] != targetStyle) { |
+ errorCode = U_INVALID_FORMAT_ERROR; |
+ return; |
+ } |
+ outputData.fallBackCache[sourceStyle] = targetStyle; |
} |
- initRelativeUnit( |
- resource, |
- pathNarrow, |
- relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
- status); |
- if (status == U_MISSING_RESOURCE_ERROR) { |
- // retry initRelativeUnit for UDAT_STYLE_NARROW using pathShort |
- status = U_ZERO_ERROR; |
- initRelativeUnit( |
- resource, |
- pathShort, |
- relativeUnits[UDAT_STYLE_NARROW][relativeUnit], |
- status); |
+ |
+ void consumeTimeUnit(const char *key, ResourceValue &value, UErrorCode &errorCode) { |
+ ResourceTable unitTypesTable = value.getTable(errorCode); |
+ if (U_FAILURE(errorCode)) { return; } |
+ |
+ for (int32_t i = 0; unitTypesTable.getKeyAndValue(i, key, value); ++i) { |
+ // Handle display name. |
+ if (uprv_strcmp(key, "dn") == 0 && value.getType() == URES_STRING) { |
+ handlePlainDirection(value, errorCode); |
+ } |
+ if (value.getType() == URES_TABLE) { |
+ if (uprv_strcmp(key, "relative") == 0) { |
+ consumeTableRelative(key, value, errorCode); |
+ } else if (uprv_strcmp(key, "relativeTime") == 0) { |
+ consumeTableRelativeTime(key, value, errorCode); |
+ } |
+ } |
+ } |
} |
-} |
-static void addWeekDays( |
- const UResourceBundle *resource, |
- const char *path, const char *pathShort, const char *pathNarrow, |
- const UnicodeString daysOfWeek[][7], |
- UDateAbsoluteUnit absoluteUnit, |
- UnicodeString absoluteUnits[][UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT], |
- UErrorCode &status) { |
- addWeekDay( |
- resource, |
- path, |
- daysOfWeek[UDAT_STYLE_LONG], |
- absoluteUnit, |
- absoluteUnits[UDAT_STYLE_LONG], |
- status); |
- addWeekDay( |
- resource, |
- pathShort, |
- daysOfWeek[UDAT_STYLE_SHORT], |
- absoluteUnit, |
- absoluteUnits[UDAT_STYLE_SHORT], |
- status); |
- if (U_FAILURE(status)) { |
- return; |
+ virtual void put(const char *key, ResourceValue &value, |
+ UBool /*noFallback*/, UErrorCode &errorCode) { |
+ // Main entry point to sink |
+ ResourceTable table = value.getTable(errorCode); |
+ if (U_FAILURE(errorCode)) { return; } |
+ for (int32_t i = 0; table.getKeyAndValue(i, key, value); ++i) { |
+ if (value.getType() == URES_ALIAS) { |
+ consumeAlias(key, value, errorCode); |
+ } else { |
+ style = styleFromString(key); |
+ int32_t unitSize = uprv_strlen(key) - styleSuffixLength(style); |
+ genericUnit = unitOrNegativeFromString(key, unitSize); |
+ if (style >= 0 && genericUnit != INVALID_UNIT) { |
+ consumeTimeUnit(key, value, errorCode); |
+ } |
+ } |
+ } |
} |
- addWeekDay( |
- resource, |
- pathNarrow, |
- daysOfWeek[UDAT_STYLE_NARROW], |
- absoluteUnit, |
- absoluteUnits[UDAT_STYLE_NARROW], |
- status); |
- if (status == U_MISSING_RESOURCE_ERROR) { |
- // retry addWeekDay for UDAT_STYLE_NARROW using pathShort |
- status = U_ZERO_ERROR; |
- addWeekDay( |
- resource, |
- pathShort, |
- daysOfWeek[UDAT_STYLE_NARROW], |
- absoluteUnit, |
- absoluteUnits[UDAT_STYLE_NARROW], |
- status); |
+ |
+}; |
+ |
+// Virtual destructors must be defined out of line. |
+RelDateTimeFmtDataSink::~RelDateTimeFmtDataSink() {} |
+} // namespace |
+ |
+DateFormatSymbols::DtWidthType styleToDateFormatSymbolWidth[UDAT_STYLE_COUNT] = { |
+ DateFormatSymbols::WIDE, DateFormatSymbols::SHORT, DateFormatSymbols::NARROW |
+}; |
+ |
+// Get days of weeks from the DateFormatSymbols class. |
+static void loadWeekdayNames(UnicodeString absoluteUnits[UDAT_STYLE_COUNT] |
+ [UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT], |
+ const char* localeId, |
+ UErrorCode& status) { |
+ Locale locale(localeId); |
+ DateFormatSymbols dfSym(locale, status); |
+ for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) { |
+ DateFormatSymbols::DtWidthType dtfmtWidth = styleToDateFormatSymbolWidth[style]; |
+ int32_t count; |
+ const UnicodeString* weekdayNames = |
+ dfSym.getWeekdays(count, DateFormatSymbols::STANDALONE, dtfmtWidth); |
+ for (int32_t dayIndex = UDAT_ABSOLUTE_SUNDAY; |
+ dayIndex <= UDAT_ABSOLUTE_SATURDAY; ++ dayIndex) { |
+ int32_t dateSymbolIndex = (dayIndex - UDAT_ABSOLUTE_SUNDAY) + UCAL_SUNDAY; |
+ absoluteUnits[style][dayIndex][UDAT_DIRECTION_PLAIN].fastCopyFrom( |
+ weekdayNames[dateSymbolIndex]); |
+ } |
} |
} |
static UBool loadUnitData( |
const UResourceBundle *resource, |
RelativeDateTimeCacheData &cacheData, |
+ const char* localeId, |
UErrorCode &status) { |
- addTimeUnits( |
- resource, |
- "fields/day", "fields/day-short", "fields/day-narrow", |
- UDAT_RELATIVE_DAYS, |
- UDAT_ABSOLUTE_DAY, |
- cacheData, |
- status); |
- addTimeUnits( |
- resource, |
- "fields/week", "fields/week-short", "fields/week-narrow", |
- UDAT_RELATIVE_WEEKS, |
- UDAT_ABSOLUTE_WEEK, |
- cacheData, |
- status); |
- addTimeUnits( |
- resource, |
- "fields/month", "fields/month-short", "fields/month-narrow", |
- UDAT_RELATIVE_MONTHS, |
- UDAT_ABSOLUTE_MONTH, |
- cacheData, |
- status); |
- addTimeUnits( |
- resource, |
- "fields/year", "fields/year-short", "fields/year-narrow", |
- UDAT_RELATIVE_YEARS, |
- UDAT_ABSOLUTE_YEAR, |
- cacheData, |
- status); |
- initRelativeUnits( |
- resource, |
- "fields/second", "fields/second-short", "fields/second-narrow", |
- UDAT_RELATIVE_SECONDS, |
- cacheData.relativeUnits, |
- status); |
- initRelativeUnits( |
- resource, |
- "fields/minute", "fields/minute-short", "fields/minute-narrow", |
- UDAT_RELATIVE_MINUTES, |
- cacheData.relativeUnits, |
- status); |
- initRelativeUnits( |
- resource, |
- "fields/hour", "fields/hour-short", "fields/hour-narrow", |
- UDAT_RELATIVE_HOURS, |
- cacheData.relativeUnits, |
- status); |
- getStringWithFallback( |
- resource, |
- "fields/second/relative/0", |
- cacheData.absoluteUnits[UDAT_STYLE_LONG][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN], |
- status); |
- getStringWithFallback( |
- resource, |
- "fields/second-short/relative/0", |
- cacheData.absoluteUnits[UDAT_STYLE_SHORT][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN], |
- status); |
- getStringWithFallback( |
- resource, |
- "fields/second-narrow/relative/0", |
- cacheData.absoluteUnits[UDAT_STYLE_NARROW][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN], |
- status); |
- UnicodeString daysOfWeek[UDAT_STYLE_COUNT][7]; |
- readDaysOfWeek( |
- resource, |
- "calendar/gregorian/dayNames/stand-alone/wide", |
- daysOfWeek[UDAT_STYLE_LONG], |
- status); |
- readDaysOfWeek( |
- resource, |
- "calendar/gregorian/dayNames/stand-alone/short", |
- daysOfWeek[UDAT_STYLE_SHORT], |
- status); |
- readDaysOfWeek( |
- resource, |
- "calendar/gregorian/dayNames/stand-alone/narrow", |
- daysOfWeek[UDAT_STYLE_NARROW], |
- status); |
- addWeekDays( |
- resource, |
- "fields/mon/relative", |
- "fields/mon-short/relative", |
- "fields/mon-narrow/relative", |
- daysOfWeek, |
- UDAT_ABSOLUTE_MONDAY, |
- cacheData.absoluteUnits, |
- status); |
- addWeekDays( |
- resource, |
- "fields/tue/relative", |
- "fields/tue-short/relative", |
- "fields/tue-narrow/relative", |
- daysOfWeek, |
- UDAT_ABSOLUTE_TUESDAY, |
- cacheData.absoluteUnits, |
- status); |
- addWeekDays( |
- resource, |
- "fields/wed/relative", |
- "fields/wed-short/relative", |
- "fields/wed-narrow/relative", |
- daysOfWeek, |
- UDAT_ABSOLUTE_WEDNESDAY, |
- cacheData.absoluteUnits, |
- status); |
- addWeekDays( |
- resource, |
- "fields/thu/relative", |
- "fields/thu-short/relative", |
- "fields/thu-narrow/relative", |
- daysOfWeek, |
- UDAT_ABSOLUTE_THURSDAY, |
- cacheData.absoluteUnits, |
- status); |
- addWeekDays( |
- resource, |
- "fields/fri/relative", |
- "fields/fri-short/relative", |
- "fields/fri-narrow/relative", |
- daysOfWeek, |
- UDAT_ABSOLUTE_FRIDAY, |
- cacheData.absoluteUnits, |
- status); |
- addWeekDays( |
- resource, |
- "fields/sat/relative", |
- "fields/sat-short/relative", |
- "fields/sat-narrow/relative", |
- daysOfWeek, |
- UDAT_ABSOLUTE_SATURDAY, |
- cacheData.absoluteUnits, |
- status); |
- addWeekDays( |
- resource, |
- "fields/sun/relative", |
- "fields/sun-short/relative", |
- "fields/sun-narrow/relative", |
- daysOfWeek, |
- UDAT_ABSOLUTE_SUNDAY, |
- cacheData.absoluteUnits, |
- status); |
+ |
+ RelDateTimeFmtDataSink sink(cacheData); |
+ |
+ ures_getAllItemsWithFallback(resource, "fields", sink, status); |
+ |
+ // Get the weekday names from DateFormatSymbols. |
+ loadWeekdayNames(cacheData.absoluteUnits, localeId, status); |
return U_SUCCESS(status); |
} |
@@ -608,7 +623,7 @@ static UBool getDateTimePattern( |
} |
int32_t size = ures_getSize(topLevel.getAlias()); |
if (size <= 8) { |
- // Oops, size is to small to access the index that we want, fallback |
+ // Oops, size is too small to access the index that we want, fallback |
// to a hard-coded value. |
result = UNICODE_STRING_SIMPLE("{1} {0}"); |
return TRUE; |
@@ -632,6 +647,7 @@ const RelativeDateTimeCacheData *LocaleCacheKey<RelativeDateTimeCacheData>::crea |
if (!loadUnitData( |
topLevel.getAlias(), |
*result, |
+ localeId, |
status)) { |
return NULL; |
} |
@@ -640,7 +656,7 @@ const RelativeDateTimeCacheData *LocaleCacheKey<RelativeDateTimeCacheData>::crea |
return NULL; |
} |
result->adoptCombinedDateAndTime( |
- new MessageFormat(dateTimePattern, localeId, status)); |
+ new SimpleFormatter(dateTimePattern, 2, 2, status)); |
if (U_FAILURE(status)) { |
return NULL; |
} |
@@ -784,27 +800,61 @@ UnicodeString& RelativeDateTimeFormatter::format( |
} |
int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0; |
FieldPosition pos(FieldPosition::DONT_CARE); |
- if (fOptBreakIterator == NULL) { |
- return fCache->relativeUnits[fStyle][unit][bFuture].format( |
- quantity, |
- **fNumberFormat, |
- **fPluralRules, |
- appendTo, |
- pos, |
- status); |
- } |
+ |
UnicodeString result; |
- fCache->relativeUnits[fStyle][unit][bFuture].format( |
- quantity, |
- **fNumberFormat, |
- **fPluralRules, |
- result, |
- pos, |
- status); |
+ UnicodeString formattedNumber; |
+ |
+ StandardPlural::Form pluralIndex = QuantityFormatter::selectPlural( |
+ quantity, **fNumberFormat, **fPluralRules, formattedNumber, pos, |
+ status); |
+ |
+ const SimpleFormatter* formatter = |
+ fCache->getRelativeUnitFormatter(fStyle, unit, bFuture, pluralIndex); |
+ if (formatter == NULL) { |
+ // TODO: WARN - look at quantity formatter's action with an error. |
+ status = U_INVALID_FORMAT_ERROR; |
+ return appendTo; |
+ } |
+ formatter->format(formattedNumber, result, status); |
adjustForContext(result); |
return appendTo.append(result); |
} |
+UnicodeString& RelativeDateTimeFormatter::formatNumeric( |
+ double offset, URelativeDateTimeUnit unit, |
+ UnicodeString& appendTo, UErrorCode& status) const { |
+ if (U_FAILURE(status)) { |
+ return appendTo; |
+ } |
+ // TODO: |
+ // The full implementation of this depends on CLDR data that is not yet available, |
+ // see: http://unicode.org/cldr/trac/ticket/9165 Add more relative field data. |
+ // In the meantime do a quick bring-up by calling the old format method; this |
+ // leaves some holes (even for data that is currently available, such as quarter). |
+ // When the new CLDR data is available, update the data storage accordingly, |
+ // rewrite this to use it directly, and rewrite the old format method to call this |
+ // new one; that is covered by http://bugs.icu-project.org/trac/ticket/12171. |
+ 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_UNSUPPORTED_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 { |
@@ -815,21 +865,87 @@ UnicodeString& RelativeDateTimeFormatter::format( |
status = U_ILLEGAL_ARGUMENT_ERROR; |
return appendTo; |
} |
- if (fOptBreakIterator == NULL) { |
- return appendTo.append(fCache->absoluteUnits[fStyle][unit][direction]); |
+ |
+ // Get string using fallback. |
+ UnicodeString result; |
+ result.fastCopyFrom(fCache->getAbsoluteUnitString(fStyle, unit, direction)); |
+ if (fOptBreakIterator != NULL) { |
+ adjustForContext(result); |
} |
- UnicodeString result(fCache->absoluteUnits[fStyle][unit][direction]); |
- adjustForContext(result); |
return appendTo.append(result); |
} |
+UnicodeString& RelativeDateTimeFormatter::format( |
+ double offset, URelativeDateTimeUnit unit, |
+ UnicodeString& appendTo, UErrorCode& status) const { |
+ if (U_FAILURE(status)) { |
+ return appendTo; |
+ } |
+ // TODO: |
+ // The full implementation of this depends on CLDR data that is not yet available, |
+ // see: http://unicode.org/cldr/trac/ticket/9165 Add more relative field data. |
+ // In the meantime do a quick bring-up by calling the old format method; this |
+ // leaves some holes (even for data that is currently available, such as quarter). |
+ // When the new CLDR data is available, update the data storage accordingly, |
+ // rewrite this to use it directly, and rewrite the old format method to call this |
+ // new one; that is covered by http://bugs.icu-project.org/trac/ticket/12171. |
+ UDateDirection direction = UDAT_DIRECTION_COUNT; |
+ if (offset > -2.1 && offset < 2.1) { |
+ // Allow a 1% epsilon, so offsets in -1.01..-0.99 map to LAST |
+ double offsetx100 = offset * 100.0; |
+ int32_t intoffset = (offsetx100 < 0)? (int32_t)(offsetx100-0.5) : (int32_t)(offsetx100+0.5); |
+ switch (intoffset) { |
+ case -200/*-2*/: direction = UDAT_DIRECTION_LAST_2; break; |
+ case -100/*-1*/: direction = UDAT_DIRECTION_LAST; break; |
+ case 0/* 0*/: direction = UDAT_DIRECTION_THIS; break; |
+ case 100/* 1*/: direction = UDAT_DIRECTION_NEXT; break; |
+ case 200/* 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_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) { |
+ const UnicodeString &unitFormatString = |
+ fCache->getAbsoluteUnitString(fStyle, absunit, direction); |
+ if (!unitFormatString.isEmpty()) { |
+ if (fOptBreakIterator != NULL) { |
+ UnicodeString result(unitFormatString); |
+ adjustForContext(result); |
+ return appendTo.append(result); |
+ } else { |
+ return appendTo.append(unitFormatString); |
+ } |
+ } |
+ } |
+ // otherwise fallback to formatNumeric |
+ return formatNumeric(offset, unit, appendTo, status); |
+} |
+ |
UnicodeString& RelativeDateTimeFormatter::combineDateAndTime( |
- const UnicodeString& relativeDateString, const UnicodeString& timeString, |
- UnicodeString& appendTo, UErrorCode& status) const { |
- Formattable args[2] = {timeString, relativeDateString}; |
- FieldPosition fpos(0); |
+ const UnicodeString& relativeDateString, const UnicodeString& timeString, |
+ UnicodeString& appendTo, UErrorCode& status) const { |
return fCache->getCombinedDateAndTime()->format( |
- args, 2, appendTo, fpos, status); |
+ timeString, relativeDateString, appendTo, status); |
} |
void RelativeDateTimeFormatter::adjustForContext(UnicodeString &str) const { |
@@ -894,8 +1010,120 @@ void RelativeDateTimeFormatter::init( |
} |
} |
- |
U_NAMESPACE_END |
-#endif /* !UCONFIG_NO_FORMATTING */ |
+// 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<RelativeDateTimeFormatter> formatter(new RelativeDateTimeFormatter(Locale(locale), |
+ (NumberFormat*)nfToAdopt, width, |
+ capitalizationContext, *status), *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 != 0 : relativeDateStringLen < -1) || |
+ (timeString == NULL ? timeStringLen != 0 : 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(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 */ |