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