// © 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(reinterpret_cast(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_AM_PM_MIDNIGHT_NOON_FIELD=35 (no match) UCAL_FIELD_COUNT, // UDAT_FLEXIBLE_DAY_PERIOD_FIELD=36 (no match) UCAL_FIELD_COUNT, // UDAT_TIME_SEPARATOR_FIELD = 37 (no match) // UDAT_FIELD_COUNT = 38 as of ICU 67 // UCAL_IS_LEAP_MONTH is not the target of a mapping }; U_CAPI UCalendarDateFields U_EXPORT2 udat_toCalendarDateField(UDateFormatField field) { static_assert(UDAT_FIELD_COUNT == UPRV_LENGTHOF(gDateFieldMapping), "UDateFormatField and gDateFieldMapping should have the same number of entries and be kept in sync."); return (field >= UDAT_ERA_FIELD && field < UPRV_LENGTHOF(gDateFieldMapping))? gDateFieldMapping[field]: UCAL_FIELD_COUNT; } /* 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 == nullptr) { *status = U_MEMORY_ALLOCATION_ERROR; return nullptr; } if (U_FAILURE(*status)) { delete fmt; return nullptr; } 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(fmt); const SimpleDateFormat *sdtfmt=dynamic_cast(df); const RelativeDateFormat *reldtfmt; if (sdtfmt!=NULL) { if(localized) sdtfmt->toLocalizedPattern(res, *status); else sdtfmt->toPattern(res); } else if (!localized && (reldtfmt=dynamic_cast(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(reinterpret_cast(fmt))) != NULL) { syms = sdtfmt->getDateFormatSymbols(); } else if ((rdtfmt = dynamic_cast(reinterpret_cast(fmt))) != NULL) { syms = rdtfmt->getDateFormatSymbols(); } else { return -1; } int32_t count = 0; 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(reinterpret_cast(fmt))) != NULL) { syms = sdtfmt->getDateFormatSymbols(); } else if ((rdtfmt = dynamic_cast(reinterpret_cast(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(reinterpret_cast(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 */