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