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