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 
42 U_NAMESPACE_BEGIN
43 
DateFormat()44 DateFormat::DateFormat()
45 :   fCalendar(0),
46     fNumberFormat(0),
47     fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
48 {
49 }
50 
51 //----------------------------------------------------------------------
52 
DateFormat(const DateFormat & other)53 DateFormat::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 
operator =(const DateFormat & other)64 DateFormat& 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 
~DateFormat()88 DateFormat::~DateFormat()
89 {
90     delete fCalendar;
91     delete fNumberFormat;
92 }
93 
94 //----------------------------------------------------------------------
95 
96 UBool
operator ==(const Format & other) const97 DateFormat::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 
115 UnicodeString&
format(const Formattable & obj,UnicodeString & appendTo,FieldPosition & fieldPosition,UErrorCode & status) const116 DateFormat::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 
150 UnicodeString&
format(const Formattable & obj,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const151 DateFormat::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.
186 UnicodeString&
format(Calendar &,UnicodeString & appendTo,FieldPositionIterator *,UErrorCode & status) const187 DateFormat::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 
199 UnicodeString&
format(UDate date,UnicodeString & appendTo,FieldPosition & fieldPosition) const200 DateFormat::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 
218 UnicodeString&
format(UDate date,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const219 DateFormat::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 
236 UnicodeString&
format(UDate date,UnicodeString & appendTo) const237 DateFormat::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 
247 UDate
parse(const UnicodeString & text,ParsePosition & pos) const248 DateFormat::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 
278 UDate
parse(const UnicodeString & text,UErrorCode & status) const279 DateFormat::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 
298 void
parseObject(const UnicodeString & source,Formattable & result,ParsePosition & pos) const299 DateFormat::parseObject(const UnicodeString& source,
300                         Formattable& result,
301                         ParsePosition& pos) const
302 {
303     result.setDate(parse(source, pos));
304 }
305 
306 //----------------------------------------------------------------------
307 
308 DateFormat* U_EXPORT2
createTimeInstance(DateFormat::EStyle style,const Locale & aLocale)309 DateFormat::createTimeInstance(DateFormat::EStyle style,
310                                const Locale& aLocale)
311 {
312     return createDateTimeInstance(kNone, style, aLocale);
313 }
314 
315 //----------------------------------------------------------------------
316 
317 DateFormat* U_EXPORT2
createDateInstance(DateFormat::EStyle style,const Locale & aLocale)318 DateFormat::createDateInstance(DateFormat::EStyle style,
319                                const Locale& aLocale)
320 {
321     return createDateTimeInstance(style, kNone, aLocale);
322 }
323 
324 //----------------------------------------------------------------------
325 
326 DateFormat* U_EXPORT2
createDateTimeInstance(EStyle dateStyle,EStyle timeStyle,const Locale & aLocale)327 DateFormat::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 
340 DateFormat* U_EXPORT2
createInstance()341 DateFormat::createInstance()
342 {
343     return createDateTimeInstance(kShort, kShort, Locale::getDefault());
344 }
345 
346 //----------------------------------------------------------------------
347 
348 DateFormat* U_EXPORT2
createInstanceForSkeleton(Calendar * calendarToAdopt,const UnicodeString & skeleton,const Locale & locale,UErrorCode & status)349 DateFormat::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 
370 DateFormat* U_EXPORT2
createInstanceForSkeleton(const UnicodeString & skeleton,const Locale & locale,UErrorCode & status)371 DateFormat::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 
384 DateFormat* U_EXPORT2
createInstanceForSkeleton(const UnicodeString & skeleton,UErrorCode & status)385 DateFormat::createInstanceForSkeleton(
386         const UnicodeString& skeleton,
387         UErrorCode &status) {
388     return createInstanceForSkeleton(
389             skeleton, Locale::getDefault(), status);
390 }
391 
392 DateFormat* U_EXPORT2
internalCreateInstanceForSkeleton(const UnicodeString & skeleton,const Locale & locale,DateTimePatternGenerator & gen,UErrorCode & status)393 DateFormat::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 
418 DateFormat* U_EXPORT2
create(EStyle timeStyle,EStyle dateStyle,const Locale & locale)419 DateFormat::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 
466 const Locale* U_EXPORT2
getAvailableLocales(int32_t & count)467 DateFormat::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 
477 void
adoptCalendar(Calendar * newCalendar)478 DateFormat::adoptCalendar(Calendar* newCalendar)
479 {
480     delete fCalendar;
481     fCalendar = newCalendar;
482 }
483 
484 //----------------------------------------------------------------------
485 void
setCalendar(const Calendar & newCalendar)486 DateFormat::setCalendar(const Calendar& newCalendar)
487 {
488     Calendar* newCalClone = newCalendar.clone();
489     if (newCalClone != NULL) {
490         adoptCalendar(newCalClone);
491     }
492 }
493 
494 //----------------------------------------------------------------------
495 
496 const Calendar*
getCalendar() const497 DateFormat::getCalendar() const
498 {
499     return fCalendar;
500 }
501 
502 //----------------------------------------------------------------------
503 
504 void
adoptNumberFormat(NumberFormat * newNumberFormat)505 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
506 {
507     delete fNumberFormat;
508     fNumberFormat = newNumberFormat;
509     newNumberFormat->setParseIntegerOnly(TRUE);
510 }
511 //----------------------------------------------------------------------
512 
513 void
setNumberFormat(const NumberFormat & newNumberFormat)514 DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
515 {
516     NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone();
517     if (newNumFmtClone != NULL) {
518         adoptNumberFormat(newNumFmtClone);
519     }
520 }
521 
522 //----------------------------------------------------------------------
523 
524 const NumberFormat*
getNumberFormat() const525 DateFormat::getNumberFormat() const
526 {
527     return fNumberFormat;
528 }
529 
530 //----------------------------------------------------------------------
531 
532 void
adoptTimeZone(TimeZone * zone)533 DateFormat::adoptTimeZone(TimeZone* zone)
534 {
535     if (fCalendar != NULL) {
536         fCalendar->adoptTimeZone(zone);
537     }
538 }
539 //----------------------------------------------------------------------
540 
541 void
setTimeZone(const TimeZone & zone)542 DateFormat::setTimeZone(const TimeZone& zone)
543 {
544     if (fCalendar != NULL) {
545         fCalendar->setTimeZone(zone);
546     }
547 }
548 
549 //----------------------------------------------------------------------
550 
551 const TimeZone&
getTimeZone() const552 DateFormat::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 
564 void
setLenient(UBool lenient)565 DateFormat::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 
577 UBool
isLenient() const578 DateFormat::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 
590 void
setCalendarLenient(UBool lenient)591 DateFormat::setCalendarLenient(UBool lenient)
592 {
593     if (fCalendar != NULL) {
594         fCalendar->setLenient(lenient);
595     }
596 }
597 
598 //----------------------------------------------------------------------
599 
600 UBool
isCalendarLenient() const601 DateFormat::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 
setContext(UDisplayContext value,UErrorCode & status)614 void 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 
getContext(UDisplayContextType type,UErrorCode & status) const629 UDisplayContext 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 
644 DateFormat&
setBooleanAttribute(UDateFormatBooleanAttribute attr,UBool newValue,UErrorCode & status)645 DateFormat::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 
659 UBool
getBooleanAttribute(UDateFormatBooleanAttribute attr,UErrorCode &) const660 DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const {
661 
662     return fBoolFlags.get(attr);
663 }
664 
665 U_NAMESPACE_END
666 
667 #endif /* #if !UCONFIG_NO_FORMATTING */
668 
669 //eof
670