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 41 U_NAMESPACE_BEGIN 42 43 DateFormat::DateFormat() 44 : fCalendar(0), 45 fNumberFormat(0) 46 { 47 } 48 49 //---------------------------------------------------------------------- 50 51 DateFormat::DateFormat(const DateFormat& other) 52 : Format(other), 53 fCalendar(0), 54 fNumberFormat(0) 55 { 56 *this = other; 57 } 58 59 //---------------------------------------------------------------------- 60 61 DateFormat& 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 84 DateFormat::~DateFormat() 85 { 86 delete fCalendar; 87 delete fNumberFormat; 88 } 89 90 //---------------------------------------------------------------------- 91 92 UBool 93 DateFormat::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 110 UnicodeString& 111 DateFormat::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 145 UnicodeString& 146 DateFormat::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. 181 UnicodeString& 182 DateFormat::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 194 UnicodeString& 195 DateFormat::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 213 UnicodeString& 214 DateFormat::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 231 UnicodeString& 232 DateFormat::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 242 UDate 243 DateFormat::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 273 UDate 274 DateFormat::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 293 void 294 DateFormat::parseObject(const UnicodeString& source, 295 Formattable& result, 296 ParsePosition& pos) const 297 { 298 result.setDate(parse(source, pos)); 299 } 300 301 //---------------------------------------------------------------------- 302 303 DateFormat* U_EXPORT2 304 DateFormat::createTimeInstance(DateFormat::EStyle style, 305 const Locale& aLocale) 306 { 307 return create(style, kNone, aLocale); 308 } 309 310 //---------------------------------------------------------------------- 311 312 DateFormat* U_EXPORT2 313 DateFormat::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 327 DateFormat* U_EXPORT2 328 DateFormat::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 341 DateFormat* U_EXPORT2 342 DateFormat::createInstance() 343 { 344 return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault()); 345 } 346 347 //---------------------------------------------------------------------- 348 349 DateFormat* U_EXPORT2 350 DateFormat::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 397 const Locale* U_EXPORT2 398 DateFormat::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 408 void 409 DateFormat::adoptCalendar(Calendar* newCalendar) 410 { 411 delete fCalendar; 412 fCalendar = newCalendar; 413 } 414 415 //---------------------------------------------------------------------- 416 void 417 DateFormat::setCalendar(const Calendar& newCalendar) 418 { 419 Calendar* newCalClone = newCalendar.clone(); 420 if (newCalClone != NULL) { 421 adoptCalendar(newCalClone); 422 } 423 } 424 425 //---------------------------------------------------------------------- 426 427 const Calendar* 428 DateFormat::getCalendar() const 429 { 430 return fCalendar; 431 } 432 433 //---------------------------------------------------------------------- 434 435 void 436 DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat) 437 { 438 delete fNumberFormat; 439 fNumberFormat = newNumberFormat; 440 newNumberFormat->setParseIntegerOnly(TRUE); 441 } 442 //---------------------------------------------------------------------- 443 444 void 445 DateFormat::setNumberFormat(const NumberFormat& newNumberFormat) 446 { 447 NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone(); 448 if (newNumFmtClone != NULL) { 449 adoptNumberFormat(newNumFmtClone); 450 } 451 } 452 453 //---------------------------------------------------------------------- 454 455 const NumberFormat* 456 DateFormat::getNumberFormat() const 457 { 458 return fNumberFormat; 459 } 460 461 //---------------------------------------------------------------------- 462 463 void 464 DateFormat::adoptTimeZone(TimeZone* zone) 465 { 466 if (fCalendar != NULL) { 467 fCalendar->adoptTimeZone(zone); 468 } 469 } 470 //---------------------------------------------------------------------- 471 472 void 473 DateFormat::setTimeZone(const TimeZone& zone) 474 { 475 if (fCalendar != NULL) { 476 fCalendar->setTimeZone(zone); 477 } 478 } 479 480 //---------------------------------------------------------------------- 481 482 const TimeZone& 483 DateFormat::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 495 void 496 DateFormat::setLenient(UBool lenient) 497 { 498 if (fCalendar != NULL) { 499 fCalendar->setLenient(lenient); 500 } 501 } 502 503 //---------------------------------------------------------------------- 504 505 UBool 506 DateFormat::isLenient() const 507 { 508 if (fCalendar != NULL) { 509 return fCalendar->isLenient(); 510 } 511 // fCalendar is rarely null 512 return FALSE; 513 } 514 515 //---------------------------------------------------------------------- 516 517 DateFormat& 518 DateFormat::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 532 UBool 533 DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const { 534 535 return fBoolFlags.get(attr); 536 } 537 538 U_NAMESPACE_END 539 540 #endif /* #if !UCONFIG_NO_FORMATTING */ 541 542 //eof 543