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 747