// © 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 */