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 create(style, kNone, aLocale); 313 } 314 315 //---------------------------------------------------------------------- 316 317 DateFormat* U_EXPORT2 318 DateFormat::createDateInstance(DateFormat::EStyle style, 319 const Locale& aLocale) 320 { 321 // +4 to set the correct index for getting data out of 322 // LocaleElements. 323 if(style != kNone) 324 { 325 style = (EStyle) (style + kDateOffset); 326 } 327 return create(kNone, (EStyle) (style), aLocale); 328 } 329 330 //---------------------------------------------------------------------- 331 332 DateFormat* U_EXPORT2 333 DateFormat::createDateTimeInstance(EStyle dateStyle, 334 EStyle timeStyle, 335 const Locale& aLocale) 336 { 337 if(dateStyle != kNone) 338 { 339 dateStyle = (EStyle) (dateStyle + kDateOffset); 340 } 341 return create(timeStyle, dateStyle, aLocale); 342 } 343 344 //---------------------------------------------------------------------- 345 346 DateFormat* U_EXPORT2 347 DateFormat::createInstance() 348 { 349 return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault()); 350 } 351 352 //---------------------------------------------------------------------- 353 354 DateFormat* U_EXPORT2 355 DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale) 356 { 357 UErrorCode status = U_ZERO_ERROR; 358 #if U_PLATFORM_HAS_WIN32_API 359 char buffer[8]; 360 int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status); 361 362 // if the locale has "@compat=host", create a host-specific DateFormat... 363 if (count > 0 && uprv_strcmp(buffer, "host") == 0) { 364 Win32DateFormat *f = new Win32DateFormat(timeStyle, dateStyle, locale, status); 365 366 if (U_SUCCESS(status)) { 367 return f; 368 } 369 370 delete f; 371 } 372 #endif 373 374 // is it relative? 375 if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=kNone)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) { 376 RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status); 377 if(U_SUCCESS(status)) return r; 378 delete r; 379 status = U_ZERO_ERROR; 380 } 381 382 // Try to create a SimpleDateFormat of the desired style. 383 SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status); 384 if (U_SUCCESS(status)) return f; 385 delete f; 386 387 // If that fails, try to create a format using the default pattern and 388 // the DateFormatSymbols for this locale. 389 status = U_ZERO_ERROR; 390 f = new SimpleDateFormat(locale, status); 391 if (U_SUCCESS(status)) return f; 392 delete f; 393 394 // This should never really happen, because the preceding constructor 395 // should always succeed. If the resource data is unavailable, a last 396 // resort object should be returned. 397 return 0; 398 } 399 400 //---------------------------------------------------------------------- 401 402 const Locale* U_EXPORT2 403 DateFormat::getAvailableLocales(int32_t& count) 404 { 405 // Get the list of installed locales. 406 // Even if root has the correct date format for this locale, 407 // it's still a valid locale (we don't worry about data fallbacks). 408 return Locale::getAvailableLocales(count); 409 } 410 411 //---------------------------------------------------------------------- 412 413 void 414 DateFormat::adoptCalendar(Calendar* newCalendar) 415 { 416 delete fCalendar; 417 fCalendar = newCalendar; 418 } 419 420 //---------------------------------------------------------------------- 421 void 422 DateFormat::setCalendar(const Calendar& newCalendar) 423 { 424 Calendar* newCalClone = newCalendar.clone(); 425 if (newCalClone != NULL) { 426 adoptCalendar(newCalClone); 427 } 428 } 429 430 //---------------------------------------------------------------------- 431 432 const Calendar* 433 DateFormat::getCalendar() const 434 { 435 return fCalendar; 436 } 437 438 //---------------------------------------------------------------------- 439 440 void 441 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat) 442 { 443 delete fNumberFormat; 444 fNumberFormat = newNumberFormat; 445 newNumberFormat->setParseIntegerOnly(TRUE); 446 } 447 //---------------------------------------------------------------------- 448 449 void 450 DateFormat::setNumberFormat(const NumberFormat& newNumberFormat) 451 { 452 NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone(); 453 if (newNumFmtClone != NULL) { 454 adoptNumberFormat(newNumFmtClone); 455 } 456 } 457 458 //---------------------------------------------------------------------- 459 460 const NumberFormat* 461 DateFormat::getNumberFormat() const 462 { 463 return fNumberFormat; 464 } 465 466 //---------------------------------------------------------------------- 467 468 void 469 DateFormat::adoptTimeZone(TimeZone* zone) 470 { 471 if (fCalendar != NULL) { 472 fCalendar->adoptTimeZone(zone); 473 } 474 } 475 //---------------------------------------------------------------------- 476 477 void 478 DateFormat::setTimeZone(const TimeZone& zone) 479 { 480 if (fCalendar != NULL) { 481 fCalendar->setTimeZone(zone); 482 } 483 } 484 485 //---------------------------------------------------------------------- 486 487 const TimeZone& 488 DateFormat::getTimeZone() const 489 { 490 if (fCalendar != NULL) { 491 return fCalendar->getTimeZone(); 492 } 493 // If calendar doesn't exists, create default timezone. 494 // fCalendar is rarely null 495 return *(TimeZone::createDefault()); 496 } 497 498 //---------------------------------------------------------------------- 499 500 void 501 DateFormat::setLenient(UBool lenient) 502 { 503 if (fCalendar != NULL) { 504 fCalendar->setLenient(lenient); 505 } 506 UErrorCode status = U_ZERO_ERROR; 507 setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, lenient, status); 508 setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, lenient, status); 509 } 510 511 //---------------------------------------------------------------------- 512 513 UBool 514 DateFormat::isLenient() const 515 { 516 UBool lenient = TRUE; 517 if (fCalendar != NULL) { 518 lenient = fCalendar->isLenient(); 519 } 520 UErrorCode status = U_ZERO_ERROR; 521 return lenient 522 && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status) 523 && getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status); 524 } 525 526 void 527 DateFormat::setCalendarLenient(UBool lenient) 528 { 529 if (fCalendar != NULL) { 530 fCalendar->setLenient(lenient); 531 } 532 } 533 534 //---------------------------------------------------------------------- 535 536 UBool 537 DateFormat::isCalendarLenient() const 538 { 539 if (fCalendar != NULL) { 540 return fCalendar->isLenient(); 541 } 542 // fCalendar is rarely null 543 return FALSE; 544 } 545 546 547 //---------------------------------------------------------------------- 548 549 550 void DateFormat::setContext(UDisplayContext value, UErrorCode& status) 551 { 552 if (U_FAILURE(status)) 553 return; 554 if ( (UDisplayContextType)((uint32_t)value >> 8) == UDISPCTX_TYPE_CAPITALIZATION ) { 555 fCapitalizationContext = value; 556 } else { 557 status = U_ILLEGAL_ARGUMENT_ERROR; 558 } 559 } 560 561 562 //---------------------------------------------------------------------- 563 564 565 UDisplayContext DateFormat::getContext(UDisplayContextType type, UErrorCode& status) const 566 { 567 if (U_FAILURE(status)) 568 return (UDisplayContext)0; 569 if (type != UDISPCTX_TYPE_CAPITALIZATION) { 570 status = U_ILLEGAL_ARGUMENT_ERROR; 571 return (UDisplayContext)0; 572 } 573 return fCapitalizationContext; 574 } 575 576 577 //---------------------------------------------------------------------- 578 579 580 DateFormat& 581 DateFormat::setBooleanAttribute(UDateFormatBooleanAttribute attr, 582 UBool newValue, 583 UErrorCode &status) { 584 if(!fBoolFlags.isValidValue(newValue)) { 585 status = U_ILLEGAL_ARGUMENT_ERROR; 586 } else { 587 fBoolFlags.set(attr, newValue); 588 } 589 590 return *this; 591 } 592 593 //---------------------------------------------------------------------- 594 595 UBool 596 DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const { 597 598 return fBoolFlags.get(attr); 599 } 600 601 U_NAMESPACE_END 602 603 #endif /* #if !UCONFIG_NO_FORMATTING */ 604 605 //eof 606