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