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