1/*
2 *******************************************************************************
3 * Copyright (C) 1997-2015, International Business Machines Corporation and    *
4 * others. All Rights Reserved.                                                *
5 *******************************************************************************
6 *
7 * File DATEFMT.CPP
8 *
9 * Modification History:
10 *
11 *   Date        Name        Description
12 *   02/19/97    aliu        Converted from java.
13 *   03/31/97    aliu        Modified extensively to work with 50 locales.
14 *   04/01/97    aliu        Added support for centuries.
15 *   08/12/97    aliu        Fixed operator== to use Calendar::equivalentTo.
16 *   07/20/98    stephen     Changed ParsePosition initialization
17 ********************************************************************************
18 */
19
20#include "unicode/utypes.h"
21
22#if !UCONFIG_NO_FORMATTING
23
24#include "unicode/ures.h"
25#include "unicode/datefmt.h"
26#include "unicode/smpdtfmt.h"
27#include "unicode/dtptngen.h"
28#include "unicode/udisplaycontext.h"
29#include "reldtfmt.h"
30#include "sharedobject.h"
31#include "unifiedcache.h"
32#include "uarrsort.h"
33
34#include "cstring.h"
35#include "windtfmt.h"
36
37#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
38#include <stdio.h>
39#endif
40
41// *****************************************************************************
42// class DateFormat
43// *****************************************************************************
44
45U_NAMESPACE_BEGIN
46
47class U_I18N_API DateFmtBestPattern : public SharedObject {
48public:
49    UnicodeString fPattern;
50
51    DateFmtBestPattern(const UnicodeString &pattern)
52            : fPattern(pattern) { }
53    ~DateFmtBestPattern();
54};
55
56DateFmtBestPattern::~DateFmtBestPattern() {
57}
58
59template<> U_I18N_API
60const DateFmtBestPattern *LocaleCacheKey<DateFmtBestPattern>::createObject(
61        const void * /*creationContext*/, UErrorCode &status) const {
62    status = U_UNSUPPORTED_ERROR;
63    return NULL;
64}
65
66class U_I18N_API DateFmtBestPatternKey : public LocaleCacheKey<DateFmtBestPattern> {
67private:
68    UnicodeString fSkeleton;
69public:
70    DateFmtBestPatternKey(
71        const Locale &loc,
72        const UnicodeString &skeleton,
73        UErrorCode &status)
74            : LocaleCacheKey<DateFmtBestPattern>(loc),
75              fSkeleton(DateTimePatternGenerator::staticGetSkeleton(skeleton, status)) { }
76    DateFmtBestPatternKey(const DateFmtBestPatternKey &other) :
77            LocaleCacheKey<DateFmtBestPattern>(other),
78            fSkeleton(other.fSkeleton) { }
79    virtual ~DateFmtBestPatternKey();
80    virtual int32_t hashCode() const {
81        return 37 * LocaleCacheKey<DateFmtBestPattern>::hashCode() + fSkeleton.hashCode();
82    }
83    virtual UBool operator==(const CacheKeyBase &other) const {
84       // reflexive
85       if (this == &other) {
86           return TRUE;
87       }
88       if (!LocaleCacheKey<DateFmtBestPattern>::operator==(other)) {
89           return FALSE;
90       }
91       // We know that this and other are of same class if we get this far.
92       const DateFmtBestPatternKey &realOther =
93               static_cast<const DateFmtBestPatternKey &>(other);
94       return (realOther.fSkeleton == fSkeleton);
95    }
96    virtual CacheKeyBase *clone() const {
97        return new DateFmtBestPatternKey(*this);
98    }
99    virtual const DateFmtBestPattern *createObject(
100            const void * /*unused*/, UErrorCode &status) const {
101        LocalPointer<DateTimePatternGenerator> dtpg(
102                    DateTimePatternGenerator::createInstance(fLoc, status));
103        if (U_FAILURE(status)) {
104            return NULL;
105        }
106
107        LocalPointer<DateFmtBestPattern> pattern(
108                new DateFmtBestPattern(
109                        dtpg->getBestPattern(fSkeleton, status)),
110                status);
111        if (U_FAILURE(status)) {
112            return NULL;
113        }
114        DateFmtBestPattern *result = pattern.orphan();
115        result->addRef();
116        return result;
117    }
118};
119
120DateFmtBestPatternKey::~DateFmtBestPatternKey() { }
121
122
123DateFormat::DateFormat()
124:   fCalendar(0),
125    fNumberFormat(0),
126    fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
127{
128}
129
130//----------------------------------------------------------------------
131
132DateFormat::DateFormat(const DateFormat& other)
133:   Format(other),
134    fCalendar(0),
135    fNumberFormat(0),
136    fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
137{
138    *this = other;
139}
140
141//----------------------------------------------------------------------
142
143DateFormat& DateFormat::operator=(const DateFormat& other)
144{
145    if (this != &other)
146    {
147        delete fCalendar;
148        delete fNumberFormat;
149        if(other.fCalendar) {
150          fCalendar = other.fCalendar->clone();
151        } else {
152          fCalendar = NULL;
153        }
154        if(other.fNumberFormat) {
155          fNumberFormat = (NumberFormat*)other.fNumberFormat->clone();
156        } else {
157          fNumberFormat = NULL;
158        }
159        fBoolFlags = other.fBoolFlags;
160        fCapitalizationContext = other.fCapitalizationContext;
161    }
162    return *this;
163}
164
165//----------------------------------------------------------------------
166
167DateFormat::~DateFormat()
168{
169    delete fCalendar;
170    delete fNumberFormat;
171}
172
173//----------------------------------------------------------------------
174
175UBool
176DateFormat::operator==(const Format& other) const
177{
178    // This protected comparison operator should only be called by subclasses
179    // which have confirmed that the other object being compared against is
180    // an instance of a sublcass of DateFormat.  THIS IS IMPORTANT.
181
182    // Format::operator== guarantees that this cast is safe
183    DateFormat* fmt = (DateFormat*)&other;
184
185    return (this == fmt) ||
186        (Format::operator==(other) &&
187         fCalendar&&(fCalendar->isEquivalentTo(*fmt->fCalendar)) &&
188         (fNumberFormat && *fNumberFormat == *fmt->fNumberFormat) &&
189         (fCapitalizationContext == fmt->fCapitalizationContext) );
190}
191
192//----------------------------------------------------------------------
193
194UnicodeString&
195DateFormat::format(const Formattable& obj,
196                   UnicodeString& appendTo,
197                   FieldPosition& fieldPosition,
198                   UErrorCode& status) const
199{
200    if (U_FAILURE(status)) return appendTo;
201
202    // if the type of the Formattable is double or long, treat it as if it were a Date
203    UDate date = 0;
204    switch (obj.getType())
205    {
206    case Formattable::kDate:
207        date = obj.getDate();
208        break;
209    case Formattable::kDouble:
210        date = (UDate)obj.getDouble();
211        break;
212    case Formattable::kLong:
213        date = (UDate)obj.getLong();
214        break;
215    default:
216        status = U_ILLEGAL_ARGUMENT_ERROR;
217        return appendTo;
218    }
219
220    // Is this right?
221    //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex())
222    //  status = U_ILLEGAL_ARGUMENT_ERROR;
223
224    return format(date, appendTo, fieldPosition);
225}
226
227//----------------------------------------------------------------------
228
229UnicodeString&
230DateFormat::format(const Formattable& obj,
231                   UnicodeString& appendTo,
232                   FieldPositionIterator* posIter,
233                   UErrorCode& status) const
234{
235    if (U_FAILURE(status)) return appendTo;
236
237    // if the type of the Formattable is double or long, treat it as if it were a Date
238    UDate date = 0;
239    switch (obj.getType())
240    {
241    case Formattable::kDate:
242        date = obj.getDate();
243        break;
244    case Formattable::kDouble:
245        date = (UDate)obj.getDouble();
246        break;
247    case Formattable::kLong:
248        date = (UDate)obj.getLong();
249        break;
250    default:
251        status = U_ILLEGAL_ARGUMENT_ERROR;
252        return appendTo;
253    }
254
255    // Is this right?
256    //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex())
257    //  status = U_ILLEGAL_ARGUMENT_ERROR;
258
259    return format(date, appendTo, posIter, status);
260}
261
262//----------------------------------------------------------------------
263
264// Default implementation for backwards compatibility, subclasses should implement.
265UnicodeString&
266DateFormat::format(Calendar& /* unused cal */,
267                   UnicodeString& appendTo,
268                   FieldPositionIterator* /* unused posIter */,
269                   UErrorCode& status) const {
270    if (U_SUCCESS(status)) {
271        status = U_UNSUPPORTED_ERROR;
272    }
273    return appendTo;
274}
275
276//----------------------------------------------------------------------
277
278UnicodeString&
279DateFormat::format(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const {
280    if (fCalendar != NULL) {
281        // Use a clone of our calendar instance
282        Calendar* calClone = fCalendar->clone();
283        if (calClone != NULL) {
284            UErrorCode ec = U_ZERO_ERROR;
285            calClone->setTime(date, ec);
286            if (U_SUCCESS(ec)) {
287                format(*calClone, appendTo, fieldPosition);
288            }
289            delete calClone;
290        }
291    }
292    return appendTo;
293}
294
295//----------------------------------------------------------------------
296
297UnicodeString&
298DateFormat::format(UDate date, UnicodeString& appendTo, FieldPositionIterator* posIter,
299                   UErrorCode& status) const {
300    if (fCalendar != NULL) {
301        Calendar* calClone = fCalendar->clone();
302        if (calClone != NULL) {
303            calClone->setTime(date, status);
304            if (U_SUCCESS(status)) {
305               format(*calClone, appendTo, posIter, status);
306            }
307            delete calClone;
308        }
309    }
310    return appendTo;
311}
312
313//----------------------------------------------------------------------
314
315UnicodeString&
316DateFormat::format(UDate date, UnicodeString& appendTo) const
317{
318    // Note that any error information is just lost.  That's okay
319    // for this convenience method.
320    FieldPosition fpos(0);
321    return format(date, appendTo, fpos);
322}
323
324//----------------------------------------------------------------------
325
326UDate
327DateFormat::parse(const UnicodeString& text,
328                  ParsePosition& pos) const
329{
330    UDate d = 0; // Error return UDate is 0 (the epoch)
331    if (fCalendar != NULL) {
332        Calendar* calClone = fCalendar->clone();
333        if (calClone != NULL) {
334            int32_t start = pos.getIndex();
335            calClone->clear();
336            parse(text, *calClone, pos);
337            if (pos.getIndex() != start) {
338                UErrorCode ec = U_ZERO_ERROR;
339                d = calClone->getTime(ec);
340                if (U_FAILURE(ec)) {
341                    // We arrive here if fCalendar => calClone is non-lenient and
342                    // there is an out-of-range field.  We don't know which field
343                    // was illegal so we set the error index to the start.
344                    pos.setIndex(start);
345                    pos.setErrorIndex(start);
346                    d = 0;
347                }
348            }
349            delete calClone;
350        }
351    }
352    return d;
353}
354
355//----------------------------------------------------------------------
356
357UDate
358DateFormat::parse(const UnicodeString& text,
359                  UErrorCode& status) const
360{
361    if (U_FAILURE(status)) return 0;
362
363    ParsePosition pos(0);
364    UDate result = parse(text, pos);
365    if (pos.getIndex() == 0) {
366#if defined (U_DEBUG_CAL)
367      fprintf(stderr, "%s:%d - - failed to parse  - err index %d\n"
368              , __FILE__, __LINE__, pos.getErrorIndex() );
369#endif
370      status = U_ILLEGAL_ARGUMENT_ERROR;
371    }
372    return result;
373}
374
375//----------------------------------------------------------------------
376
377void
378DateFormat::parseObject(const UnicodeString& source,
379                        Formattable& result,
380                        ParsePosition& pos) const
381{
382    result.setDate(parse(source, pos));
383}
384
385//----------------------------------------------------------------------
386
387DateFormat* U_EXPORT2
388DateFormat::createTimeInstance(DateFormat::EStyle style,
389                               const Locale& aLocale)
390{
391    return createDateTimeInstance(kNone, style, aLocale);
392}
393
394//----------------------------------------------------------------------
395
396DateFormat* U_EXPORT2
397DateFormat::createDateInstance(DateFormat::EStyle style,
398                               const Locale& aLocale)
399{
400    return createDateTimeInstance(style, kNone, aLocale);
401}
402
403//----------------------------------------------------------------------
404
405DateFormat* U_EXPORT2
406DateFormat::createDateTimeInstance(EStyle dateStyle,
407                                   EStyle timeStyle,
408                                   const Locale& aLocale)
409{
410   if(dateStyle != kNone)
411   {
412       dateStyle = (EStyle) (dateStyle + kDateOffset);
413   }
414   return create(timeStyle, dateStyle, aLocale);
415}
416
417//----------------------------------------------------------------------
418
419DateFormat* U_EXPORT2
420DateFormat::createInstance()
421{
422    return createDateTimeInstance(kShort, kShort, Locale::getDefault());
423}
424
425//----------------------------------------------------------------------
426
427UnicodeString U_EXPORT2
428DateFormat::getBestPattern(
429        const Locale &locale,
430        const UnicodeString &skeleton,
431        UErrorCode &status) {
432    UnifiedCache *cache = UnifiedCache::getInstance(status);
433    if (U_FAILURE(status)) {
434        return UnicodeString();
435    }
436    DateFmtBestPatternKey key(locale, skeleton, status);
437    const DateFmtBestPattern *patternPtr = NULL;
438    cache->get(key, patternPtr, status);
439    if (U_FAILURE(status)) {
440        return UnicodeString();
441    }
442    UnicodeString result(patternPtr->fPattern);
443    patternPtr->removeRef();
444    return result;
445}
446
447DateFormat* U_EXPORT2
448DateFormat::createInstanceForSkeleton(
449        Calendar *calendarToAdopt,
450        const UnicodeString& skeleton,
451        const Locale &locale,
452        UErrorCode &status) {
453    LocalPointer<Calendar> calendar(calendarToAdopt);
454    if (U_FAILURE(status)) {
455        return NULL;
456    }
457    if (calendar.isNull()) {
458        status = U_ILLEGAL_ARGUMENT_ERROR;
459        return NULL;
460    }
461    DateFormat *result = createInstanceForSkeleton(skeleton, locale, status);
462    if (U_FAILURE(status)) {
463        return NULL;
464    }
465    result->adoptCalendar(calendar.orphan());
466    return result;
467}
468
469DateFormat* U_EXPORT2
470DateFormat::createInstanceForSkeleton(
471        const UnicodeString& skeleton,
472        const Locale &locale,
473        UErrorCode &status) {
474    if (U_FAILURE(status)) {
475        return NULL;
476    }
477    LocalPointer<DateFormat> df(
478        new SimpleDateFormat(
479            getBestPattern(locale, skeleton, status),
480            locale, status),
481        status);
482    return U_SUCCESS(status) ? df.orphan() : NULL;
483}
484
485DateFormat* U_EXPORT2
486DateFormat::createInstanceForSkeleton(
487        const UnicodeString& skeleton,
488        UErrorCode &status) {
489    return createInstanceForSkeleton(
490            skeleton, Locale::getDefault(), status);
491}
492
493//----------------------------------------------------------------------
494
495DateFormat* U_EXPORT2
496DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
497{
498    UErrorCode status = U_ZERO_ERROR;
499#if U_PLATFORM_HAS_WIN32_API
500    char buffer[8];
501    int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status);
502
503    // if the locale has "@compat=host", create a host-specific DateFormat...
504    if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
505        Win32DateFormat *f = new Win32DateFormat(timeStyle, dateStyle, locale, status);
506
507        if (U_SUCCESS(status)) {
508            return f;
509        }
510
511        delete f;
512    }
513#endif
514
515    // is it relative?
516    if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=kNone)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) {
517        RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status);
518        if(U_SUCCESS(status)) return r;
519        delete r;
520        status = U_ZERO_ERROR;
521    }
522
523    // Try to create a SimpleDateFormat of the desired style.
524    SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status);
525    if (U_SUCCESS(status)) return f;
526    delete f;
527
528    // If that fails, try to create a format using the default pattern and
529    // the DateFormatSymbols for this locale.
530    status = U_ZERO_ERROR;
531    f = new SimpleDateFormat(locale, status);
532    if (U_SUCCESS(status)) return f;
533    delete f;
534
535    // This should never really happen, because the preceding constructor
536    // should always succeed.  If the resource data is unavailable, a last
537    // resort object should be returned.
538    return 0;
539}
540
541//----------------------------------------------------------------------
542
543const Locale* U_EXPORT2
544DateFormat::getAvailableLocales(int32_t& count)
545{
546    // Get the list of installed locales.
547    // Even if root has the correct date format for this locale,
548    // it's still a valid locale (we don't worry about data fallbacks).
549    return Locale::getAvailableLocales(count);
550}
551
552//----------------------------------------------------------------------
553
554void
555DateFormat::adoptCalendar(Calendar* newCalendar)
556{
557    delete fCalendar;
558    fCalendar = newCalendar;
559}
560
561//----------------------------------------------------------------------
562void
563DateFormat::setCalendar(const Calendar& newCalendar)
564{
565    Calendar* newCalClone = newCalendar.clone();
566    if (newCalClone != NULL) {
567        adoptCalendar(newCalClone);
568    }
569}
570
571//----------------------------------------------------------------------
572
573const Calendar*
574DateFormat::getCalendar() const
575{
576    return fCalendar;
577}
578
579//----------------------------------------------------------------------
580
581void
582DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
583{
584    delete fNumberFormat;
585    fNumberFormat = newNumberFormat;
586    newNumberFormat->setParseIntegerOnly(TRUE);
587}
588//----------------------------------------------------------------------
589
590void
591DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
592{
593    NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone();
594    if (newNumFmtClone != NULL) {
595        adoptNumberFormat(newNumFmtClone);
596    }
597}
598
599//----------------------------------------------------------------------
600
601const NumberFormat*
602DateFormat::getNumberFormat() const
603{
604    return fNumberFormat;
605}
606
607//----------------------------------------------------------------------
608
609void
610DateFormat::adoptTimeZone(TimeZone* zone)
611{
612    if (fCalendar != NULL) {
613        fCalendar->adoptTimeZone(zone);
614    }
615}
616//----------------------------------------------------------------------
617
618void
619DateFormat::setTimeZone(const TimeZone& zone)
620{
621    if (fCalendar != NULL) {
622        fCalendar->setTimeZone(zone);
623    }
624}
625
626//----------------------------------------------------------------------
627
628const TimeZone&
629DateFormat::getTimeZone() const
630{
631    if (fCalendar != NULL) {
632        return fCalendar->getTimeZone();
633    }
634    // If calendar doesn't exists, create default timezone.
635    // fCalendar is rarely null
636    return *(TimeZone::createDefault());
637}
638
639//----------------------------------------------------------------------
640
641void
642DateFormat::setLenient(UBool lenient)
643{
644    if (fCalendar != NULL) {
645        fCalendar->setLenient(lenient);
646    }
647    UErrorCode status = U_ZERO_ERROR;
648    setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, lenient, status);
649    setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, lenient, status);
650}
651
652//----------------------------------------------------------------------
653
654UBool
655DateFormat::isLenient() const
656{
657    UBool lenient = TRUE;
658    if (fCalendar != NULL) {
659        lenient = fCalendar->isLenient();
660    }
661    UErrorCode status = U_ZERO_ERROR;
662    return lenient
663        && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)
664        && getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status);
665}
666
667void
668DateFormat::setCalendarLenient(UBool lenient)
669{
670    if (fCalendar != NULL) {
671        fCalendar->setLenient(lenient);
672    }
673}
674
675//----------------------------------------------------------------------
676
677UBool
678DateFormat::isCalendarLenient() const
679{
680    if (fCalendar != NULL) {
681        return fCalendar->isLenient();
682    }
683    // fCalendar is rarely null
684    return FALSE;
685}
686
687
688//----------------------------------------------------------------------
689
690
691void DateFormat::setContext(UDisplayContext value, UErrorCode& status)
692{
693    if (U_FAILURE(status))
694        return;
695    if ( (UDisplayContextType)((uint32_t)value >> 8) == UDISPCTX_TYPE_CAPITALIZATION ) {
696        fCapitalizationContext = value;
697    } else {
698        status = U_ILLEGAL_ARGUMENT_ERROR;
699   }
700}
701
702
703//----------------------------------------------------------------------
704
705
706UDisplayContext DateFormat::getContext(UDisplayContextType type, UErrorCode& status) const
707{
708    if (U_FAILURE(status))
709        return (UDisplayContext)0;
710    if (type != UDISPCTX_TYPE_CAPITALIZATION) {
711        status = U_ILLEGAL_ARGUMENT_ERROR;
712        return (UDisplayContext)0;
713    }
714    return fCapitalizationContext;
715}
716
717
718//----------------------------------------------------------------------
719
720
721DateFormat&
722DateFormat::setBooleanAttribute(UDateFormatBooleanAttribute attr,
723    									UBool newValue,
724    									UErrorCode &status) {
725    if(!fBoolFlags.isValidValue(newValue)) {
726        status = U_ILLEGAL_ARGUMENT_ERROR;
727    } else {
728        fBoolFlags.set(attr, newValue);
729    }
730
731    return *this;
732}
733
734//----------------------------------------------------------------------
735
736UBool
737DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const {
738
739    return fBoolFlags.get(attr);
740}
741
742U_NAMESPACE_END
743
744#endif /* #if !UCONFIG_NO_FORMATTING */
745
746//eof
747