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