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 42U_NAMESPACE_BEGIN 43 44DateFormat::DateFormat() 45: fCalendar(0), 46 fNumberFormat(0), 47 fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 48{ 49} 50 51//---------------------------------------------------------------------- 52 53DateFormat::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 64DateFormat& 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 88DateFormat::~DateFormat() 89{ 90 delete fCalendar; 91 delete fNumberFormat; 92} 93 94//---------------------------------------------------------------------- 95 96UBool 97DateFormat::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 115UnicodeString& 116DateFormat::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 150UnicodeString& 151DateFormat::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. 186UnicodeString& 187DateFormat::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 199UnicodeString& 200DateFormat::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 218UnicodeString& 219DateFormat::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 236UnicodeString& 237DateFormat::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 247UDate 248DateFormat::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 278UDate 279DateFormat::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 298void 299DateFormat::parseObject(const UnicodeString& source, 300 Formattable& result, 301 ParsePosition& pos) const 302{ 303 result.setDate(parse(source, pos)); 304} 305 306//---------------------------------------------------------------------- 307 308DateFormat* U_EXPORT2 309DateFormat::createTimeInstance(DateFormat::EStyle style, 310 const Locale& aLocale) 311{ 312 return createDateTimeInstance(kNone, style, aLocale); 313} 314 315//---------------------------------------------------------------------- 316 317DateFormat* U_EXPORT2 318DateFormat::createDateInstance(DateFormat::EStyle style, 319 const Locale& aLocale) 320{ 321 return createDateTimeInstance(style, kNone, aLocale); 322} 323 324//---------------------------------------------------------------------- 325 326DateFormat* U_EXPORT2 327DateFormat::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 340DateFormat* U_EXPORT2 341DateFormat::createInstance() 342{ 343 return createDateTimeInstance(kShort, kShort, Locale::getDefault()); 344} 345 346//---------------------------------------------------------------------- 347 348DateFormat* U_EXPORT2 349DateFormat::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 370DateFormat* U_EXPORT2 371DateFormat::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 384DateFormat* U_EXPORT2 385DateFormat::createInstanceForSkeleton( 386 const UnicodeString& skeleton, 387 UErrorCode &status) { 388 return createInstanceForSkeleton( 389 skeleton, Locale::getDefault(), status); 390} 391 392DateFormat* U_EXPORT2 393DateFormat::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 418DateFormat* U_EXPORT2 419DateFormat::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 466const Locale* U_EXPORT2 467DateFormat::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 477void 478DateFormat::adoptCalendar(Calendar* newCalendar) 479{ 480 delete fCalendar; 481 fCalendar = newCalendar; 482} 483 484//---------------------------------------------------------------------- 485void 486DateFormat::setCalendar(const Calendar& newCalendar) 487{ 488 Calendar* newCalClone = newCalendar.clone(); 489 if (newCalClone != NULL) { 490 adoptCalendar(newCalClone); 491 } 492} 493 494//---------------------------------------------------------------------- 495 496const Calendar* 497DateFormat::getCalendar() const 498{ 499 return fCalendar; 500} 501 502//---------------------------------------------------------------------- 503 504void 505DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat) 506{ 507 delete fNumberFormat; 508 fNumberFormat = newNumberFormat; 509 newNumberFormat->setParseIntegerOnly(TRUE); 510} 511//---------------------------------------------------------------------- 512 513void 514DateFormat::setNumberFormat(const NumberFormat& newNumberFormat) 515{ 516 NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone(); 517 if (newNumFmtClone != NULL) { 518 adoptNumberFormat(newNumFmtClone); 519 } 520} 521 522//---------------------------------------------------------------------- 523 524const NumberFormat* 525DateFormat::getNumberFormat() const 526{ 527 return fNumberFormat; 528} 529 530//---------------------------------------------------------------------- 531 532void 533DateFormat::adoptTimeZone(TimeZone* zone) 534{ 535 if (fCalendar != NULL) { 536 fCalendar->adoptTimeZone(zone); 537 } 538} 539//---------------------------------------------------------------------- 540 541void 542DateFormat::setTimeZone(const TimeZone& zone) 543{ 544 if (fCalendar != NULL) { 545 fCalendar->setTimeZone(zone); 546 } 547} 548 549//---------------------------------------------------------------------- 550 551const TimeZone& 552DateFormat::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 564void 565DateFormat::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 577UBool 578DateFormat::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 590void 591DateFormat::setCalendarLenient(UBool lenient) 592{ 593 if (fCalendar != NULL) { 594 fCalendar->setLenient(lenient); 595 } 596} 597 598//---------------------------------------------------------------------- 599 600UBool 601DateFormat::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 614void 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 629UDisplayContext 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 644DateFormat& 645DateFormat::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 659UBool 660DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const { 661 662 return fBoolFlags.get(attr); 663} 664 665U_NAMESPACE_END 666 667#endif /* #if !UCONFIG_NO_FORMATTING */ 668 669//eof 670