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