diff options
Diffstat (limited to 'intl/icu/source/i18n/udat.cpp')
-rw-r--r-- | intl/icu/source/i18n/udat.cpp | 1316 |
1 files changed, 1316 insertions, 0 deletions
diff --git a/intl/icu/source/i18n/udat.cpp b/intl/icu/source/i18n/udat.cpp new file mode 100644 index 000000000..3b8a36a1b --- /dev/null +++ b/intl/icu/source/i18n/udat.cpp @@ -0,0 +1,1316 @@ +// Copyright (C) 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/* +******************************************************************************* +* Copyright (C) 1996-2015, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +*/ + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/udat.h" + +#include "unicode/uloc.h" +#include "unicode/datefmt.h" +#include "unicode/timezone.h" +#include "unicode/smpdtfmt.h" +#include "unicode/fieldpos.h" +#include "unicode/parsepos.h" +#include "unicode/calendar.h" +#include "unicode/numfmt.h" +#include "unicode/dtfmtsym.h" +#include "unicode/ustring.h" +#include "unicode/udisplaycontext.h" +#include "unicode/ufieldpositer.h" +#include "cpputils.h" +#include "reldtfmt.h" +#include "umutex.h" + +U_NAMESPACE_USE + +/** + * Verify that fmt is a SimpleDateFormat. Invalid error if not. + * @param fmt the UDateFormat, definitely a DateFormat, maybe something else + * @param status error code, will be set to failure if there is a familure or the fmt is NULL. + */ +static void verifyIsSimpleDateFormat(const UDateFormat* fmt, UErrorCode *status) { + if(U_SUCCESS(*status) && + dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + } +} + +// This mirrors the correspondence between the +// SimpleDateFormat::fgPatternIndexToDateFormatField and +// SimpleDateFormat::fgPatternIndexToCalendarField arrays. +static UCalendarDateFields gDateFieldMapping[] = { + UCAL_ERA, // UDAT_ERA_FIELD = 0 + UCAL_YEAR, // UDAT_YEAR_FIELD = 1 + UCAL_MONTH, // UDAT_MONTH_FIELD = 2 + UCAL_DATE, // UDAT_DATE_FIELD = 3 + UCAL_HOUR_OF_DAY, // UDAT_HOUR_OF_DAY1_FIELD = 4 + UCAL_HOUR_OF_DAY, // UDAT_HOUR_OF_DAY0_FIELD = 5 + UCAL_MINUTE, // UDAT_MINUTE_FIELD = 6 + UCAL_SECOND, // UDAT_SECOND_FIELD = 7 + UCAL_MILLISECOND, // UDAT_FRACTIONAL_SECOND_FIELD = 8 + UCAL_DAY_OF_WEEK, // UDAT_DAY_OF_WEEK_FIELD = 9 + UCAL_DAY_OF_YEAR, // UDAT_DAY_OF_YEAR_FIELD = 10 + UCAL_DAY_OF_WEEK_IN_MONTH, // UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11 + UCAL_WEEK_OF_YEAR, // UDAT_WEEK_OF_YEAR_FIELD = 12 + UCAL_WEEK_OF_MONTH, // UDAT_WEEK_OF_MONTH_FIELD = 13 + UCAL_AM_PM, // UDAT_AM_PM_FIELD = 14 + UCAL_HOUR, // UDAT_HOUR1_FIELD = 15 + UCAL_HOUR, // UDAT_HOUR0_FIELD = 16 + UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_FIELD = 17 + UCAL_YEAR_WOY, // UDAT_YEAR_WOY_FIELD = 18 + UCAL_DOW_LOCAL, // UDAT_DOW_LOCAL_FIELD = 19 + UCAL_EXTENDED_YEAR, // UDAT_EXTENDED_YEAR_FIELD = 20 + UCAL_JULIAN_DAY, // UDAT_JULIAN_DAY_FIELD = 21 + UCAL_MILLISECONDS_IN_DAY, // UDAT_MILLISECONDS_IN_DAY_FIELD = 22 + UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_RFC_FIELD = 23 (also UCAL_DST_OFFSET) + UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_GENERIC_FIELD = 24 (also UCAL_DST_OFFSET) + UCAL_DOW_LOCAL, // UDAT_STANDALONE_DAY_FIELD = 25 + UCAL_MONTH, // UDAT_STANDALONE_MONTH_FIELD = 26 + UCAL_MONTH, // UDAT_QUARTER_FIELD = 27 + UCAL_MONTH, // UDAT_STANDALONE_QUARTER_FIELD = 28 + UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_SPECIAL_FIELD = 29 (also UCAL_DST_OFFSET) + UCAL_YEAR, // UDAT_YEAR_NAME_FIELD = 30 + UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD = 31 (also UCAL_DST_OFFSET) + UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_ISO_FIELD = 32 (also UCAL_DST_OFFSET) + UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_ISO_LOCAL_FIELD = 33 (also UCAL_DST_OFFSET) + UCAL_EXTENDED_YEAR, // UDAT_RELATED_YEAR_FIELD = 34 (not an exact match) + UCAL_FIELD_COUNT, // UDAT_FIELD_COUNT = 35 + // UCAL_IS_LEAP_MONTH is not the target of a mapping +}; + +U_CAPI UCalendarDateFields U_EXPORT2 +udat_toCalendarDateField(UDateFormatField field) { + return gDateFieldMapping[field]; +} + +/* For now- one opener. */ +static UDateFormatOpener gOpener = NULL; + +U_INTERNAL void U_EXPORT2 +udat_registerOpener(UDateFormatOpener opener, UErrorCode *status) +{ + if(U_FAILURE(*status)) return; + umtx_lock(NULL); + if(gOpener==NULL) { + gOpener = opener; + } else { + *status = U_ILLEGAL_ARGUMENT_ERROR; + } + umtx_unlock(NULL); +} + +U_INTERNAL UDateFormatOpener U_EXPORT2 +udat_unregisterOpener(UDateFormatOpener opener, UErrorCode *status) +{ + if(U_FAILURE(*status)) return NULL; + UDateFormatOpener oldOpener = NULL; + umtx_lock(NULL); + if(gOpener==NULL || gOpener!=opener) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + } else { + oldOpener=gOpener; + gOpener=NULL; + } + umtx_unlock(NULL); + return oldOpener; +} + + + +U_CAPI UDateFormat* U_EXPORT2 +udat_open(UDateFormatStyle timeStyle, + UDateFormatStyle dateStyle, + const char *locale, + const UChar *tzID, + int32_t tzIDLength, + const UChar *pattern, + int32_t patternLength, + UErrorCode *status) +{ + DateFormat *fmt; + if(U_FAILURE(*status)) { + return 0; + } + if(gOpener!=NULL) { // if it's registered + fmt = (DateFormat*) (*gOpener)(timeStyle,dateStyle,locale,tzID,tzIDLength,pattern,patternLength,status); + if(fmt!=NULL) { + return (UDateFormat*)fmt; + } // else fall through. + } + if(timeStyle != UDAT_PATTERN) { + if(locale == 0) { + fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle, + (DateFormat::EStyle)timeStyle); + } + else { + fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle, + (DateFormat::EStyle)timeStyle, + Locale(locale)); + } + } + else { + UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength); + + if(locale == 0) { + fmt = new SimpleDateFormat(pat, *status); + } + else { + fmt = new SimpleDateFormat(pat, Locale(locale), *status); + } + } + + if(fmt == 0) { + *status = U_MEMORY_ALLOCATION_ERROR; + return 0; + } + + if(tzID != 0) { + TimeZone *zone = TimeZone::createTimeZone(UnicodeString((UBool)(tzIDLength == -1), tzID, tzIDLength)); + if(zone == 0) { + *status = U_MEMORY_ALLOCATION_ERROR; + delete fmt; + return 0; + } + fmt->adoptTimeZone(zone); + } + + return (UDateFormat*)fmt; +} + + +U_CAPI void U_EXPORT2 +udat_close(UDateFormat* format) +{ + delete (DateFormat*)format; +} + +U_CAPI UDateFormat* U_EXPORT2 +udat_clone(const UDateFormat *fmt, + UErrorCode *status) +{ + if(U_FAILURE(*status)) return 0; + + Format *res = ((DateFormat*)fmt)->clone(); + + if(res == 0) { + *status = U_MEMORY_ALLOCATION_ERROR; + return 0; + } + + return (UDateFormat*) res; +} + +U_CAPI int32_t U_EXPORT2 +udat_format( const UDateFormat* format, + UDate dateToFormat, + UChar* result, + int32_t resultLength, + UFieldPosition* position, + UErrorCode* status) +{ + if(U_FAILURE(*status)) { + return -1; + } + if (result == NULL ? resultLength != 0 : resultLength < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + + UnicodeString res; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + res.setTo(result, 0, resultLength); + } + + FieldPosition fp; + + if(position != 0) + fp.setField(position->field); + + ((DateFormat*)format)->format(dateToFormat, res, fp); + + if(position != 0) { + position->beginIndex = fp.getBeginIndex(); + position->endIndex = fp.getEndIndex(); + } + + return res.extract(result, resultLength, *status); +} + +U_CAPI int32_t U_EXPORT2 +udat_formatCalendar(const UDateFormat* format, + UCalendar* calendar, + UChar* result, + int32_t resultLength, + UFieldPosition* position, + UErrorCode* status) +{ + if(U_FAILURE(*status)) { + return -1; + } + if (result == NULL ? resultLength != 0 : resultLength < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + + UnicodeString res; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + res.setTo(result, 0, resultLength); + } + + FieldPosition fp; + + if(position != 0) + fp.setField(position->field); + + ((DateFormat*)format)->format(*(Calendar*)calendar, res, fp); + + if(position != 0) { + position->beginIndex = fp.getBeginIndex(); + position->endIndex = fp.getEndIndex(); + } + + return res.extract(result, resultLength, *status); +} + +U_CAPI int32_t U_EXPORT2 +udat_formatForFields( const UDateFormat* format, + UDate dateToFormat, + UChar* result, + int32_t resultLength, + UFieldPositionIterator* fpositer, + UErrorCode* status) +{ + if(U_FAILURE(*status)) { + return -1; + } + if (result == NULL ? resultLength != 0 : resultLength < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + + UnicodeString res; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + res.setTo(result, 0, resultLength); + } + + ((DateFormat*)format)->format(dateToFormat, res, (FieldPositionIterator*)fpositer, *status); + + return res.extract(result, resultLength, *status); +} + +U_CAPI int32_t U_EXPORT2 +udat_formatCalendarForFields(const UDateFormat* format, + UCalendar* calendar, + UChar* result, + int32_t resultLength, + UFieldPositionIterator* fpositer, + UErrorCode* status) +{ + if(U_FAILURE(*status)) { + return -1; + } + if (result == NULL ? resultLength != 0 : resultLength < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + + UnicodeString res; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + res.setTo(result, 0, resultLength); + } + + ((DateFormat*)format)->format(*(Calendar*)calendar, res, (FieldPositionIterator*)fpositer, *status); + + return res.extract(result, resultLength, *status); +} + +U_CAPI UDate U_EXPORT2 +udat_parse( const UDateFormat* format, + const UChar* text, + int32_t textLength, + int32_t *parsePos, + UErrorCode *status) +{ + if(U_FAILURE(*status)) return (UDate)0; + + const UnicodeString src((UBool)(textLength == -1), text, textLength); + ParsePosition pp; + int32_t stackParsePos = 0; + UDate res; + + if(parsePos == NULL) { + parsePos = &stackParsePos; + } + + pp.setIndex(*parsePos); + + res = ((DateFormat*)format)->parse(src, pp); + + if(pp.getErrorIndex() == -1) + *parsePos = pp.getIndex(); + else { + *parsePos = pp.getErrorIndex(); + *status = U_PARSE_ERROR; + } + + return res; +} + +U_CAPI void U_EXPORT2 +udat_parseCalendar(const UDateFormat* format, + UCalendar* calendar, + const UChar* text, + int32_t textLength, + int32_t *parsePos, + UErrorCode *status) +{ + if(U_FAILURE(*status)) return; + + const UnicodeString src((UBool)(textLength == -1), text, textLength); + ParsePosition pp; + int32_t stackParsePos = 0; + + if(parsePos == NULL) { + parsePos = &stackParsePos; + } + + pp.setIndex(*parsePos); + + ((DateFormat*)format)->parse(src, *(Calendar*)calendar, pp); + + if(pp.getErrorIndex() == -1) + *parsePos = pp.getIndex(); + else { + *parsePos = pp.getErrorIndex(); + *status = U_PARSE_ERROR; + } +} + +U_CAPI UBool U_EXPORT2 +udat_isLenient(const UDateFormat* fmt) +{ + return ((DateFormat*)fmt)->isLenient(); +} + +U_CAPI void U_EXPORT2 +udat_setLenient( UDateFormat* fmt, + UBool isLenient) +{ + ((DateFormat*)fmt)->setLenient(isLenient); +} + +U_DRAFT UBool U_EXPORT2 +udat_getBooleanAttribute(const UDateFormat* fmt, + UDateFormatBooleanAttribute attr, + UErrorCode* status) +{ + if(U_FAILURE(*status)) return FALSE; + return ((DateFormat*)fmt)->getBooleanAttribute(attr, *status); + //return FALSE; +} + +U_DRAFT void U_EXPORT2 +udat_setBooleanAttribute(UDateFormat *fmt, + UDateFormatBooleanAttribute attr, + UBool newValue, + UErrorCode* status) +{ + if(U_FAILURE(*status)) return; + ((DateFormat*)fmt)->setBooleanAttribute(attr, newValue, *status); +} + +U_CAPI const UCalendar* U_EXPORT2 +udat_getCalendar(const UDateFormat* fmt) +{ + return (const UCalendar*) ((DateFormat*)fmt)->getCalendar(); +} + +U_CAPI void U_EXPORT2 +udat_setCalendar(UDateFormat* fmt, + const UCalendar* calendarToSet) +{ + ((DateFormat*)fmt)->setCalendar(*((Calendar*)calendarToSet)); +} + +U_DRAFT const UNumberFormat* U_EXPORT2 +udat_getNumberFormatForField(const UDateFormat* fmt, UChar field) +{ + UErrorCode status = U_ZERO_ERROR; + verifyIsSimpleDateFormat(fmt, &status); + if (U_FAILURE(status)) return (const UNumberFormat*) ((DateFormat*)fmt)->getNumberFormat(); + return (const UNumberFormat*) ((SimpleDateFormat*)fmt)->getNumberFormatForField(field); +} + +U_CAPI const UNumberFormat* U_EXPORT2 +udat_getNumberFormat(const UDateFormat* fmt) +{ + return (const UNumberFormat*) ((DateFormat*)fmt)->getNumberFormat(); +} + +U_DRAFT void U_EXPORT2 +udat_adoptNumberFormatForFields( UDateFormat* fmt, + const UChar* fields, + UNumberFormat* numberFormatToSet, + UErrorCode* status) +{ + verifyIsSimpleDateFormat(fmt, status); + if (U_FAILURE(*status)) return; + + if (fields!=NULL) { + UnicodeString overrideFields(fields); + ((SimpleDateFormat*)fmt)->adoptNumberFormat(overrideFields, (NumberFormat*)numberFormatToSet, *status); + } +} + +U_CAPI void U_EXPORT2 +udat_setNumberFormat(UDateFormat* fmt, + const UNumberFormat* numberFormatToSet) +{ + ((DateFormat*)fmt)->setNumberFormat(*((NumberFormat*)numberFormatToSet)); +} + +U_DRAFT void U_EXPORT2 +udat_adoptNumberFormat( UDateFormat* fmt, + UNumberFormat* numberFormatToAdopt) +{ + ((DateFormat*)fmt)->adoptNumberFormat((NumberFormat*)numberFormatToAdopt); +} + +U_CAPI const char* U_EXPORT2 +udat_getAvailable(int32_t index) +{ + return uloc_getAvailable(index); +} + +U_CAPI int32_t U_EXPORT2 +udat_countAvailable() +{ + return uloc_countAvailable(); +} + +U_CAPI UDate U_EXPORT2 +udat_get2DigitYearStart( const UDateFormat *fmt, + UErrorCode *status) +{ + verifyIsSimpleDateFormat(fmt, status); + if(U_FAILURE(*status)) return (UDate)0; + return ((SimpleDateFormat*)fmt)->get2DigitYearStart(*status); +} + +U_CAPI void U_EXPORT2 +udat_set2DigitYearStart( UDateFormat *fmt, + UDate d, + UErrorCode *status) +{ + verifyIsSimpleDateFormat(fmt, status); + if(U_FAILURE(*status)) return; + ((SimpleDateFormat*)fmt)->set2DigitYearStart(d, *status); +} + +U_CAPI int32_t U_EXPORT2 +udat_toPattern( const UDateFormat *fmt, + UBool localized, + UChar *result, + int32_t resultLength, + UErrorCode *status) +{ + if(U_FAILURE(*status)) { + return -1; + } + if (result == NULL ? resultLength != 0 : resultLength < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + + UnicodeString res; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + res.setTo(result, 0, resultLength); + } + + const DateFormat *df=reinterpret_cast<const DateFormat *>(fmt); + const SimpleDateFormat *sdtfmt=dynamic_cast<const SimpleDateFormat *>(df); + const RelativeDateFormat *reldtfmt; + if (sdtfmt!=NULL) { + if(localized) + sdtfmt->toLocalizedPattern(res, *status); + else + sdtfmt->toPattern(res); + } else if (!localized && (reldtfmt=dynamic_cast<const RelativeDateFormat *>(df))!=NULL) { + reldtfmt->toPattern(res, *status); + } else { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + + return res.extract(result, resultLength, *status); +} + +// TODO: should this take an UErrorCode? +// A: Yes. Of course. +U_CAPI void U_EXPORT2 +udat_applyPattern( UDateFormat *format, + UBool localized, + const UChar *pattern, + int32_t patternLength) +{ + const UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength); + UErrorCode status = U_ZERO_ERROR; + + verifyIsSimpleDateFormat(format, &status); + if(U_FAILURE(status)) { + return; + } + + if(localized) + ((SimpleDateFormat*)format)->applyLocalizedPattern(pat, status); + else + ((SimpleDateFormat*)format)->applyPattern(pat); +} + +U_CAPI int32_t U_EXPORT2 +udat_getSymbols(const UDateFormat *fmt, + UDateFormatSymbolType type, + int32_t index, + UChar *result, + int32_t resultLength, + UErrorCode *status) +{ + const DateFormatSymbols *syms; + const SimpleDateFormat* sdtfmt; + const RelativeDateFormat* rdtfmt; + if ((sdtfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) { + syms = sdtfmt->getDateFormatSymbols(); + } else if ((rdtfmt = dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) { + syms = rdtfmt->getDateFormatSymbols(); + } else { + return -1; + } + int32_t count; + const UnicodeString *res = NULL; + + switch(type) { + case UDAT_ERAS: + res = syms->getEras(count); + break; + + case UDAT_ERA_NAMES: + res = syms->getEraNames(count); + break; + + case UDAT_MONTHS: + res = syms->getMonths(count); + break; + + case UDAT_SHORT_MONTHS: + res = syms->getShortMonths(count); + break; + + case UDAT_WEEKDAYS: + res = syms->getWeekdays(count); + break; + + case UDAT_SHORT_WEEKDAYS: + res = syms->getShortWeekdays(count); + break; + + case UDAT_AM_PMS: + res = syms->getAmPmStrings(count); + break; + + case UDAT_LOCALIZED_CHARS: + { + UnicodeString res1; + if(!(result==NULL && resultLength==0)) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + res1.setTo(result, 0, resultLength); + } + syms->getLocalPatternChars(res1); + return res1.extract(result, resultLength, *status); + } + + case UDAT_NARROW_MONTHS: + res = syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW); + break; + + case UDAT_SHORTER_WEEKDAYS: + res = syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::SHORT); + break; + + case UDAT_NARROW_WEEKDAYS: + res = syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW); + break; + + case UDAT_STANDALONE_MONTHS: + res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE); + break; + + case UDAT_STANDALONE_SHORT_MONTHS: + res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_STANDALONE_NARROW_MONTHS: + res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW); + break; + + case UDAT_STANDALONE_WEEKDAYS: + res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE); + break; + + case UDAT_STANDALONE_SHORT_WEEKDAYS: + res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_STANDALONE_SHORTER_WEEKDAYS: + res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::SHORT); + break; + + case UDAT_STANDALONE_NARROW_WEEKDAYS: + res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW); + break; + + case UDAT_QUARTERS: + res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE); + break; + + case UDAT_SHORT_QUARTERS: + res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_STANDALONE_QUARTERS: + res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE); + break; + + case UDAT_STANDALONE_SHORT_QUARTERS: + res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_CYCLIC_YEARS_WIDE: + res = syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE); + break; + + case UDAT_CYCLIC_YEARS_ABBREVIATED: + res = syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_CYCLIC_YEARS_NARROW: + res = syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW); + break; + + case UDAT_ZODIAC_NAMES_WIDE: + res = syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE); + break; + + case UDAT_ZODIAC_NAMES_ABBREVIATED: + res = syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_ZODIAC_NAMES_NARROW: + res = syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW); + break; + + } + + if(index < count) { + return res[index].extract(result, resultLength, *status); + } + return 0; +} + +// TODO: also needs an errorCode. +U_CAPI int32_t U_EXPORT2 +udat_countSymbols( const UDateFormat *fmt, + UDateFormatSymbolType type) +{ + const DateFormatSymbols *syms; + const SimpleDateFormat* sdtfmt; + const RelativeDateFormat* rdtfmt; + if ((sdtfmt = dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) { + syms = sdtfmt->getDateFormatSymbols(); + } else if ((rdtfmt = dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))) != NULL) { + syms = rdtfmt->getDateFormatSymbols(); + } else { + return 0; + } + int32_t count = 0; + + switch(type) { + case UDAT_ERAS: + syms->getEras(count); + break; + + case UDAT_MONTHS: + syms->getMonths(count); + break; + + case UDAT_SHORT_MONTHS: + syms->getShortMonths(count); + break; + + case UDAT_WEEKDAYS: + syms->getWeekdays(count); + break; + + case UDAT_SHORT_WEEKDAYS: + syms->getShortWeekdays(count); + break; + + case UDAT_AM_PMS: + syms->getAmPmStrings(count); + break; + + case UDAT_LOCALIZED_CHARS: + count = 1; + break; + + case UDAT_ERA_NAMES: + syms->getEraNames(count); + break; + + case UDAT_NARROW_MONTHS: + syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW); + break; + + case UDAT_SHORTER_WEEKDAYS: + syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::SHORT); + break; + + case UDAT_NARROW_WEEKDAYS: + syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW); + break; + + case UDAT_STANDALONE_MONTHS: + syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE); + break; + + case UDAT_STANDALONE_SHORT_MONTHS: + syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_STANDALONE_NARROW_MONTHS: + syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW); + break; + + case UDAT_STANDALONE_WEEKDAYS: + syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE); + break; + + case UDAT_STANDALONE_SHORT_WEEKDAYS: + syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_STANDALONE_SHORTER_WEEKDAYS: + syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::SHORT); + break; + + case UDAT_STANDALONE_NARROW_WEEKDAYS: + syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW); + break; + + case UDAT_QUARTERS: + syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE); + break; + + case UDAT_SHORT_QUARTERS: + syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_STANDALONE_QUARTERS: + syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE); + break; + + case UDAT_STANDALONE_SHORT_QUARTERS: + syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_CYCLIC_YEARS_WIDE: + syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE); + break; + + case UDAT_CYCLIC_YEARS_ABBREVIATED: + syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_CYCLIC_YEARS_NARROW: + syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW); + break; + + case UDAT_ZODIAC_NAMES_WIDE: + syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE); + break; + + case UDAT_ZODIAC_NAMES_ABBREVIATED: + syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED); + break; + + case UDAT_ZODIAC_NAMES_NARROW: + syms->getZodiacNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW); + break; + + } + + return count; +} + +U_NAMESPACE_BEGIN + +/* + * This DateFormatSymbolsSingleSetter class is a friend of DateFormatSymbols + * solely for the purpose of avoiding to clone the array of strings + * just to modify one of them and then setting all of them back. + * For example, the old code looked like this: + * case UDAT_MONTHS: + * res = syms->getMonths(count); + * array = new UnicodeString[count]; + * if(array == 0) { + * *status = U_MEMORY_ALLOCATION_ERROR; + * return; + * } + * uprv_arrayCopy(res, array, count); + * if(index < count) + * array[index] = val; + * syms->setMonths(array, count); + * break; + * + * Even worse, the old code actually cloned the entire DateFormatSymbols object, + * cloned one value array, changed one value, and then made the SimpleDateFormat + * replace its DateFormatSymbols object with the new one. + * + * markus 2002-oct-14 + */ +class DateFormatSymbolsSingleSetter /* not : public UObject because all methods are static */ { +public: + static void + setSymbol(UnicodeString *array, int32_t count, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + if(array!=NULL) { + if(index>=count) { + errorCode=U_INDEX_OUTOFBOUNDS_ERROR; + } else if(value==NULL) { + errorCode=U_ILLEGAL_ARGUMENT_ERROR; + } else { + array[index].setTo(value, valueLength); + } + } + } + + static void + setEra(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fEras, syms->fErasCount, index, value, valueLength, errorCode); + } + + static void + setEraName(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fEraNames, syms->fEraNamesCount, index, value, valueLength, errorCode); + } + + static void + setMonth(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fMonths, syms->fMonthsCount, index, value, valueLength, errorCode); + } + + static void + setShortMonth(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fShortMonths, syms->fShortMonthsCount, index, value, valueLength, errorCode); + } + + static void + setNarrowMonth(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fNarrowMonths, syms->fNarrowMonthsCount, index, value, valueLength, errorCode); + } + + static void + setStandaloneMonth(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fStandaloneMonths, syms->fStandaloneMonthsCount, index, value, valueLength, errorCode); + } + + static void + setStandaloneShortMonth(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fStandaloneShortMonths, syms->fStandaloneShortMonthsCount, index, value, valueLength, errorCode); + } + + static void + setStandaloneNarrowMonth(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fStandaloneNarrowMonths, syms->fStandaloneNarrowMonthsCount, index, value, valueLength, errorCode); + } + + static void + setWeekday(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fWeekdays, syms->fWeekdaysCount, index, value, valueLength, errorCode); + } + + static void + setShortWeekday(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fShortWeekdays, syms->fShortWeekdaysCount, index, value, valueLength, errorCode); + } + + static void + setShorterWeekday(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fShorterWeekdays, syms->fShorterWeekdaysCount, index, value, valueLength, errorCode); + } + + static void + setNarrowWeekday(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fNarrowWeekdays, syms->fNarrowWeekdaysCount, index, value, valueLength, errorCode); + } + + static void + setStandaloneWeekday(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fStandaloneWeekdays, syms->fStandaloneWeekdaysCount, index, value, valueLength, errorCode); + } + + static void + setStandaloneShortWeekday(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fStandaloneShortWeekdays, syms->fStandaloneShortWeekdaysCount, index, value, valueLength, errorCode); + } + + static void + setStandaloneShorterWeekday(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fStandaloneShorterWeekdays, syms->fStandaloneShorterWeekdaysCount, index, value, valueLength, errorCode); + } + + static void + setStandaloneNarrowWeekday(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fStandaloneNarrowWeekdays, syms->fStandaloneNarrowWeekdaysCount, index, value, valueLength, errorCode); + } + + static void + setQuarter(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fQuarters, syms->fQuartersCount, index, value, valueLength, errorCode); + } + + static void + setShortQuarter(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fShortQuarters, syms->fShortQuartersCount, index, value, valueLength, errorCode); + } + + static void + setStandaloneQuarter(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fStandaloneQuarters, syms->fStandaloneQuartersCount, index, value, valueLength, errorCode); + } + + static void + setStandaloneShortQuarter(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fStandaloneShortQuarters, syms->fStandaloneShortQuartersCount, index, value, valueLength, errorCode); + } + + static void + setShortYearNames(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fShortYearNames, syms->fShortYearNamesCount, index, value, valueLength, errorCode); + } + + static void + setShortZodiacNames(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fShortZodiacNames, syms->fShortZodiacNamesCount, index, value, valueLength, errorCode); + } + + static void + setAmPm(DateFormatSymbols *syms, int32_t index, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(syms->fAmPms, syms->fAmPmsCount, index, value, valueLength, errorCode); + } + + static void + setLocalPatternChars(DateFormatSymbols *syms, + const UChar *value, int32_t valueLength, UErrorCode &errorCode) + { + setSymbol(&syms->fLocalPatternChars, 1, 0, value, valueLength, errorCode); + } +}; + +U_NAMESPACE_END + +U_CAPI void U_EXPORT2 +udat_setSymbols( UDateFormat *format, + UDateFormatSymbolType type, + int32_t index, + UChar *value, + int32_t valueLength, + UErrorCode *status) +{ + verifyIsSimpleDateFormat(format, status); + if(U_FAILURE(*status)) return; + + DateFormatSymbols *syms = (DateFormatSymbols *)((SimpleDateFormat *)format)->getDateFormatSymbols(); + + switch(type) { + case UDAT_ERAS: + DateFormatSymbolsSingleSetter::setEra(syms, index, value, valueLength, *status); + break; + + case UDAT_ERA_NAMES: + DateFormatSymbolsSingleSetter::setEraName(syms, index, value, valueLength, *status); + break; + + case UDAT_MONTHS: + DateFormatSymbolsSingleSetter::setMonth(syms, index, value, valueLength, *status); + break; + + case UDAT_SHORT_MONTHS: + DateFormatSymbolsSingleSetter::setShortMonth(syms, index, value, valueLength, *status); + break; + + case UDAT_NARROW_MONTHS: + DateFormatSymbolsSingleSetter::setNarrowMonth(syms, index, value, valueLength, *status); + break; + + case UDAT_STANDALONE_MONTHS: + DateFormatSymbolsSingleSetter::setStandaloneMonth(syms, index, value, valueLength, *status); + break; + + case UDAT_STANDALONE_SHORT_MONTHS: + DateFormatSymbolsSingleSetter::setStandaloneShortMonth(syms, index, value, valueLength, *status); + break; + + case UDAT_STANDALONE_NARROW_MONTHS: + DateFormatSymbolsSingleSetter::setStandaloneNarrowMonth(syms, index, value, valueLength, *status); + break; + + case UDAT_WEEKDAYS: + DateFormatSymbolsSingleSetter::setWeekday(syms, index, value, valueLength, *status); + break; + + case UDAT_SHORT_WEEKDAYS: + DateFormatSymbolsSingleSetter::setShortWeekday(syms, index, value, valueLength, *status); + break; + + case UDAT_SHORTER_WEEKDAYS: + DateFormatSymbolsSingleSetter::setShorterWeekday(syms, index, value, valueLength, *status); + break; + + case UDAT_NARROW_WEEKDAYS: + DateFormatSymbolsSingleSetter::setNarrowWeekday(syms, index, value, valueLength, *status); + break; + + case UDAT_STANDALONE_WEEKDAYS: + DateFormatSymbolsSingleSetter::setStandaloneWeekday(syms, index, value, valueLength, *status); + break; + + case UDAT_STANDALONE_SHORT_WEEKDAYS: + DateFormatSymbolsSingleSetter::setStandaloneShortWeekday(syms, index, value, valueLength, *status); + break; + + case UDAT_STANDALONE_SHORTER_WEEKDAYS: + DateFormatSymbolsSingleSetter::setStandaloneShorterWeekday(syms, index, value, valueLength, *status); + break; + + case UDAT_STANDALONE_NARROW_WEEKDAYS: + DateFormatSymbolsSingleSetter::setStandaloneNarrowWeekday(syms, index, value, valueLength, *status); + break; + + case UDAT_QUARTERS: + DateFormatSymbolsSingleSetter::setQuarter(syms, index, value, valueLength, *status); + break; + + case UDAT_SHORT_QUARTERS: + DateFormatSymbolsSingleSetter::setShortQuarter(syms, index, value, valueLength, *status); + break; + + case UDAT_STANDALONE_QUARTERS: + DateFormatSymbolsSingleSetter::setStandaloneQuarter(syms, index, value, valueLength, *status); + break; + + case UDAT_STANDALONE_SHORT_QUARTERS: + DateFormatSymbolsSingleSetter::setStandaloneShortQuarter(syms, index, value, valueLength, *status); + break; + + case UDAT_CYCLIC_YEARS_ABBREVIATED: + DateFormatSymbolsSingleSetter::setShortYearNames(syms, index, value, valueLength, *status); + break; + + case UDAT_ZODIAC_NAMES_ABBREVIATED: + DateFormatSymbolsSingleSetter::setShortZodiacNames(syms, index, value, valueLength, *status); + break; + + case UDAT_AM_PMS: + DateFormatSymbolsSingleSetter::setAmPm(syms, index, value, valueLength, *status); + break; + + case UDAT_LOCALIZED_CHARS: + DateFormatSymbolsSingleSetter::setLocalPatternChars(syms, value, valueLength, *status); + break; + + default: + *status = U_UNSUPPORTED_ERROR; + break; + + } +} + +U_CAPI const char* U_EXPORT2 +udat_getLocaleByType(const UDateFormat *fmt, + ULocDataLocaleType type, + UErrorCode* status) +{ + if (fmt == NULL) { + if (U_SUCCESS(*status)) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + } + return NULL; + } + return ((Format*)fmt)->getLocaleID(type, *status); +} + +U_CAPI void U_EXPORT2 +udat_setContext(UDateFormat* fmt, UDisplayContext value, UErrorCode* status) +{ + if (U_FAILURE(*status)) { + return; + } + ((DateFormat*)fmt)->setContext(value, *status); + return; +} + +U_CAPI UDisplayContext U_EXPORT2 +udat_getContext(const UDateFormat* fmt, UDisplayContextType type, UErrorCode* status) +{ + if (U_FAILURE(*status)) { + return (UDisplayContext)0; + } + return ((const DateFormat*)fmt)->getContext(type, *status); +} + + +/** + * Verify that fmt is a RelativeDateFormat. Invalid error if not. + * @param fmt the UDateFormat, definitely a DateFormat, maybe something else + * @param status error code, will be set to failure if there is a familure or the fmt is NULL. + */ +static void verifyIsRelativeDateFormat(const UDateFormat* fmt, UErrorCode *status) { + if(U_SUCCESS(*status) && + dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + } +} + + +U_CAPI int32_t U_EXPORT2 +udat_toPatternRelativeDate(const UDateFormat *fmt, + UChar *result, + int32_t resultLength, + UErrorCode *status) +{ + verifyIsRelativeDateFormat(fmt, status); + if(U_FAILURE(*status)) { + return -1; + } + if (result == NULL ? resultLength != 0 : resultLength < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + + UnicodeString datePattern; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + datePattern.setTo(result, 0, resultLength); + } + ((RelativeDateFormat*)fmt)->toPatternDate(datePattern, *status); + return datePattern.extract(result, resultLength, *status); +} + +U_CAPI int32_t U_EXPORT2 +udat_toPatternRelativeTime(const UDateFormat *fmt, + UChar *result, + int32_t resultLength, + UErrorCode *status) +{ + verifyIsRelativeDateFormat(fmt, status); + if(U_FAILURE(*status)) { + return -1; + } + if (result == NULL ? resultLength != 0 : resultLength < 0) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return -1; + } + + UnicodeString timePattern; + if (result != NULL) { + // NULL destination for pure preflighting: empty dummy string + // otherwise, alias the destination buffer + timePattern.setTo(result, 0, resultLength); + } + ((RelativeDateFormat*)fmt)->toPatternTime(timePattern, *status); + return timePattern.extract(result, resultLength, *status); +} + +U_CAPI void U_EXPORT2 +udat_applyPatternRelative(UDateFormat *format, + const UChar *datePattern, + int32_t datePatternLength, + const UChar *timePattern, + int32_t timePatternLength, + UErrorCode *status) +{ + verifyIsRelativeDateFormat(format, status); + if(U_FAILURE(*status)) return; + const UnicodeString datePat((UBool)(datePatternLength == -1), datePattern, datePatternLength); + const UnicodeString timePat((UBool)(timePatternLength == -1), timePattern, timePatternLength); + ((RelativeDateFormat*)format)->applyPatterns(datePat, timePat, *status); +} + +#endif /* #if !UCONFIG_NO_FORMATTING */ |