intl/icu/source/i18n/dtitvfmt.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*******************************************************************************
michael@0 2 * Copyright (C) 2008-2013, International Business Machines Corporation and
michael@0 3 * others. All Rights Reserved.
michael@0 4 *******************************************************************************
michael@0 5 *
michael@0 6 * File DTITVFMT.CPP
michael@0 7 *
michael@0 8 *******************************************************************************
michael@0 9 */
michael@0 10
michael@0 11 #include "utypeinfo.h" // for 'typeid' to work
michael@0 12
michael@0 13 #include "unicode/dtitvfmt.h"
michael@0 14
michael@0 15 #if !UCONFIG_NO_FORMATTING
michael@0 16
michael@0 17 //TODO: put in compilation
michael@0 18 //#define DTITVFMT_DEBUG 1
michael@0 19
michael@0 20 #include "cstring.h"
michael@0 21 #include "unicode/msgfmt.h"
michael@0 22 #include "unicode/dtptngen.h"
michael@0 23 #include "unicode/dtitvinf.h"
michael@0 24 #include "unicode/calendar.h"
michael@0 25 #include "dtitv_impl.h"
michael@0 26
michael@0 27 #ifdef DTITVFMT_DEBUG
michael@0 28 #include <iostream>
michael@0 29 #include "cstring.h"
michael@0 30 #endif
michael@0 31
michael@0 32 #include "gregoimp.h"
michael@0 33
michael@0 34 U_NAMESPACE_BEGIN
michael@0 35
michael@0 36
michael@0 37
michael@0 38 #ifdef DTITVFMT_DEBUG
michael@0 39 #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
michael@0 40 #endif
michael@0 41
michael@0 42
michael@0 43 static const UChar gDateFormatSkeleton[][11] = {
michael@0 44 //yMMMMEEEEd
michael@0 45 {LOW_Y, CAP_M, CAP_M, CAP_M, CAP_M, CAP_E, CAP_E, CAP_E, CAP_E, LOW_D, 0},
michael@0 46 //yMMMMd
michael@0 47 {LOW_Y, CAP_M, CAP_M, CAP_M, CAP_M, LOW_D, 0},
michael@0 48 //yMMMd
michael@0 49 {LOW_Y, CAP_M, CAP_M, CAP_M, LOW_D, 0},
michael@0 50 //yMd
michael@0 51 {LOW_Y, CAP_M, LOW_D, 0} };
michael@0 52
michael@0 53
michael@0 54 static const char gDateTimePatternsTag[]="DateTimePatterns";
michael@0 55
michael@0 56
michael@0 57 // latestFirst:
michael@0 58 static const UChar gLaterFirstPrefix[] = {LOW_L, LOW_A, LOW_T, LOW_E, LOW_S,LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
michael@0 59
michael@0 60 // earliestFirst:
michael@0 61 static const UChar gEarlierFirstPrefix[] = {LOW_E, LOW_A, LOW_R, LOW_L, LOW_I, LOW_E, LOW_S, LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
michael@0 62
michael@0 63
michael@0 64 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalFormat)
michael@0 65
michael@0 66
michael@0 67
michael@0 68 DateIntervalFormat* U_EXPORT2
michael@0 69 DateIntervalFormat::createInstance(const UnicodeString& skeleton,
michael@0 70 UErrorCode& status) {
michael@0 71 return createInstance(skeleton, Locale::getDefault(), status);
michael@0 72 }
michael@0 73
michael@0 74
michael@0 75 DateIntervalFormat* U_EXPORT2
michael@0 76 DateIntervalFormat::createInstance(const UnicodeString& skeleton,
michael@0 77 const Locale& locale,
michael@0 78 UErrorCode& status) {
michael@0 79 #ifdef DTITVFMT_DEBUG
michael@0 80 char result[1000];
michael@0 81 char result_1[1000];
michael@0 82 char mesg[2000];
michael@0 83 skeleton.extract(0, skeleton.length(), result, "UTF-8");
michael@0 84 UnicodeString pat;
michael@0 85 ((SimpleDateFormat*)dtfmt)->toPattern(pat);
michael@0 86 pat.extract(0, pat.length(), result_1, "UTF-8");
michael@0 87 sprintf(mesg, "skeleton: %s; pattern: %s\n", result, result_1);
michael@0 88 PRINTMESG(mesg)
michael@0 89 #endif
michael@0 90
michael@0 91 DateIntervalInfo* dtitvinf = new DateIntervalInfo(locale, status);
michael@0 92 return create(locale, dtitvinf, &skeleton, status);
michael@0 93 }
michael@0 94
michael@0 95
michael@0 96
michael@0 97 DateIntervalFormat* U_EXPORT2
michael@0 98 DateIntervalFormat::createInstance(const UnicodeString& skeleton,
michael@0 99 const DateIntervalInfo& dtitvinf,
michael@0 100 UErrorCode& status) {
michael@0 101 return createInstance(skeleton, Locale::getDefault(), dtitvinf, status);
michael@0 102 }
michael@0 103
michael@0 104
michael@0 105 DateIntervalFormat* U_EXPORT2
michael@0 106 DateIntervalFormat::createInstance(const UnicodeString& skeleton,
michael@0 107 const Locale& locale,
michael@0 108 const DateIntervalInfo& dtitvinf,
michael@0 109 UErrorCode& status) {
michael@0 110 DateIntervalInfo* ptn = dtitvinf.clone();
michael@0 111 return create(locale, ptn, &skeleton, status);
michael@0 112 }
michael@0 113
michael@0 114
michael@0 115 DateIntervalFormat::DateIntervalFormat()
michael@0 116 : fInfo(NULL),
michael@0 117 fDateFormat(NULL),
michael@0 118 fFromCalendar(NULL),
michael@0 119 fToCalendar(NULL),
michael@0 120 fDtpng(NULL)
michael@0 121 {}
michael@0 122
michael@0 123
michael@0 124 DateIntervalFormat::DateIntervalFormat(const DateIntervalFormat& itvfmt)
michael@0 125 : Format(itvfmt),
michael@0 126 fInfo(NULL),
michael@0 127 fDateFormat(NULL),
michael@0 128 fFromCalendar(NULL),
michael@0 129 fToCalendar(NULL),
michael@0 130 fDtpng(NULL) {
michael@0 131 *this = itvfmt;
michael@0 132 }
michael@0 133
michael@0 134
michael@0 135 DateIntervalFormat&
michael@0 136 DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) {
michael@0 137 if ( this != &itvfmt ) {
michael@0 138 delete fDateFormat;
michael@0 139 delete fInfo;
michael@0 140 delete fFromCalendar;
michael@0 141 delete fToCalendar;
michael@0 142 delete fDtpng;
michael@0 143 if ( itvfmt.fDateFormat ) {
michael@0 144 fDateFormat = (SimpleDateFormat*)itvfmt.fDateFormat->clone();
michael@0 145 } else {
michael@0 146 fDateFormat = NULL;
michael@0 147 }
michael@0 148 if ( itvfmt.fInfo ) {
michael@0 149 fInfo = itvfmt.fInfo->clone();
michael@0 150 } else {
michael@0 151 fInfo = NULL;
michael@0 152 }
michael@0 153 if ( itvfmt.fFromCalendar ) {
michael@0 154 fFromCalendar = itvfmt.fFromCalendar->clone();
michael@0 155 } else {
michael@0 156 fFromCalendar = NULL;
michael@0 157 }
michael@0 158 if ( itvfmt.fToCalendar ) {
michael@0 159 fToCalendar = itvfmt.fToCalendar->clone();
michael@0 160 } else {
michael@0 161 fToCalendar = NULL;
michael@0 162 }
michael@0 163 fSkeleton = itvfmt.fSkeleton;
michael@0 164 int8_t i;
michael@0 165 for ( i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
michael@0 166 fIntervalPatterns[i] = itvfmt.fIntervalPatterns[i];
michael@0 167 }
michael@0 168 if (itvfmt.fDtpng) {
michael@0 169 fDtpng = itvfmt.fDtpng->clone();
michael@0 170 }
michael@0 171 }
michael@0 172 return *this;
michael@0 173 }
michael@0 174
michael@0 175
michael@0 176 DateIntervalFormat::~DateIntervalFormat() {
michael@0 177 delete fInfo;
michael@0 178 delete fDateFormat;
michael@0 179 delete fFromCalendar;
michael@0 180 delete fToCalendar;
michael@0 181 delete fDtpng;
michael@0 182 }
michael@0 183
michael@0 184
michael@0 185 Format*
michael@0 186 DateIntervalFormat::clone(void) const {
michael@0 187 return new DateIntervalFormat(*this);
michael@0 188 }
michael@0 189
michael@0 190
michael@0 191 UBool
michael@0 192 DateIntervalFormat::operator==(const Format& other) const {
michael@0 193 if (typeid(*this) == typeid(other)) {
michael@0 194 const DateIntervalFormat* fmt = (DateIntervalFormat*)&other;
michael@0 195 #ifdef DTITVFMT_DEBUG
michael@0 196 UBool equal;
michael@0 197 equal = (this == fmt);
michael@0 198
michael@0 199 equal = (*fInfo == *fmt->fInfo);
michael@0 200 equal = (*fDateFormat == *fmt->fDateFormat);
michael@0 201 equal = fFromCalendar->isEquivalentTo(*fmt->fFromCalendar) ;
michael@0 202 equal = fToCalendar->isEquivalentTo(*fmt->fToCalendar) ;
michael@0 203 equal = (fSkeleton == fmt->fSkeleton);
michael@0 204 #endif
michael@0 205 UBool res;
michael@0 206 res = ( this == fmt ) ||
michael@0 207 ( Format::operator==(other) &&
michael@0 208 fInfo &&
michael@0 209 ( *fInfo == *fmt->fInfo ) &&
michael@0 210 fDateFormat &&
michael@0 211 ( *fDateFormat == *fmt->fDateFormat ) &&
michael@0 212 fFromCalendar &&
michael@0 213 fFromCalendar->isEquivalentTo(*fmt->fFromCalendar) &&
michael@0 214 fToCalendar &&
michael@0 215 fToCalendar->isEquivalentTo(*fmt->fToCalendar) &&
michael@0 216 fSkeleton == fmt->fSkeleton &&
michael@0 217 fDtpng &&
michael@0 218 (*fDtpng == *fmt->fDtpng) );
michael@0 219 int8_t i;
michael@0 220 for (i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX && res == TRUE; ++i ) {
michael@0 221 res = ( fIntervalPatterns[i].firstPart ==
michael@0 222 fmt->fIntervalPatterns[i].firstPart) &&
michael@0 223 ( fIntervalPatterns[i].secondPart ==
michael@0 224 fmt->fIntervalPatterns[i].secondPart ) &&
michael@0 225 ( fIntervalPatterns[i].laterDateFirst ==
michael@0 226 fmt->fIntervalPatterns[i].laterDateFirst) ;
michael@0 227 }
michael@0 228 return res;
michael@0 229 }
michael@0 230 return FALSE;
michael@0 231 }
michael@0 232
michael@0 233
michael@0 234
michael@0 235 UnicodeString&
michael@0 236 DateIntervalFormat::format(const Formattable& obj,
michael@0 237 UnicodeString& appendTo,
michael@0 238 FieldPosition& fieldPosition,
michael@0 239 UErrorCode& status) const {
michael@0 240 if ( U_FAILURE(status) ) {
michael@0 241 return appendTo;
michael@0 242 }
michael@0 243
michael@0 244 if ( obj.getType() == Formattable::kObject ) {
michael@0 245 const UObject* formatObj = obj.getObject();
michael@0 246 const DateInterval* interval = dynamic_cast<const DateInterval*>(formatObj);
michael@0 247 if (interval != NULL){
michael@0 248 return format(interval, appendTo, fieldPosition, status);
michael@0 249 }
michael@0 250 }
michael@0 251 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 252 return appendTo;
michael@0 253 }
michael@0 254
michael@0 255
michael@0 256 UnicodeString&
michael@0 257 DateIntervalFormat::format(const DateInterval* dtInterval,
michael@0 258 UnicodeString& appendTo,
michael@0 259 FieldPosition& fieldPosition,
michael@0 260 UErrorCode& status) const {
michael@0 261 if ( U_FAILURE(status) ) {
michael@0 262 return appendTo;
michael@0 263 }
michael@0 264
michael@0 265 if ( fFromCalendar != NULL && fToCalendar != NULL &&
michael@0 266 fDateFormat != NULL && fInfo != NULL ) {
michael@0 267 fFromCalendar->setTime(dtInterval->getFromDate(), status);
michael@0 268 fToCalendar->setTime(dtInterval->getToDate(), status);
michael@0 269 if ( U_SUCCESS(status) ) {
michael@0 270 return format(*fFromCalendar, *fToCalendar, appendTo,fieldPosition, status);
michael@0 271 }
michael@0 272 }
michael@0 273 return appendTo;
michael@0 274 }
michael@0 275
michael@0 276
michael@0 277 UnicodeString&
michael@0 278 DateIntervalFormat::format(Calendar& fromCalendar,
michael@0 279 Calendar& toCalendar,
michael@0 280 UnicodeString& appendTo,
michael@0 281 FieldPosition& pos,
michael@0 282 UErrorCode& status) const {
michael@0 283 if ( U_FAILURE(status) ) {
michael@0 284 return appendTo;
michael@0 285 }
michael@0 286
michael@0 287 // not support different calendar types and time zones
michael@0 288 //if ( fromCalendar.getType() != toCalendar.getType() ) {
michael@0 289 if ( !fromCalendar.isEquivalentTo(toCalendar) ) {
michael@0 290 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 291 return appendTo;
michael@0 292 }
michael@0 293
michael@0 294 // First, find the largest different calendar field.
michael@0 295 UCalendarDateFields field = UCAL_FIELD_COUNT;
michael@0 296
michael@0 297 if ( fromCalendar.get(UCAL_ERA,status) != toCalendar.get(UCAL_ERA,status)) {
michael@0 298 field = UCAL_ERA;
michael@0 299 } else if ( fromCalendar.get(UCAL_YEAR, status) !=
michael@0 300 toCalendar.get(UCAL_YEAR, status) ) {
michael@0 301 field = UCAL_YEAR;
michael@0 302 } else if ( fromCalendar.get(UCAL_MONTH, status) !=
michael@0 303 toCalendar.get(UCAL_MONTH, status) ) {
michael@0 304 field = UCAL_MONTH;
michael@0 305 } else if ( fromCalendar.get(UCAL_DATE, status) !=
michael@0 306 toCalendar.get(UCAL_DATE, status) ) {
michael@0 307 field = UCAL_DATE;
michael@0 308 } else if ( fromCalendar.get(UCAL_AM_PM, status) !=
michael@0 309 toCalendar.get(UCAL_AM_PM, status) ) {
michael@0 310 field = UCAL_AM_PM;
michael@0 311 } else if ( fromCalendar.get(UCAL_HOUR, status) !=
michael@0 312 toCalendar.get(UCAL_HOUR, status) ) {
michael@0 313 field = UCAL_HOUR;
michael@0 314 } else if ( fromCalendar.get(UCAL_MINUTE, status) !=
michael@0 315 toCalendar.get(UCAL_MINUTE, status) ) {
michael@0 316 field = UCAL_MINUTE;
michael@0 317 }
michael@0 318
michael@0 319 if ( U_FAILURE(status) ) {
michael@0 320 return appendTo;
michael@0 321 }
michael@0 322 if ( field == UCAL_FIELD_COUNT ) {
michael@0 323 /* ignore the second/millisecond etc. small fields' difference.
michael@0 324 * use single date when all the above are the same.
michael@0 325 */
michael@0 326 return fDateFormat->format(fromCalendar, appendTo, pos);
michael@0 327 }
michael@0 328
michael@0 329 // following call should not set wrong status,
michael@0 330 // all the pass-in fields are valid till here
michael@0 331 int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
michael@0 332 status);
michael@0 333 const PatternInfo& intervalPattern = fIntervalPatterns[itvPtnIndex];
michael@0 334
michael@0 335 if ( intervalPattern.firstPart.isEmpty() &&
michael@0 336 intervalPattern.secondPart.isEmpty() ) {
michael@0 337 if ( fDateFormat->isFieldUnitIgnored(field) ) {
michael@0 338 /* the largest different calendar field is small than
michael@0 339 * the smallest calendar field in pattern,
michael@0 340 * return single date format.
michael@0 341 */
michael@0 342 return fDateFormat->format(fromCalendar, appendTo, pos);
michael@0 343 }
michael@0 344 return fallbackFormat(fromCalendar, toCalendar, appendTo, pos, status);
michael@0 345 }
michael@0 346 // If the first part in interval pattern is empty,
michael@0 347 // the 2nd part of it saves the full-pattern used in fall-back.
michael@0 348 // For a 'real' interval pattern, the first part will never be empty.
michael@0 349 if ( intervalPattern.firstPart.isEmpty() ) {
michael@0 350 // fall back
michael@0 351 UnicodeString originalPattern;
michael@0 352 fDateFormat->toPattern(originalPattern);
michael@0 353 fDateFormat->applyPattern(intervalPattern.secondPart);
michael@0 354 appendTo = fallbackFormat(fromCalendar, toCalendar, appendTo, pos, status);
michael@0 355 fDateFormat->applyPattern(originalPattern);
michael@0 356 return appendTo;
michael@0 357 }
michael@0 358 Calendar* firstCal;
michael@0 359 Calendar* secondCal;
michael@0 360 if ( intervalPattern.laterDateFirst ) {
michael@0 361 firstCal = &toCalendar;
michael@0 362 secondCal = &fromCalendar;
michael@0 363 } else {
michael@0 364 firstCal = &fromCalendar;
michael@0 365 secondCal = &toCalendar;
michael@0 366 }
michael@0 367 // break the interval pattern into 2 parts,
michael@0 368 // first part should not be empty,
michael@0 369 UnicodeString originalPattern;
michael@0 370 fDateFormat->toPattern(originalPattern);
michael@0 371 fDateFormat->applyPattern(intervalPattern.firstPart);
michael@0 372 fDateFormat->format(*firstCal, appendTo, pos);
michael@0 373 if ( !intervalPattern.secondPart.isEmpty() ) {
michael@0 374 fDateFormat->applyPattern(intervalPattern.secondPart);
michael@0 375 fDateFormat->format(*secondCal, appendTo, pos);
michael@0 376 }
michael@0 377 fDateFormat->applyPattern(originalPattern);
michael@0 378 return appendTo;
michael@0 379 }
michael@0 380
michael@0 381
michael@0 382
michael@0 383 void
michael@0 384 DateIntervalFormat::parseObject(const UnicodeString& /* source */,
michael@0 385 Formattable& /* result */,
michael@0 386 ParsePosition& /* parse_pos */) const {
michael@0 387 // parseObject(const UnicodeString&, Formattable&, UErrorCode&) const
michael@0 388 // will set status as U_INVALID_FORMAT_ERROR if
michael@0 389 // parse_pos is still 0
michael@0 390 }
michael@0 391
michael@0 392
michael@0 393
michael@0 394
michael@0 395 const DateIntervalInfo*
michael@0 396 DateIntervalFormat::getDateIntervalInfo() const {
michael@0 397 return fInfo;
michael@0 398 }
michael@0 399
michael@0 400
michael@0 401 void
michael@0 402 DateIntervalFormat::setDateIntervalInfo(const DateIntervalInfo& newItvPattern,
michael@0 403 UErrorCode& status) {
michael@0 404 delete fInfo;
michael@0 405 fInfo = new DateIntervalInfo(newItvPattern);
michael@0 406 if ( fDateFormat ) {
michael@0 407 initializePattern(status);
michael@0 408 }
michael@0 409 }
michael@0 410
michael@0 411
michael@0 412
michael@0 413 const DateFormat*
michael@0 414 DateIntervalFormat::getDateFormat() const {
michael@0 415 return fDateFormat;
michael@0 416 }
michael@0 417
michael@0 418
michael@0 419 void
michael@0 420 DateIntervalFormat::adoptTimeZone(TimeZone* zone)
michael@0 421 {
michael@0 422 if (fDateFormat != NULL) {
michael@0 423 fDateFormat->adoptTimeZone(zone);
michael@0 424 }
michael@0 425 // The fDateFormat has the master calendar for the DateIntervalFormat and has
michael@0 426 // ownership of any adopted TimeZone; fFromCalendar and fToCalendar are internal
michael@0 427 // work clones of that calendar (and should not also be given ownership of the
michael@0 428 // adopted TimeZone).
michael@0 429 if (fFromCalendar) {
michael@0 430 fFromCalendar->setTimeZone(*zone);
michael@0 431 }
michael@0 432 if (fToCalendar) {
michael@0 433 fToCalendar->setTimeZone(*zone);
michael@0 434 }
michael@0 435 }
michael@0 436
michael@0 437 void
michael@0 438 DateIntervalFormat::setTimeZone(const TimeZone& zone)
michael@0 439 {
michael@0 440 if (fDateFormat != NULL) {
michael@0 441 fDateFormat->setTimeZone(zone);
michael@0 442 }
michael@0 443 // The fDateFormat has the master calendar for the DateIntervalFormat;
michael@0 444 // fFromCalendar and fToCalendar are internal work clones of that calendar.
michael@0 445 if (fFromCalendar) {
michael@0 446 fFromCalendar->setTimeZone(zone);
michael@0 447 }
michael@0 448 if (fToCalendar) {
michael@0 449 fToCalendar->setTimeZone(zone);
michael@0 450 }
michael@0 451 }
michael@0 452
michael@0 453 const TimeZone&
michael@0 454 DateIntervalFormat::getTimeZone() const
michael@0 455 {
michael@0 456 if (fDateFormat != NULL) {
michael@0 457 return fDateFormat->getTimeZone();
michael@0 458 }
michael@0 459 // If fDateFormat is NULL (unexpected), create default timezone.
michael@0 460 return *(TimeZone::createDefault());
michael@0 461 }
michael@0 462
michael@0 463 DateIntervalFormat::DateIntervalFormat(const Locale& locale,
michael@0 464 DateIntervalInfo* dtItvInfo,
michael@0 465 const UnicodeString* skeleton,
michael@0 466 UErrorCode& status)
michael@0 467 : fInfo(NULL),
michael@0 468 fDateFormat(NULL),
michael@0 469 fFromCalendar(NULL),
michael@0 470 fToCalendar(NULL),
michael@0 471 fDtpng(NULL)
michael@0 472 {
michael@0 473 if ( U_FAILURE(status) ) {
michael@0 474 delete dtItvInfo;
michael@0 475 return;
michael@0 476 }
michael@0 477 fDtpng = DateTimePatternGenerator::createInstance(locale, status);
michael@0 478 SimpleDateFormat* dtfmt = createSDFPatternInstance(*skeleton, locale,
michael@0 479 fDtpng, status);
michael@0 480 if ( U_FAILURE(status) ) {
michael@0 481 delete dtItvInfo;
michael@0 482 delete fDtpng;
michael@0 483 delete dtfmt;
michael@0 484 return;
michael@0 485 }
michael@0 486 if ( dtfmt == NULL || dtItvInfo == NULL || fDtpng == NULL ) {
michael@0 487 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 488 // safe to delete NULL
michael@0 489 delete dtfmt;
michael@0 490 delete dtItvInfo;
michael@0 491 delete fDtpng;
michael@0 492 return;
michael@0 493 }
michael@0 494 if ( skeleton ) {
michael@0 495 fSkeleton = *skeleton;
michael@0 496 }
michael@0 497 fInfo = dtItvInfo;
michael@0 498 fDateFormat = dtfmt;
michael@0 499 if ( dtfmt->getCalendar() ) {
michael@0 500 fFromCalendar = dtfmt->getCalendar()->clone();
michael@0 501 fToCalendar = dtfmt->getCalendar()->clone();
michael@0 502 } else {
michael@0 503 fFromCalendar = NULL;
michael@0 504 fToCalendar = NULL;
michael@0 505 }
michael@0 506 initializePattern(status);
michael@0 507 }
michael@0 508
michael@0 509
michael@0 510 SimpleDateFormat* U_EXPORT2
michael@0 511 DateIntervalFormat::createSDFPatternInstance(const UnicodeString& skeleton,
michael@0 512 const Locale& locale,
michael@0 513 DateTimePatternGenerator* dtpng,
michael@0 514 UErrorCode& status)
michael@0 515 {
michael@0 516 if ( U_FAILURE(status) ) {
michael@0 517 return NULL;
michael@0 518 }
michael@0 519
michael@0 520 const UnicodeString pattern = dtpng->getBestPattern(skeleton, status);
michael@0 521 if ( U_FAILURE(status) ) {
michael@0 522 return NULL;
michael@0 523 }
michael@0 524 SimpleDateFormat* dtfmt = new SimpleDateFormat(pattern, locale, status);
michael@0 525 if ( U_FAILURE(status) ) {
michael@0 526 delete dtfmt;
michael@0 527 return NULL;
michael@0 528 }
michael@0 529 return dtfmt;
michael@0 530 }
michael@0 531
michael@0 532
michael@0 533 DateIntervalFormat* U_EXPORT2
michael@0 534 DateIntervalFormat::create(const Locale& locale,
michael@0 535 DateIntervalInfo* dtitvinf,
michael@0 536 const UnicodeString* skeleton,
michael@0 537 UErrorCode& status) {
michael@0 538 DateIntervalFormat* f = new DateIntervalFormat(locale, dtitvinf,
michael@0 539 skeleton, status);
michael@0 540 if ( f == NULL ) {
michael@0 541 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 542 delete dtitvinf;
michael@0 543 } else if ( U_FAILURE(status) ) {
michael@0 544 // safe to delete f, although nothing acutally is saved
michael@0 545 delete f;
michael@0 546 f = 0;
michael@0 547 }
michael@0 548 return f;
michael@0 549 }
michael@0 550
michael@0 551
michael@0 552
michael@0 553 /**
michael@0 554 * Initialize interval patterns locale to this formatter
michael@0 555 *
michael@0 556 * This code is a bit complicated since
michael@0 557 * 1. the interval patterns saved in resource bundle files are interval
michael@0 558 * patterns based on date or time only.
michael@0 559 * It does not have interval patterns based on both date and time.
michael@0 560 * Interval patterns on both date and time are algorithm generated.
michael@0 561 *
michael@0 562 * For example, it has interval patterns on skeleton "dMy" and "hm",
michael@0 563 * but it does not have interval patterns on skeleton "dMyhm".
michael@0 564 *
michael@0 565 * The rule to genearte interval patterns for both date and time skeleton are
michael@0 566 * 1) when the year, month, or day differs, concatenate the two original
michael@0 567 * expressions with a separator between,
michael@0 568 * For example, interval pattern from "Jan 10, 2007 10:10 am"
michael@0 569 * to "Jan 11, 2007 10:10am" is
michael@0 570 * "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
michael@0 571 *
michael@0 572 * 2) otherwise, present the date followed by the range expression
michael@0 573 * for the time.
michael@0 574 * For example, interval pattern from "Jan 10, 2007 10:10 am"
michael@0 575 * to "Jan 10, 2007 11:10am" is
michael@0 576 * "Jan 10, 2007 10:10 am - 11:10am"
michael@0 577 *
michael@0 578 * 2. even a pattern does not request a certion calendar field,
michael@0 579 * the interval pattern needs to include such field if such fields are
michael@0 580 * different between 2 dates.
michael@0 581 * For example, a pattern/skeleton is "hm", but the interval pattern
michael@0 582 * includes year, month, and date when year, month, and date differs.
michael@0 583 *
michael@0 584 * @param status output param set to success/failure code on exit
michael@0 585 * @stable ICU 4.0
michael@0 586 */
michael@0 587 void
michael@0 588 DateIntervalFormat::initializePattern(UErrorCode& status) {
michael@0 589 if ( U_FAILURE(status) ) {
michael@0 590 return;
michael@0 591 }
michael@0 592 const Locale& locale = fDateFormat->getSmpFmtLocale();
michael@0 593 if ( fSkeleton.isEmpty() ) {
michael@0 594 UnicodeString fullPattern;
michael@0 595 fDateFormat->toPattern(fullPattern);
michael@0 596 #ifdef DTITVFMT_DEBUG
michael@0 597 char result[1000];
michael@0 598 char result_1[1000];
michael@0 599 char mesg[2000];
michael@0 600 fSkeleton.extract(0, fSkeleton.length(), result, "UTF-8");
michael@0 601 sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result);
michael@0 602 PRINTMESG(mesg)
michael@0 603 #endif
michael@0 604 // fSkeleton is already set by createDateIntervalInstance()
michael@0 605 // or by createInstance(UnicodeString skeleton, .... )
michael@0 606 fSkeleton = fDtpng->getSkeleton(fullPattern, status);
michael@0 607 if ( U_FAILURE(status) ) {
michael@0 608 return;
michael@0 609 }
michael@0 610 }
michael@0 611
michael@0 612 // initialize the fIntervalPattern ordering
michael@0 613 int8_t i;
michael@0 614 for ( i = 0; i < DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
michael@0 615 fIntervalPatterns[i].laterDateFirst = fInfo->getDefaultOrder();
michael@0 616 }
michael@0 617
michael@0 618 /* Check whether the skeleton is a combination of date and time.
michael@0 619 * For the complication reason 1 explained above.
michael@0 620 */
michael@0 621 UnicodeString dateSkeleton;
michael@0 622 UnicodeString timeSkeleton;
michael@0 623 UnicodeString normalizedTimeSkeleton;
michael@0 624 UnicodeString normalizedDateSkeleton;
michael@0 625
michael@0 626
michael@0 627 /* the difference between time skeleton and normalizedTimeSkeleton are:
michael@0 628 * 1. (Formerly, normalized time skeleton folded 'H' to 'h'; no longer true)
michael@0 629 * 2. 'a' is omitted in normalized time skeleton.
michael@0 630 * 3. there is only one appearance for 'h' or 'H', 'm','v', 'z' in normalized
michael@0 631 * time skeleton
michael@0 632 *
michael@0 633 * The difference between date skeleton and normalizedDateSkeleton are:
michael@0 634 * 1. both 'y' and 'd' appear only once in normalizeDateSkeleton
michael@0 635 * 2. 'E' and 'EE' are normalized into 'EEE'
michael@0 636 * 3. 'MM' is normalized into 'M'
michael@0 637 */
michael@0 638 getDateTimeSkeleton(fSkeleton, dateSkeleton, normalizedDateSkeleton,
michael@0 639 timeSkeleton, normalizedTimeSkeleton);
michael@0 640
michael@0 641 #ifdef DTITVFMT_DEBUG
michael@0 642 char result[1000];
michael@0 643 char result_1[1000];
michael@0 644 char mesg[2000];
michael@0 645 fSkeleton.extract(0, fSkeleton.length(), result, "UTF-8");
michael@0 646 sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result);
michael@0 647 PRINTMESG(mesg)
michael@0 648 #endif
michael@0 649
michael@0 650
michael@0 651 UBool found = setSeparateDateTimePtn(normalizedDateSkeleton,
michael@0 652 normalizedTimeSkeleton);
michael@0 653
michael@0 654 if ( found == false ) {
michael@0 655 // use fallback
michael@0 656 // TODO: if user asks "m"(minute), but "d"(day) differ
michael@0 657 if ( timeSkeleton.length() != 0 ) {
michael@0 658 if ( dateSkeleton.length() == 0 ) {
michael@0 659 // prefix with yMd
michael@0 660 timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort], -1);
michael@0 661 UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status);
michael@0 662 if ( U_FAILURE(status) ) {
michael@0 663 return;
michael@0 664 }
michael@0 665 // for fall back interval patterns,
michael@0 666 // the first part of the pattern is empty,
michael@0 667 // the second part of the pattern is the full-pattern
michael@0 668 // should be used in fall-back.
michael@0 669 setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder());
michael@0 670 setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder());
michael@0 671 setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder());
michael@0 672 } else {
michael@0 673 // TODO: fall back
michael@0 674 }
michael@0 675 } else {
michael@0 676 // TODO: fall back
michael@0 677 }
michael@0 678 return;
michael@0 679 } // end of skeleton not found
michael@0 680 // interval patterns for skeleton are found in resource
michael@0 681 if ( timeSkeleton.length() == 0 ) {
michael@0 682 // done
michael@0 683 } else if ( dateSkeleton.length() == 0 ) {
michael@0 684 // prefix with yMd
michael@0 685 timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort], -1);
michael@0 686 UnicodeString pattern = fDtpng->getBestPattern(timeSkeleton, status);
michael@0 687 if ( U_FAILURE(status) ) {
michael@0 688 return;
michael@0 689 }
michael@0 690 // for fall back interval patterns,
michael@0 691 // the first part of the pattern is empty,
michael@0 692 // the second part of the pattern is the full-pattern
michael@0 693 // should be used in fall-back.
michael@0 694 setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder());
michael@0 695 setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder());
michael@0 696 setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder());
michael@0 697 } else {
michael@0 698 /* if both present,
michael@0 699 * 1) when the year, month, or day differs,
michael@0 700 * concatenate the two original expressions with a separator between,
michael@0 701 * 2) otherwise, present the date followed by the
michael@0 702 * range expression for the time.
michael@0 703 */
michael@0 704 /*
michael@0 705 * 1) when the year, month, or day differs,
michael@0 706 * concatenate the two original expressions with a separator between,
michael@0 707 */
michael@0 708 // if field exists, use fall back
michael@0 709 UnicodeString skeleton = fSkeleton;
michael@0 710 if ( !fieldExistsInSkeleton(UCAL_DATE, dateSkeleton) ) {
michael@0 711 // prefix skeleton with 'd'
michael@0 712 skeleton.insert(0, LOW_D);
michael@0 713 setFallbackPattern(UCAL_DATE, skeleton, status);
michael@0 714 }
michael@0 715 if ( !fieldExistsInSkeleton(UCAL_MONTH, dateSkeleton) ) {
michael@0 716 // then prefix skeleton with 'M'
michael@0 717 skeleton.insert(0, CAP_M);
michael@0 718 setFallbackPattern(UCAL_MONTH, skeleton, status);
michael@0 719 }
michael@0 720 if ( !fieldExistsInSkeleton(UCAL_YEAR, dateSkeleton) ) {
michael@0 721 // then prefix skeleton with 'y'
michael@0 722 skeleton.insert(0, LOW_Y);
michael@0 723 setFallbackPattern(UCAL_YEAR, skeleton, status);
michael@0 724 }
michael@0 725
michael@0 726 /*
michael@0 727 * 2) otherwise, present the date followed by the
michael@0 728 * range expression for the time.
michael@0 729 */
michael@0 730 // Need the Date/Time pattern for concatnation the date with
michael@0 731 // the time interval.
michael@0 732 // The date/time pattern ( such as {0} {1} ) is saved in
michael@0 733 // calendar, that is why need to get the CalendarData here.
michael@0 734 CalendarData* calData = new CalendarData(locale, NULL, status);
michael@0 735
michael@0 736 if ( U_FAILURE(status) ) {
michael@0 737 delete calData;
michael@0 738 return;
michael@0 739 }
michael@0 740
michael@0 741 if ( calData == NULL ) {
michael@0 742 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 743 return;
michael@0 744 }
michael@0 745
michael@0 746 const UResourceBundle* dateTimePatternsRes = calData->getByKey(
michael@0 747 gDateTimePatternsTag, status);
michael@0 748 int32_t dateTimeFormatLength;
michael@0 749 const UChar* dateTimeFormat = ures_getStringByIndex(
michael@0 750 dateTimePatternsRes,
michael@0 751 (int32_t)DateFormat::kDateTime,
michael@0 752 &dateTimeFormatLength, &status);
michael@0 753 if ( U_FAILURE(status) ) {
michael@0 754 return;
michael@0 755 }
michael@0 756
michael@0 757 UnicodeString datePattern = fDtpng->getBestPattern(dateSkeleton, status);
michael@0 758
michael@0 759 concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
michael@0 760 datePattern, UCAL_AM_PM, status);
michael@0 761 concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
michael@0 762 datePattern, UCAL_HOUR, status);
michael@0 763 concatSingleDate2TimeInterval(dateTimeFormat, dateTimeFormatLength,
michael@0 764 datePattern, UCAL_MINUTE, status);
michael@0 765 delete calData;
michael@0 766 }
michael@0 767 }
michael@0 768
michael@0 769
michael@0 770
michael@0 771 void U_EXPORT2
michael@0 772 DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
michael@0 773 UnicodeString& dateSkeleton,
michael@0 774 UnicodeString& normalizedDateSkeleton,
michael@0 775 UnicodeString& timeSkeleton,
michael@0 776 UnicodeString& normalizedTimeSkeleton) {
michael@0 777 // dateSkeleton follows the sequence of y*M*E*d*
michael@0 778 // timeSkeleton follows the sequence of hm*[v|z]?
michael@0 779 int32_t ECount = 0;
michael@0 780 int32_t dCount = 0;
michael@0 781 int32_t MCount = 0;
michael@0 782 int32_t yCount = 0;
michael@0 783 int32_t hCount = 0;
michael@0 784 int32_t HCount = 0;
michael@0 785 int32_t mCount = 0;
michael@0 786 int32_t vCount = 0;
michael@0 787 int32_t zCount = 0;
michael@0 788 int32_t i;
michael@0 789
michael@0 790 for (i = 0; i < skeleton.length(); ++i) {
michael@0 791 UChar ch = skeleton[i];
michael@0 792 switch ( ch ) {
michael@0 793 case CAP_E:
michael@0 794 dateSkeleton.append(ch);
michael@0 795 ++ECount;
michael@0 796 break;
michael@0 797 case LOW_D:
michael@0 798 dateSkeleton.append(ch);
michael@0 799 ++dCount;
michael@0 800 break;
michael@0 801 case CAP_M:
michael@0 802 dateSkeleton.append(ch);
michael@0 803 ++MCount;
michael@0 804 break;
michael@0 805 case LOW_Y:
michael@0 806 dateSkeleton.append(ch);
michael@0 807 ++yCount;
michael@0 808 break;
michael@0 809 case CAP_G:
michael@0 810 case CAP_Y:
michael@0 811 case LOW_U:
michael@0 812 case CAP_Q:
michael@0 813 case LOW_Q:
michael@0 814 case CAP_L:
michael@0 815 case LOW_L:
michael@0 816 case CAP_W:
michael@0 817 case LOW_W:
michael@0 818 case CAP_D:
michael@0 819 case CAP_F:
michael@0 820 case LOW_G:
michael@0 821 case LOW_E:
michael@0 822 case LOW_C:
michael@0 823 normalizedDateSkeleton.append(ch);
michael@0 824 dateSkeleton.append(ch);
michael@0 825 break;
michael@0 826 case LOW_A:
michael@0 827 // 'a' is implicitly handled
michael@0 828 timeSkeleton.append(ch);
michael@0 829 break;
michael@0 830 case LOW_H:
michael@0 831 timeSkeleton.append(ch);
michael@0 832 ++hCount;
michael@0 833 break;
michael@0 834 case CAP_H:
michael@0 835 timeSkeleton.append(ch);
michael@0 836 ++HCount;
michael@0 837 break;
michael@0 838 case LOW_M:
michael@0 839 timeSkeleton.append(ch);
michael@0 840 ++mCount;
michael@0 841 break;
michael@0 842 case LOW_Z:
michael@0 843 ++zCount;
michael@0 844 timeSkeleton.append(ch);
michael@0 845 break;
michael@0 846 case LOW_V:
michael@0 847 ++vCount;
michael@0 848 timeSkeleton.append(ch);
michael@0 849 break;
michael@0 850 case CAP_V:
michael@0 851 case CAP_Z:
michael@0 852 case LOW_K:
michael@0 853 case CAP_K:
michael@0 854 case LOW_J:
michael@0 855 case LOW_S:
michael@0 856 case CAP_S:
michael@0 857 case CAP_A:
michael@0 858 timeSkeleton.append(ch);
michael@0 859 normalizedTimeSkeleton.append(ch);
michael@0 860 break;
michael@0 861 }
michael@0 862 }
michael@0 863
michael@0 864 /* generate normalized form for date*/
michael@0 865 if ( yCount != 0 ) {
michael@0 866 for (i = 0; i < yCount; ++i) {
michael@0 867 normalizedDateSkeleton.append(LOW_Y);
michael@0 868 }
michael@0 869 }
michael@0 870 if ( MCount != 0 ) {
michael@0 871 if ( MCount < 3 ) {
michael@0 872 normalizedDateSkeleton.append(CAP_M);
michael@0 873 } else {
michael@0 874 int32_t i;
michael@0 875 for ( i = 0; i < MCount && i < MAX_M_COUNT; ++i ) {
michael@0 876 normalizedDateSkeleton.append(CAP_M);
michael@0 877 }
michael@0 878 }
michael@0 879 }
michael@0 880 if ( ECount != 0 ) {
michael@0 881 if ( ECount <= 3 ) {
michael@0 882 normalizedDateSkeleton.append(CAP_E);
michael@0 883 } else {
michael@0 884 int32_t i;
michael@0 885 for ( i = 0; i < ECount && i < MAX_E_COUNT; ++i ) {
michael@0 886 normalizedDateSkeleton.append(CAP_E);
michael@0 887 }
michael@0 888 }
michael@0 889 }
michael@0 890 if ( dCount != 0 ) {
michael@0 891 normalizedDateSkeleton.append(LOW_D);
michael@0 892 }
michael@0 893
michael@0 894 /* generate normalized form for time */
michael@0 895 if ( HCount != 0 ) {
michael@0 896 normalizedTimeSkeleton.append(CAP_H);
michael@0 897 }
michael@0 898 else if ( hCount != 0 ) {
michael@0 899 normalizedTimeSkeleton.append(LOW_H);
michael@0 900 }
michael@0 901 if ( mCount != 0 ) {
michael@0 902 normalizedTimeSkeleton.append(LOW_M);
michael@0 903 }
michael@0 904 if ( zCount != 0 ) {
michael@0 905 normalizedTimeSkeleton.append(LOW_Z);
michael@0 906 }
michael@0 907 if ( vCount != 0 ) {
michael@0 908 normalizedTimeSkeleton.append(LOW_V);
michael@0 909 }
michael@0 910 }
michael@0 911
michael@0 912
michael@0 913 /**
michael@0 914 * Generate date or time interval pattern from resource,
michael@0 915 * and set them into the interval pattern locale to this formatter.
michael@0 916 *
michael@0 917 * It needs to handle the following:
michael@0 918 * 1. need to adjust field width.
michael@0 919 * For example, the interval patterns saved in DateIntervalInfo
michael@0 920 * includes "dMMMy", but not "dMMMMy".
michael@0 921 * Need to get interval patterns for dMMMMy from dMMMy.
michael@0 922 * Another example, the interval patterns saved in DateIntervalInfo
michael@0 923 * includes "hmv", but not "hmz".
michael@0 924 * Need to get interval patterns for "hmz' from 'hmv'
michael@0 925 *
michael@0 926 * 2. there might be no pattern for 'y' differ for skeleton "Md",
michael@0 927 * in order to get interval patterns for 'y' differ,
michael@0 928 * need to look for it from skeleton 'yMd'
michael@0 929 *
michael@0 930 * @param dateSkeleton normalized date skeleton
michael@0 931 * @param timeSkeleton normalized time skeleton
michael@0 932 * @return whether the resource is found for the skeleton.
michael@0 933 * TRUE if interval pattern found for the skeleton,
michael@0 934 * FALSE otherwise.
michael@0 935 * @stable ICU 4.0
michael@0 936 */
michael@0 937 UBool
michael@0 938 DateIntervalFormat::setSeparateDateTimePtn(
michael@0 939 const UnicodeString& dateSkeleton,
michael@0 940 const UnicodeString& timeSkeleton) {
michael@0 941 const UnicodeString* skeleton;
michael@0 942 // if both date and time skeleton present,
michael@0 943 // the final interval pattern might include time interval patterns
michael@0 944 // ( when, am_pm, hour, minute differ ),
michael@0 945 // but not date interval patterns ( when year, month, day differ ).
michael@0 946 // For year/month/day differ, it falls back to fall-back pattern.
michael@0 947 if ( timeSkeleton.length() != 0 ) {
michael@0 948 skeleton = &timeSkeleton;
michael@0 949 } else {
michael@0 950 skeleton = &dateSkeleton;
michael@0 951 }
michael@0 952
michael@0 953 /* interval patterns for skeleton "dMMMy" (but not "dMMMMy")
michael@0 954 * are defined in resource,
michael@0 955 * interval patterns for skeleton "dMMMMy" are calculated by
michael@0 956 * 1. get the best match skeleton for "dMMMMy", which is "dMMMy"
michael@0 957 * 2. get the interval patterns for "dMMMy",
michael@0 958 * 3. extend "MMM" to "MMMM" in above interval patterns for "dMMMMy"
michael@0 959 * getBestSkeleton() is step 1.
michael@0 960 */
michael@0 961 // best skeleton, and the difference information
michael@0 962 int8_t differenceInfo = 0;
michael@0 963 const UnicodeString* bestSkeleton = fInfo->getBestSkeleton(*skeleton,
michael@0 964 differenceInfo);
michael@0 965 /* best skeleton could be NULL.
michael@0 966 For example: in "ca" resource file,
michael@0 967 interval format is defined as following
michael@0 968 intervalFormats{
michael@0 969 fallback{"{0} - {1}"}
michael@0 970 }
michael@0 971 there is no skeletons/interval patterns defined,
michael@0 972 and the best skeleton match could be NULL
michael@0 973 */
michael@0 974 if ( bestSkeleton == NULL ) {
michael@0 975 return false;
michael@0 976 }
michael@0 977
michael@0 978 // difference:
michael@0 979 // 0 means the best matched skeleton is the same as input skeleton
michael@0 980 // 1 means the fields are the same, but field width are different
michael@0 981 // 2 means the only difference between fields are v/z,
michael@0 982 // -1 means there are other fields difference
michael@0 983 if ( differenceInfo == -1 ) {
michael@0 984 // skeleton has different fields, not only v/z difference
michael@0 985 return false;
michael@0 986 }
michael@0 987
michael@0 988 if ( timeSkeleton.length() == 0 ) {
michael@0 989 UnicodeString extendedSkeleton;
michael@0 990 UnicodeString extendedBestSkeleton;
michael@0 991 // only has date skeleton
michael@0 992 setIntervalPattern(UCAL_DATE, skeleton, bestSkeleton, differenceInfo,
michael@0 993 &extendedSkeleton, &extendedBestSkeleton);
michael@0 994
michael@0 995 UBool extended = setIntervalPattern(UCAL_MONTH, skeleton, bestSkeleton,
michael@0 996 differenceInfo,
michael@0 997 &extendedSkeleton, &extendedBestSkeleton);
michael@0 998
michael@0 999 if ( extended ) {
michael@0 1000 bestSkeleton = &extendedBestSkeleton;
michael@0 1001 skeleton = &extendedSkeleton;
michael@0 1002 }
michael@0 1003 setIntervalPattern(UCAL_YEAR, skeleton, bestSkeleton, differenceInfo,
michael@0 1004 &extendedSkeleton, &extendedBestSkeleton);
michael@0 1005 } else {
michael@0 1006 setIntervalPattern(UCAL_MINUTE, skeleton, bestSkeleton, differenceInfo);
michael@0 1007 setIntervalPattern(UCAL_HOUR, skeleton, bestSkeleton, differenceInfo);
michael@0 1008 setIntervalPattern(UCAL_AM_PM, skeleton, bestSkeleton, differenceInfo);
michael@0 1009 }
michael@0 1010 return true;
michael@0 1011 }
michael@0 1012
michael@0 1013
michael@0 1014
michael@0 1015 void
michael@0 1016 DateIntervalFormat::setFallbackPattern(UCalendarDateFields field,
michael@0 1017 const UnicodeString& skeleton,
michael@0 1018 UErrorCode& status) {
michael@0 1019 if ( U_FAILURE(status) ) {
michael@0 1020 return;
michael@0 1021 }
michael@0 1022 UnicodeString pattern = fDtpng->getBestPattern(skeleton, status);
michael@0 1023 if ( U_FAILURE(status) ) {
michael@0 1024 return;
michael@0 1025 }
michael@0 1026 setPatternInfo(field, NULL, &pattern, fInfo->getDefaultOrder());
michael@0 1027 }
michael@0 1028
michael@0 1029
michael@0 1030
michael@0 1031
michael@0 1032 void
michael@0 1033 DateIntervalFormat::setPatternInfo(UCalendarDateFields field,
michael@0 1034 const UnicodeString* firstPart,
michael@0 1035 const UnicodeString* secondPart,
michael@0 1036 UBool laterDateFirst) {
michael@0 1037 // for fall back interval patterns,
michael@0 1038 // the first part of the pattern is empty,
michael@0 1039 // the second part of the pattern is the full-pattern
michael@0 1040 // should be used in fall-back.
michael@0 1041 UErrorCode status = U_ZERO_ERROR;
michael@0 1042 // following should not set any wrong status.
michael@0 1043 int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
michael@0 1044 status);
michael@0 1045 if ( U_FAILURE(status) ) {
michael@0 1046 return;
michael@0 1047 }
michael@0 1048 PatternInfo& ptn = fIntervalPatterns[itvPtnIndex];
michael@0 1049 if ( firstPart ) {
michael@0 1050 ptn.firstPart = *firstPart;
michael@0 1051 }
michael@0 1052 if ( secondPart ) {
michael@0 1053 ptn.secondPart = *secondPart;
michael@0 1054 }
michael@0 1055 ptn.laterDateFirst = laterDateFirst;
michael@0 1056 }
michael@0 1057
michael@0 1058 void
michael@0 1059 DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
michael@0 1060 const UnicodeString& intervalPattern) {
michael@0 1061 UBool order = fInfo->getDefaultOrder();
michael@0 1062 setIntervalPattern(field, intervalPattern, order);
michael@0 1063 }
michael@0 1064
michael@0 1065
michael@0 1066 void
michael@0 1067 DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
michael@0 1068 const UnicodeString& intervalPattern,
michael@0 1069 UBool laterDateFirst) {
michael@0 1070 const UnicodeString* pattern = &intervalPattern;
michael@0 1071 UBool order = laterDateFirst;
michael@0 1072 // check for "latestFirst:" or "earliestFirst:" prefix
michael@0 1073 int8_t prefixLength = sizeof(gLaterFirstPrefix)/sizeof(gLaterFirstPrefix[0]);
michael@0 1074 int8_t earliestFirstLength = sizeof(gEarlierFirstPrefix)/sizeof(gEarlierFirstPrefix[0]);
michael@0 1075 UnicodeString realPattern;
michael@0 1076 if ( intervalPattern.startsWith(gLaterFirstPrefix, prefixLength) ) {
michael@0 1077 order = true;
michael@0 1078 intervalPattern.extract(prefixLength,
michael@0 1079 intervalPattern.length() - prefixLength,
michael@0 1080 realPattern);
michael@0 1081 pattern = &realPattern;
michael@0 1082 } else if ( intervalPattern.startsWith(gEarlierFirstPrefix,
michael@0 1083 earliestFirstLength) ) {
michael@0 1084 order = false;
michael@0 1085 intervalPattern.extract(earliestFirstLength,
michael@0 1086 intervalPattern.length() - earliestFirstLength,
michael@0 1087 realPattern);
michael@0 1088 pattern = &realPattern;
michael@0 1089 }
michael@0 1090
michael@0 1091 int32_t splitPoint = splitPatternInto2Part(*pattern);
michael@0 1092
michael@0 1093 UnicodeString firstPart;
michael@0 1094 UnicodeString secondPart;
michael@0 1095 pattern->extract(0, splitPoint, firstPart);
michael@0 1096 if ( splitPoint < pattern->length() ) {
michael@0 1097 pattern->extract(splitPoint, pattern->length()-splitPoint, secondPart);
michael@0 1098 }
michael@0 1099 setPatternInfo(field, &firstPart, &secondPart, order);
michael@0 1100 }
michael@0 1101
michael@0 1102
michael@0 1103
michael@0 1104
michael@0 1105 /**
michael@0 1106 * Generate interval pattern from existing resource
michael@0 1107 *
michael@0 1108 * It not only save the interval patterns,
michael@0 1109 * but also return the extended skeleton and its best match skeleton.
michael@0 1110 *
michael@0 1111 * @param field largest different calendar field
michael@0 1112 * @param skeleton skeleton
michael@0 1113 * @param bestSkeleton the best match skeleton which has interval pattern
michael@0 1114 * defined in resource
michael@0 1115 * @param differenceInfo the difference between skeleton and best skeleton
michael@0 1116 * 0 means the best matched skeleton is the same as input skeleton
michael@0 1117 * 1 means the fields are the same, but field width are different
michael@0 1118 * 2 means the only difference between fields are v/z,
michael@0 1119 * -1 means there are other fields difference
michael@0 1120 *
michael@0 1121 * @param extendedSkeleton extended skeleton
michael@0 1122 * @param extendedBestSkeleton extended best match skeleton
michael@0 1123 * @return whether the interval pattern is found
michael@0 1124 * through extending skeleton or not.
michael@0 1125 * TRUE if interval pattern is found by
michael@0 1126 * extending skeleton, FALSE otherwise.
michael@0 1127 * @stable ICU 4.0
michael@0 1128 */
michael@0 1129 UBool
michael@0 1130 DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
michael@0 1131 const UnicodeString* skeleton,
michael@0 1132 const UnicodeString* bestSkeleton,
michael@0 1133 int8_t differenceInfo,
michael@0 1134 UnicodeString* extendedSkeleton,
michael@0 1135 UnicodeString* extendedBestSkeleton) {
michael@0 1136 UErrorCode status = U_ZERO_ERROR;
michael@0 1137 // following getIntervalPattern() should not generate error status
michael@0 1138 UnicodeString pattern;
michael@0 1139 fInfo->getIntervalPattern(*bestSkeleton, field, pattern, status);
michael@0 1140 if ( pattern.isEmpty() ) {
michael@0 1141 // single date
michael@0 1142 if ( SimpleDateFormat::isFieldUnitIgnored(*bestSkeleton, field) ) {
michael@0 1143 // do nothing, format will handle it
michael@0 1144 return false;
michael@0 1145 }
michael@0 1146
michael@0 1147 // for 24 hour system, interval patterns in resource file
michael@0 1148 // might not include pattern when am_pm differ,
michael@0 1149 // which should be the same as hour differ.
michael@0 1150 // add it here for simplicity
michael@0 1151 if ( field == UCAL_AM_PM ) {
michael@0 1152 fInfo->getIntervalPattern(*bestSkeleton, UCAL_HOUR, pattern,status);
michael@0 1153 if ( !pattern.isEmpty() ) {
michael@0 1154 setIntervalPattern(field, pattern);
michael@0 1155 }
michael@0 1156 return false;
michael@0 1157 }
michael@0 1158 // else, looking for pattern when 'y' differ for 'dMMMM' skeleton,
michael@0 1159 // first, get best match pattern "MMMd",
michael@0 1160 // since there is no pattern for 'y' differs for skeleton 'MMMd',
michael@0 1161 // need to look for it from skeleton 'yMMMd',
michael@0 1162 // if found, adjust field width in interval pattern from
michael@0 1163 // "MMM" to "MMMM".
michael@0 1164 UChar fieldLetter = fgCalendarFieldToPatternLetter[field];
michael@0 1165 if ( extendedSkeleton ) {
michael@0 1166 *extendedSkeleton = *skeleton;
michael@0 1167 *extendedBestSkeleton = *bestSkeleton;
michael@0 1168 extendedSkeleton->insert(0, fieldLetter);
michael@0 1169 extendedBestSkeleton->insert(0, fieldLetter);
michael@0 1170 // for example, looking for patterns when 'y' differ for
michael@0 1171 // skeleton "MMMM".
michael@0 1172 fInfo->getIntervalPattern(*extendedBestSkeleton,field,pattern,status);
michael@0 1173 if ( pattern.isEmpty() && differenceInfo == 0 ) {
michael@0 1174 // if there is no skeleton "yMMMM" defined,
michael@0 1175 // look for the best match skeleton, for example: "yMMM"
michael@0 1176 const UnicodeString* tmpBest = fInfo->getBestSkeleton(
michael@0 1177 *extendedBestSkeleton, differenceInfo);
michael@0 1178 if ( tmpBest != 0 && differenceInfo != -1 ) {
michael@0 1179 fInfo->getIntervalPattern(*tmpBest, field, pattern, status);
michael@0 1180 bestSkeleton = tmpBest;
michael@0 1181 }
michael@0 1182 }
michael@0 1183 }
michael@0 1184 }
michael@0 1185 if ( !pattern.isEmpty() ) {
michael@0 1186 if ( differenceInfo != 0 ) {
michael@0 1187 UnicodeString adjustIntervalPattern;
michael@0 1188 adjustFieldWidth(*skeleton, *bestSkeleton, pattern, differenceInfo,
michael@0 1189 adjustIntervalPattern);
michael@0 1190 setIntervalPattern(field, adjustIntervalPattern);
michael@0 1191 } else {
michael@0 1192 setIntervalPattern(field, pattern);
michael@0 1193 }
michael@0 1194 if ( extendedSkeleton && !extendedSkeleton->isEmpty() ) {
michael@0 1195 return TRUE;
michael@0 1196 }
michael@0 1197 }
michael@0 1198 return FALSE;
michael@0 1199 }
michael@0 1200
michael@0 1201
michael@0 1202
michael@0 1203 int32_t U_EXPORT2
michael@0 1204 DateIntervalFormat::splitPatternInto2Part(const UnicodeString& intervalPattern) {
michael@0 1205 UBool inQuote = false;
michael@0 1206 UChar prevCh = 0;
michael@0 1207 int32_t count = 0;
michael@0 1208
michael@0 1209 /* repeatedPattern used to record whether a pattern has already seen.
michael@0 1210 It is a pattern applies to first calendar if it is first time seen,
michael@0 1211 otherwise, it is a pattern applies to the second calendar
michael@0 1212 */
michael@0 1213 UBool patternRepeated[] =
michael@0 1214 {
michael@0 1215 // A B C D E F G H I J K L M N O
michael@0 1216 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 1217 // P Q R S T U V W X Y Z
michael@0 1218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 1219 // a b c d e f g h i j k l m n o
michael@0 1220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 1221 // p q r s t u v w x y z
michael@0 1222 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
michael@0 1223 };
michael@0 1224
michael@0 1225 int8_t PATTERN_CHAR_BASE = 0x41;
michael@0 1226
michael@0 1227 /* loop through the pattern string character by character looking for
michael@0 1228 * the first repeated pattern letter, which breaks the interval pattern
michael@0 1229 * into 2 parts.
michael@0 1230 */
michael@0 1231 int32_t i;
michael@0 1232 UBool foundRepetition = false;
michael@0 1233 for (i = 0; i < intervalPattern.length(); ++i) {
michael@0 1234 UChar ch = intervalPattern.charAt(i);
michael@0 1235
michael@0 1236 if (ch != prevCh && count > 0) {
michael@0 1237 // check the repeativeness of pattern letter
michael@0 1238 UBool repeated = patternRepeated[(int)(prevCh - PATTERN_CHAR_BASE)];
michael@0 1239 if ( repeated == FALSE ) {
michael@0 1240 patternRepeated[prevCh - PATTERN_CHAR_BASE] = TRUE;
michael@0 1241 } else {
michael@0 1242 foundRepetition = true;
michael@0 1243 break;
michael@0 1244 }
michael@0 1245 count = 0;
michael@0 1246 }
michael@0 1247 if (ch == '\'') {
michael@0 1248 // Consecutive single quotes are a single quote literal,
michael@0 1249 // either outside of quotes or between quotes
michael@0 1250 if ((i+1) < intervalPattern.length() &&
michael@0 1251 intervalPattern.charAt(i+1) == '\'') {
michael@0 1252 ++i;
michael@0 1253 } else {
michael@0 1254 inQuote = ! inQuote;
michael@0 1255 }
michael@0 1256 }
michael@0 1257 else if (!inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
michael@0 1258 || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
michael@0 1259 // ch is a date-time pattern character
michael@0 1260 prevCh = ch;
michael@0 1261 ++count;
michael@0 1262 }
michael@0 1263 }
michael@0 1264 // check last pattern char, distinguish
michael@0 1265 // "dd MM" ( no repetition ),
michael@0 1266 // "d-d"(last char repeated ), and
michael@0 1267 // "d-d MM" ( repetition found )
michael@0 1268 if ( count > 0 && foundRepetition == FALSE ) {
michael@0 1269 if ( patternRepeated[(int)(prevCh - PATTERN_CHAR_BASE)] == FALSE ) {
michael@0 1270 count = 0;
michael@0 1271 }
michael@0 1272 }
michael@0 1273 return (i - count);
michael@0 1274 }
michael@0 1275
michael@0 1276
michael@0 1277
michael@0 1278 UnicodeString&
michael@0 1279 DateIntervalFormat::fallbackFormat(Calendar& fromCalendar,
michael@0 1280 Calendar& toCalendar,
michael@0 1281 UnicodeString& appendTo,
michael@0 1282 FieldPosition& pos,
michael@0 1283 UErrorCode& status) const {
michael@0 1284 if ( U_FAILURE(status) ) {
michael@0 1285 return appendTo;
michael@0 1286 }
michael@0 1287 // the fall back
michael@0 1288 // no need delete earlierDate and laterDate since they are adopted
michael@0 1289 UnicodeString* earlierDate = new UnicodeString();
michael@0 1290 *earlierDate = fDateFormat->format(fromCalendar, *earlierDate, pos);
michael@0 1291 UnicodeString* laterDate = new UnicodeString();
michael@0 1292 *laterDate = fDateFormat->format(toCalendar, *laterDate, pos);
michael@0 1293 UnicodeString fallbackPattern;
michael@0 1294 fInfo->getFallbackIntervalPattern(fallbackPattern);
michael@0 1295 Formattable fmtArray[2];
michael@0 1296 fmtArray[0].adoptString(earlierDate);
michael@0 1297 fmtArray[1].adoptString(laterDate);
michael@0 1298
michael@0 1299 UnicodeString fallback;
michael@0 1300 MessageFormat::format(fallbackPattern, fmtArray, 2, fallback, status);
michael@0 1301 if ( U_SUCCESS(status) ) {
michael@0 1302 appendTo.append(fallback);
michael@0 1303 }
michael@0 1304 return appendTo;
michael@0 1305 }
michael@0 1306
michael@0 1307
michael@0 1308
michael@0 1309
michael@0 1310 UBool U_EXPORT2
michael@0 1311 DateIntervalFormat::fieldExistsInSkeleton(UCalendarDateFields field,
michael@0 1312 const UnicodeString& skeleton)
michael@0 1313 {
michael@0 1314 const UChar fieldChar = fgCalendarFieldToPatternLetter[field];
michael@0 1315 return ( (skeleton.indexOf(fieldChar) == -1)?FALSE:TRUE ) ;
michael@0 1316 }
michael@0 1317
michael@0 1318
michael@0 1319
michael@0 1320 void U_EXPORT2
michael@0 1321 DateIntervalFormat::adjustFieldWidth(const UnicodeString& inputSkeleton,
michael@0 1322 const UnicodeString& bestMatchSkeleton,
michael@0 1323 const UnicodeString& bestIntervalPattern,
michael@0 1324 int8_t differenceInfo,
michael@0 1325 UnicodeString& adjustedPtn) {
michael@0 1326 adjustedPtn = bestIntervalPattern;
michael@0 1327 int32_t inputSkeletonFieldWidth[] =
michael@0 1328 {
michael@0 1329 // A B C D E F G H I J K L M N O
michael@0 1330 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 1331 // P Q R S T U V W X Y Z
michael@0 1332 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 1333 // a b c d e f g h i j k l m n o
michael@0 1334 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 1335 // p q r s t u v w x y z
michael@0 1336 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
michael@0 1337 };
michael@0 1338
michael@0 1339 int32_t bestMatchSkeletonFieldWidth[] =
michael@0 1340 {
michael@0 1341 // A B C D E F G H I J K L M N O
michael@0 1342 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 1343 // P Q R S T U V W X Y Z
michael@0 1344 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 1345 // a b c d e f g h i j k l m n o
michael@0 1346 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
michael@0 1347 // p q r s t u v w x y z
michael@0 1348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
michael@0 1349 };
michael@0 1350
michael@0 1351 DateIntervalInfo::parseSkeleton(inputSkeleton, inputSkeletonFieldWidth);
michael@0 1352 DateIntervalInfo::parseSkeleton(bestMatchSkeleton, bestMatchSkeletonFieldWidth);
michael@0 1353 if ( differenceInfo == 2 ) {
michael@0 1354 adjustedPtn.findAndReplace(UnicodeString((UChar)0x76 /* v */),
michael@0 1355 UnicodeString((UChar)0x7a /* z */));
michael@0 1356 }
michael@0 1357
michael@0 1358 UBool inQuote = false;
michael@0 1359 UChar prevCh = 0;
michael@0 1360 int32_t count = 0;
michael@0 1361
michael@0 1362 const int8_t PATTERN_CHAR_BASE = 0x41;
michael@0 1363
michael@0 1364 // loop through the pattern string character by character
michael@0 1365 int32_t adjustedPtnLength = adjustedPtn.length();
michael@0 1366 int32_t i;
michael@0 1367 for (i = 0; i < adjustedPtnLength; ++i) {
michael@0 1368 UChar ch = adjustedPtn.charAt(i);
michael@0 1369 if (ch != prevCh && count > 0) {
michael@0 1370 // check the repeativeness of pattern letter
michael@0 1371 UChar skeletonChar = prevCh;
michael@0 1372 if ( skeletonChar == CAP_L ) {
michael@0 1373 // there is no "L" (always be "M") in skeleton,
michael@0 1374 // but there is "L" in pattern.
michael@0 1375 // for skeleton "M+", the pattern might be "...L..."
michael@0 1376 skeletonChar = CAP_M;
michael@0 1377 }
michael@0 1378 int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
michael@0 1379 int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
michael@0 1380 if ( fieldCount == count && inputFieldCount > fieldCount ) {
michael@0 1381 count = inputFieldCount - fieldCount;
michael@0 1382 int32_t j;
michael@0 1383 for ( j = 0; j < count; ++j ) {
michael@0 1384 adjustedPtn.insert(i, prevCh);
michael@0 1385 }
michael@0 1386 i += count;
michael@0 1387 adjustedPtnLength += count;
michael@0 1388 }
michael@0 1389 count = 0;
michael@0 1390 }
michael@0 1391 if (ch == '\'') {
michael@0 1392 // Consecutive single quotes are a single quote literal,
michael@0 1393 // either outside of quotes or between quotes
michael@0 1394 if ((i+1) < adjustedPtn.length() && adjustedPtn.charAt(i+1) == '\'') {
michael@0 1395 ++i;
michael@0 1396 } else {
michael@0 1397 inQuote = ! inQuote;
michael@0 1398 }
michael@0 1399 }
michael@0 1400 else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
michael@0 1401 || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
michael@0 1402 // ch is a date-time pattern character
michael@0 1403 prevCh = ch;
michael@0 1404 ++count;
michael@0 1405 }
michael@0 1406 }
michael@0 1407 if ( count > 0 ) {
michael@0 1408 // last item
michael@0 1409 // check the repeativeness of pattern letter
michael@0 1410 UChar skeletonChar = prevCh;
michael@0 1411 if ( skeletonChar == CAP_L ) {
michael@0 1412 // there is no "L" (always be "M") in skeleton,
michael@0 1413 // but there is "L" in pattern.
michael@0 1414 // for skeleton "M+", the pattern might be "...L..."
michael@0 1415 skeletonChar = CAP_M;
michael@0 1416 }
michael@0 1417 int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
michael@0 1418 int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
michael@0 1419 if ( fieldCount == count && inputFieldCount > fieldCount ) {
michael@0 1420 count = inputFieldCount - fieldCount;
michael@0 1421 int32_t j;
michael@0 1422 for ( j = 0; j < count; ++j ) {
michael@0 1423 adjustedPtn.append(prevCh);
michael@0 1424 }
michael@0 1425 }
michael@0 1426 }
michael@0 1427 }
michael@0 1428
michael@0 1429
michael@0 1430
michael@0 1431 void
michael@0 1432 DateIntervalFormat::concatSingleDate2TimeInterval(const UChar* format,
michael@0 1433 int32_t formatLen,
michael@0 1434 const UnicodeString& datePattern,
michael@0 1435 UCalendarDateFields field,
michael@0 1436 UErrorCode& status) {
michael@0 1437 // following should not set wrong status
michael@0 1438 int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
michael@0 1439 status);
michael@0 1440 if ( U_FAILURE(status) ) {
michael@0 1441 return;
michael@0 1442 }
michael@0 1443 PatternInfo& timeItvPtnInfo = fIntervalPatterns[itvPtnIndex];
michael@0 1444 if ( !timeItvPtnInfo.firstPart.isEmpty() ) {
michael@0 1445 // UnicodeString allocated here is adopted, so no need to delete
michael@0 1446 UnicodeString* timeIntervalPattern = new UnicodeString(timeItvPtnInfo.firstPart);
michael@0 1447 timeIntervalPattern->append(timeItvPtnInfo.secondPart);
michael@0 1448 UnicodeString* dateStr = new UnicodeString(datePattern);
michael@0 1449 Formattable fmtArray[2];
michael@0 1450 fmtArray[0].adoptString(timeIntervalPattern);
michael@0 1451 fmtArray[1].adoptString(dateStr);
michael@0 1452 UnicodeString combinedPattern;
michael@0 1453 MessageFormat::format(UnicodeString(TRUE, format, formatLen),
michael@0 1454 fmtArray, 2, combinedPattern, status);
michael@0 1455 if ( U_FAILURE(status) ) {
michael@0 1456 return;
michael@0 1457 }
michael@0 1458 setIntervalPattern(field, combinedPattern, timeItvPtnInfo.laterDateFirst);
michael@0 1459 }
michael@0 1460 // else: fall back
michael@0 1461 // it should not happen if the interval format defined is valid
michael@0 1462 }
michael@0 1463
michael@0 1464
michael@0 1465
michael@0 1466 const UChar
michael@0 1467 DateIntervalFormat::fgCalendarFieldToPatternLetter[] =
michael@0 1468 {
michael@0 1469 /*GyM*/ CAP_G, LOW_Y, CAP_M,
michael@0 1470 /*wWd*/ LOW_W, CAP_W, LOW_D,
michael@0 1471 /*DEF*/ CAP_D, CAP_E, CAP_F,
michael@0 1472 /*ahH*/ LOW_A, LOW_H, CAP_H,
michael@0 1473 /*m..*/ LOW_M,
michael@0 1474 };
michael@0 1475
michael@0 1476
michael@0 1477 U_NAMESPACE_END
michael@0 1478
michael@0 1479 #endif

mercurial