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