1/*
2*******************************************************************************
3*   Copyright (C) 1996-2010, International Business Machines
4*   Corporation and others.  All Rights Reserved.
5*******************************************************************************
6*/
7
8#include "unicode/utypes.h"
9
10#if !UCONFIG_NO_FORMATTING
11
12#include "unicode/udat.h"
13
14#include "unicode/uloc.h"
15#include "unicode/datefmt.h"
16#include "unicode/timezone.h"
17#include "unicode/smpdtfmt.h"
18#include "unicode/fieldpos.h"
19#include "unicode/parsepos.h"
20#include "unicode/calendar.h"
21#include "unicode/numfmt.h"
22#include "unicode/dtfmtsym.h"
23#include "unicode/ustring.h"
24#include "cpputils.h"
25#include "reldtfmt.h"
26
27U_NAMESPACE_USE
28
29/**
30 * Verify that fmt is a SimpleDateFormat. Invalid error if not.
31 * @param fmt the UDateFormat, definitely a DateFormat, maybe something else
32 * @param status error code, will be set to failure if there is a familure or the fmt is NULL.
33 */
34static void verifyIsSimpleDateFormat(const UDateFormat* fmt, UErrorCode *status) {
35   if(U_SUCCESS(*status) &&
36       dynamic_cast<const SimpleDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) {
37       *status = U_ILLEGAL_ARGUMENT_ERROR;
38   }
39}
40
41// This mirrors the correspondence between the
42// SimpleDateFormat::fgPatternIndexToDateFormatField and
43// SimpleDateFormat::fgPatternIndexToCalendarField arrays.
44static UCalendarDateFields gDateFieldMapping[] = {
45    UCAL_ERA,                  // UDAT_ERA_FIELD = 0
46    UCAL_YEAR,                 // UDAT_YEAR_FIELD = 1
47    UCAL_MONTH,                // UDAT_MONTH_FIELD = 2
48    UCAL_DATE,                 // UDAT_DATE_FIELD = 3
49    UCAL_HOUR_OF_DAY,          // UDAT_HOUR_OF_DAY1_FIELD = 4
50    UCAL_HOUR_OF_DAY,          // UDAT_HOUR_OF_DAY0_FIELD = 5
51    UCAL_MINUTE,               // UDAT_MINUTE_FIELD = 6
52    UCAL_SECOND,               // UDAT_SECOND_FIELD = 7
53    UCAL_MILLISECOND,          // UDAT_FRACTIONAL_SECOND_FIELD = 8
54    UCAL_DAY_OF_WEEK,          // UDAT_DAY_OF_WEEK_FIELD = 9
55    UCAL_DAY_OF_YEAR,          // UDAT_DAY_OF_YEAR_FIELD = 10
56    UCAL_DAY_OF_WEEK_IN_MONTH, // UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11
57    UCAL_WEEK_OF_YEAR,         // UDAT_WEEK_OF_YEAR_FIELD = 12
58    UCAL_WEEK_OF_MONTH,        // UDAT_WEEK_OF_MONTH_FIELD = 13
59    UCAL_AM_PM,                // UDAT_AM_PM_FIELD = 14
60    UCAL_HOUR,                 // UDAT_HOUR1_FIELD = 15
61    UCAL_HOUR,                 // UDAT_HOUR0_FIELD = 16
62    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_FIELD = 17
63    UCAL_YEAR_WOY,             // UDAT_YEAR_WOY_FIELD = 18
64    UCAL_DOW_LOCAL,            // UDAT_DOW_LOCAL_FIELD = 19
65    UCAL_EXTENDED_YEAR,        // UDAT_EXTENDED_YEAR_FIELD = 20
66    UCAL_JULIAN_DAY,           // UDAT_JULIAN_DAY_FIELD = 21
67    UCAL_MILLISECONDS_IN_DAY,  // UDAT_MILLISECONDS_IN_DAY_FIELD = 22
68    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_RFC_FIELD = 23
69    // UCAL_DST_OFFSET also
70    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_GENERIC_FIELD = 24
71    UCAL_DOW_LOCAL,            // UDAT_STANDALONE_DAY_FIELD = 25
72    UCAL_MONTH,                // UDAT_STANDALONE_MONTH_FIELD = 26
73    UCAL_MONTH,                // UDAT_QUARTER_FIELD = 27
74    UCAL_MONTH,                // UDAT_STANDALONE_QUARTER_FIELD = 28
75    UCAL_ZONE_OFFSET,          // UDAT_TIMEZONE_SPECIAL_FIELD = 29
76    UCAL_FIELD_COUNT,          // UDAT_FIELD_COUNT = 30
77    // UCAL_IS_LEAP_MONTH is not the target of a mapping
78};
79
80U_CAPI UCalendarDateFields U_EXPORT2
81udat_toCalendarDateField(UDateFormatField field) {
82  return gDateFieldMapping[field];
83}
84
85U_CAPI UDateFormat* U_EXPORT2
86udat_open(UDateFormatStyle  timeStyle,
87          UDateFormatStyle  dateStyle,
88          const char        *locale,
89          const UChar       *tzID,
90          int32_t           tzIDLength,
91          const UChar       *pattern,
92          int32_t           patternLength,
93          UErrorCode        *status)
94{
95    DateFormat *fmt;
96    if(U_FAILURE(*status)) {
97        return 0;
98    }
99    if(timeStyle != UDAT_IGNORE) {
100        if(locale == 0) {
101            fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
102                (DateFormat::EStyle)timeStyle);
103        }
104        else {
105            fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
106                (DateFormat::EStyle)timeStyle,
107                Locale(locale));
108        }
109    }
110    else {
111        UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength);
112
113        if(locale == 0) {
114            fmt = new SimpleDateFormat(pat, *status);
115        }
116        else {
117            fmt = new SimpleDateFormat(pat, Locale(locale), *status);
118        }
119    }
120
121    if(fmt == 0) {
122        *status = U_MEMORY_ALLOCATION_ERROR;
123        return 0;
124    }
125
126    if(tzID != 0) {
127        TimeZone *zone = TimeZone::createTimeZone(UnicodeString((UBool)(tzIDLength == -1), tzID, tzIDLength));
128        if(zone == 0) {
129            *status = U_MEMORY_ALLOCATION_ERROR;
130            delete fmt;
131            return 0;
132        }
133        fmt->adoptTimeZone(zone);
134    }
135
136    return (UDateFormat*)fmt;
137}
138
139
140U_CAPI void U_EXPORT2
141udat_close(UDateFormat* format)
142{
143    delete (DateFormat*)format;
144}
145
146U_CAPI UDateFormat* U_EXPORT2
147udat_clone(const UDateFormat *fmt,
148       UErrorCode *status)
149{
150    if(U_FAILURE(*status)) return 0;
151
152    Format *res = ((DateFormat*)fmt)->clone();
153
154    if(res == 0) {
155        *status = U_MEMORY_ALLOCATION_ERROR;
156        return 0;
157    }
158
159    return (UDateFormat*) res;
160}
161
162U_CAPI int32_t U_EXPORT2
163udat_format(    const    UDateFormat*    format,
164        UDate           dateToFormat,
165        UChar*          result,
166        int32_t         resultLength,
167        UFieldPosition* position,
168        UErrorCode*     status)
169{
170    if(U_FAILURE(*status)) return -1;
171
172    UnicodeString res;
173    if(!(result==NULL && resultLength==0)) {
174        // NULL destination for pure preflighting: empty dummy string
175        // otherwise, alias the destination buffer
176        res.setTo(result, 0, resultLength);
177    }
178
179    FieldPosition fp;
180
181    if(position != 0)
182        fp.setField(position->field);
183
184    ((DateFormat*)format)->format(dateToFormat, res, fp);
185
186    if(position != 0) {
187        position->beginIndex = fp.getBeginIndex();
188        position->endIndex = fp.getEndIndex();
189    }
190
191    return res.extract(result, resultLength, *status);
192}
193
194U_CAPI UDate U_EXPORT2
195udat_parse(    const    UDateFormat*        format,
196        const    UChar*          text,
197        int32_t         textLength,
198        int32_t         *parsePos,
199        UErrorCode      *status)
200{
201    if(U_FAILURE(*status)) return (UDate)0;
202
203    const UnicodeString src((UBool)(textLength == -1), text, textLength);
204    ParsePosition pp;
205    int32_t stackParsePos = 0;
206    UDate res;
207
208    if(parsePos == NULL) {
209        parsePos = &stackParsePos;
210    }
211
212    pp.setIndex(*parsePos);
213
214    res = ((DateFormat*)format)->parse(src, pp);
215
216    if(pp.getErrorIndex() == -1)
217        *parsePos = pp.getIndex();
218    else {
219        *parsePos = pp.getErrorIndex();
220        *status = U_PARSE_ERROR;
221    }
222
223    return res;
224}
225
226U_CAPI void U_EXPORT2
227udat_parseCalendar(const    UDateFormat*    format,
228                            UCalendar*      calendar,
229                   const    UChar*          text,
230                            int32_t         textLength,
231                            int32_t         *parsePos,
232                            UErrorCode      *status)
233{
234    if(U_FAILURE(*status)) return;
235
236    const UnicodeString src((UBool)(textLength == -1), text, textLength);
237    ParsePosition pp;
238
239    if(parsePos != 0)
240        pp.setIndex(*parsePos);
241
242    ((DateFormat*)format)->parse(src, *(Calendar*)calendar, pp);
243
244    if(parsePos != 0) {
245        if(pp.getErrorIndex() == -1)
246            *parsePos = pp.getIndex();
247        else {
248            *parsePos = pp.getErrorIndex();
249            *status = U_PARSE_ERROR;
250        }
251    }
252}
253
254U_CAPI UBool U_EXPORT2
255udat_isLenient(const UDateFormat* fmt)
256{
257    return ((DateFormat*)fmt)->isLenient();
258}
259
260U_CAPI void U_EXPORT2
261udat_setLenient(    UDateFormat*    fmt,
262            UBool          isLenient)
263{
264    ((DateFormat*)fmt)->setLenient(isLenient);
265}
266
267U_CAPI const UCalendar* U_EXPORT2
268udat_getCalendar(const UDateFormat* fmt)
269{
270    return (const UCalendar*) ((DateFormat*)fmt)->getCalendar();
271}
272
273U_CAPI void U_EXPORT2
274udat_setCalendar(UDateFormat*    fmt,
275                 const   UCalendar*      calendarToSet)
276{
277    ((DateFormat*)fmt)->setCalendar(*((Calendar*)calendarToSet));
278}
279
280U_CAPI const UNumberFormat* U_EXPORT2
281udat_getNumberFormat(const UDateFormat* fmt)
282{
283    return (const UNumberFormat*) ((DateFormat*)fmt)->getNumberFormat();
284}
285
286U_CAPI void U_EXPORT2
287udat_setNumberFormat(UDateFormat*    fmt,
288                     const   UNumberFormat*  numberFormatToSet)
289{
290    ((DateFormat*)fmt)->setNumberFormat(*((NumberFormat*)numberFormatToSet));
291}
292
293U_CAPI const char* U_EXPORT2
294udat_getAvailable(int32_t index)
295{
296    return uloc_getAvailable(index);
297}
298
299U_CAPI int32_t U_EXPORT2
300udat_countAvailable()
301{
302    return uloc_countAvailable();
303}
304
305U_CAPI UDate U_EXPORT2
306udat_get2DigitYearStart(    const   UDateFormat     *fmt,
307                        UErrorCode      *status)
308{
309    verifyIsSimpleDateFormat(fmt, status);
310    if(U_FAILURE(*status)) return (UDate)0;
311    return ((SimpleDateFormat*)fmt)->get2DigitYearStart(*status);
312}
313
314U_CAPI void U_EXPORT2
315udat_set2DigitYearStart(    UDateFormat     *fmt,
316                        UDate           d,
317                        UErrorCode      *status)
318{
319    verifyIsSimpleDateFormat(fmt, status);
320    if(U_FAILURE(*status)) return;
321    ((SimpleDateFormat*)fmt)->set2DigitYearStart(d, *status);
322}
323
324U_CAPI int32_t U_EXPORT2
325udat_toPattern(    const   UDateFormat     *fmt,
326        UBool          localized,
327        UChar           *result,
328        int32_t         resultLength,
329        UErrorCode      *status)
330{
331    if(U_FAILURE(*status)) return -1;
332
333    UnicodeString res;
334    if(!(result==NULL && resultLength==0)) {
335        // NULL destination for pure preflighting: empty dummy string
336        // otherwise, alias the destination buffer
337        res.setTo(result, 0, resultLength);
338    }
339
340    const DateFormat *df=reinterpret_cast<const DateFormat *>(fmt);
341    const SimpleDateFormat *sdtfmt=dynamic_cast<const SimpleDateFormat *>(df);
342    const RelativeDateFormat *reldtfmt;
343    if (sdtfmt!=NULL) {
344        if(localized)
345            sdtfmt->toLocalizedPattern(res, *status);
346        else
347            sdtfmt->toPattern(res);
348    } else if (!localized && (reldtfmt=dynamic_cast<const RelativeDateFormat *>(df))!=NULL) {
349        reldtfmt->toPattern(res, *status);
350    } else {
351        *status = U_ILLEGAL_ARGUMENT_ERROR;
352        return -1;
353    }
354
355    return res.extract(result, resultLength, *status);
356}
357
358// TODO: should this take an UErrorCode?
359// A: Yes. Of course.
360U_CAPI void U_EXPORT2
361udat_applyPattern(  UDateFormat     *format,
362                    UBool          localized,
363                    const   UChar           *pattern,
364                    int32_t         patternLength)
365{
366    const UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength);
367    UErrorCode status = U_ZERO_ERROR;
368
369    verifyIsSimpleDateFormat(format, &status);
370    if(U_FAILURE(status)) {
371        return;
372    }
373
374    if(localized)
375        ((SimpleDateFormat*)format)->applyLocalizedPattern(pat, status);
376    else
377        ((SimpleDateFormat*)format)->applyPattern(pat);
378}
379
380U_CAPI int32_t U_EXPORT2
381udat_getSymbols(const   UDateFormat     *fmt,
382                UDateFormatSymbolType   type,
383                int32_t                 index,
384                UChar                   *result,
385                int32_t                 resultLength,
386                UErrorCode              *status)
387{
388    verifyIsSimpleDateFormat(fmt, status);
389    if(U_FAILURE(*status)) return -1;
390
391    const DateFormatSymbols *syms =
392        ((SimpleDateFormat*)fmt)->getDateFormatSymbols();
393    int32_t count;
394    const UnicodeString *res = NULL;
395
396    switch(type) {
397    case UDAT_ERAS:
398        res = syms->getEras(count);
399        break;
400
401    case UDAT_ERA_NAMES:
402        res = syms->getEraNames(count);
403        break;
404
405    case UDAT_MONTHS:
406        res = syms->getMonths(count);
407        break;
408
409    case UDAT_SHORT_MONTHS:
410        res = syms->getShortMonths(count);
411        break;
412
413    case UDAT_WEEKDAYS:
414        res = syms->getWeekdays(count);
415        break;
416
417    case UDAT_SHORT_WEEKDAYS:
418        res = syms->getShortWeekdays(count);
419        break;
420
421    case UDAT_AM_PMS:
422        res = syms->getAmPmStrings(count);
423        break;
424
425    case UDAT_LOCALIZED_CHARS:
426        {
427            UnicodeString res1;
428            if(!(result==NULL && resultLength==0)) {
429                // NULL destination for pure preflighting: empty dummy string
430                // otherwise, alias the destination buffer
431                res1.setTo(result, 0, resultLength);
432            }
433            syms->getLocalPatternChars(res1);
434            return res1.extract(result, resultLength, *status);
435        }
436
437    case UDAT_NARROW_MONTHS:
438        res = syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
439        break;
440
441    case UDAT_NARROW_WEEKDAYS:
442        res = syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
443        break;
444
445    case UDAT_STANDALONE_MONTHS:
446        res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
447        break;
448
449    case UDAT_STANDALONE_SHORT_MONTHS:
450        res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
451        break;
452
453    case UDAT_STANDALONE_NARROW_MONTHS:
454        res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
455        break;
456
457    case UDAT_STANDALONE_WEEKDAYS:
458        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
459        break;
460
461    case UDAT_STANDALONE_SHORT_WEEKDAYS:
462        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
463        break;
464
465    case UDAT_STANDALONE_NARROW_WEEKDAYS:
466        res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
467        break;
468
469    case UDAT_QUARTERS:
470        res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
471        break;
472
473    case UDAT_SHORT_QUARTERS:
474        res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
475        break;
476
477    case UDAT_STANDALONE_QUARTERS:
478        res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
479        break;
480
481    case UDAT_STANDALONE_SHORT_QUARTERS:
482        res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
483        break;
484
485    }
486
487    if(index < count) {
488        return res[index].extract(result, resultLength, *status);
489    }
490    return 0;
491}
492
493// TODO: also needs an errorCode.
494U_CAPI int32_t U_EXPORT2
495udat_countSymbols(    const    UDateFormat                *fmt,
496            UDateFormatSymbolType    type)
497{
498    UErrorCode status = U_ZERO_ERROR;
499
500    verifyIsSimpleDateFormat(fmt, &status);
501    if(U_FAILURE(status)) {
502        return 0;
503    }
504
505    const DateFormatSymbols *syms =
506        ((SimpleDateFormat*)fmt)->getDateFormatSymbols();
507    int32_t count = 0;
508
509    switch(type) {
510    case UDAT_ERAS:
511        syms->getEras(count);
512        break;
513
514    case UDAT_MONTHS:
515        syms->getMonths(count);
516        break;
517
518    case UDAT_SHORT_MONTHS:
519        syms->getShortMonths(count);
520        break;
521
522    case UDAT_WEEKDAYS:
523        syms->getWeekdays(count);
524        break;
525
526    case UDAT_SHORT_WEEKDAYS:
527        syms->getShortWeekdays(count);
528        break;
529
530    case UDAT_AM_PMS:
531        syms->getAmPmStrings(count);
532        break;
533
534    case UDAT_LOCALIZED_CHARS:
535        count = 1;
536        break;
537
538    case UDAT_ERA_NAMES:
539        syms->getEraNames(count);
540        break;
541
542    case UDAT_NARROW_MONTHS:
543        syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
544        break;
545
546    case UDAT_NARROW_WEEKDAYS:
547        syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
548        break;
549
550    case UDAT_STANDALONE_MONTHS:
551        syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
552        break;
553
554    case UDAT_STANDALONE_SHORT_MONTHS:
555        syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
556        break;
557
558    case UDAT_STANDALONE_NARROW_MONTHS:
559        syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
560        break;
561
562    case UDAT_STANDALONE_WEEKDAYS:
563        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
564        break;
565
566    case UDAT_STANDALONE_SHORT_WEEKDAYS:
567        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
568        break;
569
570    case UDAT_STANDALONE_NARROW_WEEKDAYS:
571        syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
572        break;
573
574    case UDAT_QUARTERS:
575        syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
576        break;
577
578    case UDAT_SHORT_QUARTERS:
579        syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
580        break;
581
582    case UDAT_STANDALONE_QUARTERS:
583        syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
584        break;
585
586    case UDAT_STANDALONE_SHORT_QUARTERS:
587        syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
588        break;
589
590    }
591
592    return count;
593}
594
595U_NAMESPACE_BEGIN
596
597/*
598 * This DateFormatSymbolsSingleSetter class is a friend of DateFormatSymbols
599 * solely for the purpose of avoiding to clone the array of strings
600 * just to modify one of them and then setting all of them back.
601 * For example, the old code looked like this:
602 *  case UDAT_MONTHS:
603 *    res = syms->getMonths(count);
604 *    array = new UnicodeString[count];
605 *    if(array == 0) {
606 *      *status = U_MEMORY_ALLOCATION_ERROR;
607 *      return;
608 *    }
609 *    uprv_arrayCopy(res, array, count);
610 *    if(index < count)
611 *      array[index] = val;
612 *    syms->setMonths(array, count);
613 *    break;
614 *
615 * Even worse, the old code actually cloned the entire DateFormatSymbols object,
616 * cloned one value array, changed one value, and then made the SimpleDateFormat
617 * replace its DateFormatSymbols object with the new one.
618 *
619 * markus 2002-oct-14
620 */
621class DateFormatSymbolsSingleSetter /* not : public UObject because all methods are static */ {
622public:
623    static void
624        setSymbol(UnicodeString *array, int32_t count, int32_t index,
625        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
626    {
627        if(array!=NULL) {
628            if(index>=count) {
629                errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
630            } else if(value==NULL) {
631                errorCode=U_ILLEGAL_ARGUMENT_ERROR;
632            } else {
633                array[index].setTo(value, valueLength);
634            }
635        }
636    }
637
638    static void
639        setEra(DateFormatSymbols *syms, int32_t index,
640        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
641    {
642        setSymbol(syms->fEras, syms->fErasCount, index, value, valueLength, errorCode);
643    }
644
645    static void
646        setEraName(DateFormatSymbols *syms, int32_t index,
647        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
648    {
649        setSymbol(syms->fEraNames, syms->fEraNamesCount, index, value, valueLength, errorCode);
650    }
651
652    static void
653        setMonth(DateFormatSymbols *syms, int32_t index,
654        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
655    {
656        setSymbol(syms->fMonths, syms->fMonthsCount, index, value, valueLength, errorCode);
657    }
658
659    static void
660        setShortMonth(DateFormatSymbols *syms, int32_t index,
661        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
662    {
663        setSymbol(syms->fShortMonths, syms->fShortMonthsCount, index, value, valueLength, errorCode);
664    }
665
666    static void
667        setNarrowMonth(DateFormatSymbols *syms, int32_t index,
668        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
669    {
670        setSymbol(syms->fNarrowMonths, syms->fNarrowMonthsCount, index, value, valueLength, errorCode);
671    }
672
673    static void
674        setStandaloneMonth(DateFormatSymbols *syms, int32_t index,
675        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
676    {
677        setSymbol(syms->fStandaloneMonths, syms->fStandaloneMonthsCount, index, value, valueLength, errorCode);
678    }
679
680    static void
681        setStandaloneShortMonth(DateFormatSymbols *syms, int32_t index,
682        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
683    {
684        setSymbol(syms->fStandaloneShortMonths, syms->fStandaloneShortMonthsCount, index, value, valueLength, errorCode);
685    }
686
687    static void
688        setStandaloneNarrowMonth(DateFormatSymbols *syms, int32_t index,
689        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
690    {
691        setSymbol(syms->fStandaloneNarrowMonths, syms->fStandaloneNarrowMonthsCount, index, value, valueLength, errorCode);
692    }
693
694    static void
695        setWeekday(DateFormatSymbols *syms, int32_t index,
696        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
697    {
698        setSymbol(syms->fWeekdays, syms->fWeekdaysCount, index, value, valueLength, errorCode);
699    }
700
701    static void
702        setShortWeekday(DateFormatSymbols *syms, int32_t index,
703        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
704    {
705        setSymbol(syms->fShortWeekdays, syms->fShortWeekdaysCount, index, value, valueLength, errorCode);
706    }
707
708    static void
709        setNarrowWeekday(DateFormatSymbols *syms, int32_t index,
710        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
711    {
712        setSymbol(syms->fNarrowWeekdays, syms->fNarrowWeekdaysCount, index, value, valueLength, errorCode);
713    }
714
715    static void
716        setStandaloneWeekday(DateFormatSymbols *syms, int32_t index,
717        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
718    {
719        setSymbol(syms->fStandaloneWeekdays, syms->fStandaloneWeekdaysCount, index, value, valueLength, errorCode);
720    }
721
722    static void
723        setStandaloneShortWeekday(DateFormatSymbols *syms, int32_t index,
724        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
725    {
726        setSymbol(syms->fStandaloneShortWeekdays, syms->fStandaloneShortWeekdaysCount, index, value, valueLength, errorCode);
727    }
728
729    static void
730        setStandaloneNarrowWeekday(DateFormatSymbols *syms, int32_t index,
731        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
732    {
733        setSymbol(syms->fStandaloneNarrowWeekdays, syms->fStandaloneNarrowWeekdaysCount, index, value, valueLength, errorCode);
734    }
735
736    static void
737        setQuarter(DateFormatSymbols *syms, int32_t index,
738        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
739    {
740        setSymbol(syms->fQuarters, syms->fQuartersCount, index, value, valueLength, errorCode);
741    }
742
743    static void
744        setShortQuarter(DateFormatSymbols *syms, int32_t index,
745        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
746    {
747        setSymbol(syms->fShortQuarters, syms->fShortQuartersCount, index, value, valueLength, errorCode);
748    }
749
750    static void
751        setStandaloneQuarter(DateFormatSymbols *syms, int32_t index,
752        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
753    {
754        setSymbol(syms->fStandaloneQuarters, syms->fStandaloneQuartersCount, index, value, valueLength, errorCode);
755    }
756
757    static void
758        setStandaloneShortQuarter(DateFormatSymbols *syms, int32_t index,
759        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
760    {
761        setSymbol(syms->fStandaloneShortQuarters, syms->fStandaloneShortQuartersCount, index, value, valueLength, errorCode);
762    }
763
764    static void
765        setAmPm(DateFormatSymbols *syms, int32_t index,
766        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
767    {
768        setSymbol(syms->fAmPms, syms->fAmPmsCount, index, value, valueLength, errorCode);
769    }
770
771    static void
772        setLocalPatternChars(DateFormatSymbols *syms,
773        const UChar *value, int32_t valueLength, UErrorCode &errorCode)
774    {
775        setSymbol(&syms->fLocalPatternChars, 1, 0, value, valueLength, errorCode);
776    }
777};
778
779U_NAMESPACE_END
780
781U_CAPI void U_EXPORT2
782udat_setSymbols(    UDateFormat             *format,
783            UDateFormatSymbolType   type,
784            int32_t                 index,
785            UChar                   *value,
786            int32_t                 valueLength,
787            UErrorCode              *status)
788{
789    verifyIsSimpleDateFormat(format, status);
790    if(U_FAILURE(*status)) return;
791
792    DateFormatSymbols *syms = (DateFormatSymbols *)((SimpleDateFormat *)format)->getDateFormatSymbols();
793
794    switch(type) {
795    case UDAT_ERAS:
796        DateFormatSymbolsSingleSetter::setEra(syms, index, value, valueLength, *status);
797        break;
798
799    case UDAT_ERA_NAMES:
800        DateFormatSymbolsSingleSetter::setEraName(syms, index, value, valueLength, *status);
801        break;
802
803    case UDAT_MONTHS:
804        DateFormatSymbolsSingleSetter::setMonth(syms, index, value, valueLength, *status);
805        break;
806
807    case UDAT_SHORT_MONTHS:
808        DateFormatSymbolsSingleSetter::setShortMonth(syms, index, value, valueLength, *status);
809        break;
810
811    case UDAT_NARROW_MONTHS:
812        DateFormatSymbolsSingleSetter::setNarrowMonth(syms, index, value, valueLength, *status);
813        break;
814
815    case UDAT_STANDALONE_MONTHS:
816        DateFormatSymbolsSingleSetter::setStandaloneMonth(syms, index, value, valueLength, *status);
817        break;
818
819    case UDAT_STANDALONE_SHORT_MONTHS:
820        DateFormatSymbolsSingleSetter::setStandaloneShortMonth(syms, index, value, valueLength, *status);
821        break;
822
823    case UDAT_STANDALONE_NARROW_MONTHS:
824        DateFormatSymbolsSingleSetter::setStandaloneNarrowMonth(syms, index, value, valueLength, *status);
825        break;
826
827    case UDAT_WEEKDAYS:
828        DateFormatSymbolsSingleSetter::setWeekday(syms, index, value, valueLength, *status);
829        break;
830
831    case UDAT_SHORT_WEEKDAYS:
832        DateFormatSymbolsSingleSetter::setShortWeekday(syms, index, value, valueLength, *status);
833        break;
834
835    case UDAT_NARROW_WEEKDAYS:
836        DateFormatSymbolsSingleSetter::setNarrowWeekday(syms, index, value, valueLength, *status);
837        break;
838
839    case UDAT_STANDALONE_WEEKDAYS:
840        DateFormatSymbolsSingleSetter::setStandaloneWeekday(syms, index, value, valueLength, *status);
841        break;
842
843    case UDAT_STANDALONE_SHORT_WEEKDAYS:
844        DateFormatSymbolsSingleSetter::setStandaloneShortWeekday(syms, index, value, valueLength, *status);
845        break;
846
847    case UDAT_STANDALONE_NARROW_WEEKDAYS:
848        DateFormatSymbolsSingleSetter::setStandaloneNarrowWeekday(syms, index, value, valueLength, *status);
849        break;
850
851    case UDAT_QUARTERS:
852        DateFormatSymbolsSingleSetter::setQuarter(syms, index, value, valueLength, *status);
853        break;
854
855    case UDAT_SHORT_QUARTERS:
856        DateFormatSymbolsSingleSetter::setShortQuarter(syms, index, value, valueLength, *status);
857        break;
858
859    case UDAT_STANDALONE_QUARTERS:
860        DateFormatSymbolsSingleSetter::setStandaloneQuarter(syms, index, value, valueLength, *status);
861        break;
862
863    case UDAT_STANDALONE_SHORT_QUARTERS:
864        DateFormatSymbolsSingleSetter::setStandaloneShortQuarter(syms, index, value, valueLength, *status);
865        break;
866
867    case UDAT_AM_PMS:
868        DateFormatSymbolsSingleSetter::setAmPm(syms, index, value, valueLength, *status);
869        break;
870
871    case UDAT_LOCALIZED_CHARS:
872        DateFormatSymbolsSingleSetter::setLocalPatternChars(syms, value, valueLength, *status);
873        break;
874
875    default:
876        *status = U_UNSUPPORTED_ERROR;
877        break;
878
879    }
880}
881
882U_CAPI const char* U_EXPORT2
883udat_getLocaleByType(const UDateFormat *fmt,
884                     ULocDataLocaleType type,
885                     UErrorCode* status)
886{
887    if (fmt == NULL) {
888        if (U_SUCCESS(*status)) {
889            *status = U_ILLEGAL_ARGUMENT_ERROR;
890        }
891        return NULL;
892    }
893    return ((Format*)fmt)->getLocaleID(type, *status);
894}
895
896/**
897 * Verify that fmt is a RelativeDateFormat. Invalid error if not.
898 * @param fmt the UDateFormat, definitely a DateFormat, maybe something else
899 * @param status error code, will be set to failure if there is a familure or the fmt is NULL.
900 */
901static void verifyIsRelativeDateFormat(const UDateFormat* fmt, UErrorCode *status) {
902   if(U_SUCCESS(*status) &&
903       dynamic_cast<const RelativeDateFormat*>(reinterpret_cast<const DateFormat*>(fmt))==NULL) {
904       *status = U_ILLEGAL_ARGUMENT_ERROR;
905   }
906}
907
908
909U_CAPI int32_t U_EXPORT2
910udat_toPatternRelativeDate(const UDateFormat *fmt,
911                           UChar             *result,
912                           int32_t           resultLength,
913                           UErrorCode        *status)
914{
915    verifyIsRelativeDateFormat(fmt, status);
916    if(U_FAILURE(*status)) return -1;
917
918    UnicodeString datePattern;
919    if(!(result==NULL && resultLength==0)) {
920        // NULL destination for pure preflighting: empty dummy string
921        // otherwise, alias the destination buffer
922        datePattern.setTo(result, 0, resultLength);
923    }
924    ((RelativeDateFormat*)fmt)->toPatternDate(datePattern, *status);
925    return datePattern.extract(result, resultLength, *status);
926}
927
928U_CAPI int32_t U_EXPORT2
929udat_toPatternRelativeTime(const UDateFormat *fmt,
930                           UChar             *result,
931                           int32_t           resultLength,
932                           UErrorCode        *status)
933{
934    verifyIsRelativeDateFormat(fmt, status);
935    if(U_FAILURE(*status)) return -1;
936
937    UnicodeString timePattern;
938    if(!(result==NULL && resultLength==0)) {
939        // NULL destination for pure preflighting: empty dummy string
940        // otherwise, alias the destination buffer
941        timePattern.setTo(result, 0, resultLength);
942    }
943    ((RelativeDateFormat*)fmt)->toPatternTime(timePattern, *status);
944    return timePattern.extract(result, resultLength, *status);
945}
946
947U_CAPI void U_EXPORT2
948udat_applyPatternRelative(UDateFormat *format,
949                          const UChar *datePattern,
950                          int32_t     datePatternLength,
951                          const UChar *timePattern,
952                          int32_t     timePatternLength,
953                          UErrorCode  *status)
954{
955    verifyIsRelativeDateFormat(format, status);
956    if(U_FAILURE(*status)) return;
957    const UnicodeString datePat((UBool)(datePatternLength == -1), datePattern, datePatternLength);
958    const UnicodeString timePat((UBool)(timePatternLength == -1), timePattern, timePatternLength);
959    ((RelativeDateFormat*)format)->applyPatterns(datePat, timePat, *status);
960}
961
962#endif /* #if !UCONFIG_NO_FORMATTING */
963