Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* |
michael@0 | 2 | ******************************************************************************* |
michael@0 | 3 | * Copyright (C) 2007-2013, International Business Machines Corporation and |
michael@0 | 4 | * others. All Rights Reserved. |
michael@0 | 5 | ******************************************************************************* |
michael@0 | 6 | */ |
michael@0 | 7 | |
michael@0 | 8 | #include "unicode/utypes.h" |
michael@0 | 9 | |
michael@0 | 10 | #if !UCONFIG_NO_FORMATTING |
michael@0 | 11 | |
michael@0 | 12 | #include <stdlib.h> |
michael@0 | 13 | |
michael@0 | 14 | #include "reldtfmt.h" |
michael@0 | 15 | #include "unicode/datefmt.h" |
michael@0 | 16 | #include "unicode/smpdtfmt.h" |
michael@0 | 17 | #include "unicode/msgfmt.h" |
michael@0 | 18 | |
michael@0 | 19 | #include "gregoimp.h" // for CalendarData |
michael@0 | 20 | #include "cmemory.h" |
michael@0 | 21 | #include "uresimp.h" |
michael@0 | 22 | |
michael@0 | 23 | U_NAMESPACE_BEGIN |
michael@0 | 24 | |
michael@0 | 25 | |
michael@0 | 26 | /** |
michael@0 | 27 | * An array of URelativeString structs is used to store the resource data loaded out of the bundle. |
michael@0 | 28 | */ |
michael@0 | 29 | struct URelativeString { |
michael@0 | 30 | int32_t offset; /** offset of this item, such as, the relative date **/ |
michael@0 | 31 | int32_t len; /** length of the string **/ |
michael@0 | 32 | const UChar* string; /** string, or NULL if not set **/ |
michael@0 | 33 | }; |
michael@0 | 34 | |
michael@0 | 35 | static const char DT_DateTimePatternsTag[]="DateTimePatterns"; |
michael@0 | 36 | |
michael@0 | 37 | |
michael@0 | 38 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RelativeDateFormat) |
michael@0 | 39 | |
michael@0 | 40 | RelativeDateFormat::RelativeDateFormat(const RelativeDateFormat& other) : |
michael@0 | 41 | DateFormat(other), fDateTimeFormatter(NULL), fDatePattern(other.fDatePattern), |
michael@0 | 42 | fTimePattern(other.fTimePattern), fCombinedFormat(NULL), |
michael@0 | 43 | fDateStyle(other.fDateStyle), fLocale(other.fLocale), |
michael@0 | 44 | fDayMin(other.fDayMin), fDayMax(other.fDayMax), |
michael@0 | 45 | fDatesLen(other.fDatesLen), fDates(NULL) |
michael@0 | 46 | { |
michael@0 | 47 | if(other.fDateTimeFormatter != NULL) { |
michael@0 | 48 | fDateTimeFormatter = (SimpleDateFormat*)other.fDateTimeFormatter->clone(); |
michael@0 | 49 | } |
michael@0 | 50 | if(other.fCombinedFormat != NULL) { |
michael@0 | 51 | fCombinedFormat = (MessageFormat*)other.fCombinedFormat->clone(); |
michael@0 | 52 | } |
michael@0 | 53 | if (fDatesLen > 0) { |
michael@0 | 54 | fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*fDatesLen); |
michael@0 | 55 | uprv_memcpy(fDates, other.fDates, sizeof(fDates[0])*fDatesLen); |
michael@0 | 56 | } |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | RelativeDateFormat::RelativeDateFormat( UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, |
michael@0 | 60 | const Locale& locale, UErrorCode& status) : |
michael@0 | 61 | DateFormat(), fDateTimeFormatter(NULL), fDatePattern(), fTimePattern(), fCombinedFormat(NULL), |
michael@0 | 62 | fDateStyle(dateStyle), fLocale(locale), fDatesLen(0), fDates(NULL) |
michael@0 | 63 | { |
michael@0 | 64 | if(U_FAILURE(status) ) { |
michael@0 | 65 | return; |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | if (timeStyle < UDAT_NONE || timeStyle > UDAT_SHORT) { |
michael@0 | 69 | // don't support other time styles (e.g. relative styles), for now |
michael@0 | 70 | status = U_ILLEGAL_ARGUMENT_ERROR; |
michael@0 | 71 | return; |
michael@0 | 72 | } |
michael@0 | 73 | UDateFormatStyle baseDateStyle = (dateStyle > UDAT_SHORT)? (UDateFormatStyle)(dateStyle & ~UDAT_RELATIVE): dateStyle; |
michael@0 | 74 | DateFormat * df; |
michael@0 | 75 | // Get fDateTimeFormatter from either date or time style (does not matter, we will override the pattern). |
michael@0 | 76 | // We do need to get separate patterns for the date & time styles. |
michael@0 | 77 | if (baseDateStyle != UDAT_NONE) { |
michael@0 | 78 | df = createDateInstance((EStyle)baseDateStyle, locale); |
michael@0 | 79 | fDateTimeFormatter=dynamic_cast<SimpleDateFormat *>(df); |
michael@0 | 80 | if (fDateTimeFormatter == NULL) { |
michael@0 | 81 | status = U_UNSUPPORTED_ERROR; |
michael@0 | 82 | return; |
michael@0 | 83 | } |
michael@0 | 84 | fDateTimeFormatter->toPattern(fDatePattern); |
michael@0 | 85 | if (timeStyle != UDAT_NONE) { |
michael@0 | 86 | df = createTimeInstance((EStyle)timeStyle, locale); |
michael@0 | 87 | SimpleDateFormat *sdf = dynamic_cast<SimpleDateFormat *>(df); |
michael@0 | 88 | if (sdf != NULL) { |
michael@0 | 89 | sdf->toPattern(fTimePattern); |
michael@0 | 90 | delete sdf; |
michael@0 | 91 | } |
michael@0 | 92 | } |
michael@0 | 93 | } else { |
michael@0 | 94 | // does not matter whether timeStyle is UDAT_NONE, we need something for fDateTimeFormatter |
michael@0 | 95 | df = createTimeInstance((EStyle)timeStyle, locale); |
michael@0 | 96 | fDateTimeFormatter=dynamic_cast<SimpleDateFormat *>(df); |
michael@0 | 97 | if (fDateTimeFormatter == NULL) { |
michael@0 | 98 | status = U_UNSUPPORTED_ERROR; |
michael@0 | 99 | return; |
michael@0 | 100 | } |
michael@0 | 101 | fDateTimeFormatter->toPattern(fTimePattern); |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | // Initialize the parent fCalendar, so that parse() works correctly. |
michael@0 | 105 | initializeCalendar(NULL, locale, status); |
michael@0 | 106 | loadDates(status); |
michael@0 | 107 | } |
michael@0 | 108 | |
michael@0 | 109 | RelativeDateFormat::~RelativeDateFormat() { |
michael@0 | 110 | delete fDateTimeFormatter; |
michael@0 | 111 | delete fCombinedFormat; |
michael@0 | 112 | uprv_free(fDates); |
michael@0 | 113 | } |
michael@0 | 114 | |
michael@0 | 115 | |
michael@0 | 116 | Format* RelativeDateFormat::clone(void) const { |
michael@0 | 117 | return new RelativeDateFormat(*this); |
michael@0 | 118 | } |
michael@0 | 119 | |
michael@0 | 120 | UBool RelativeDateFormat::operator==(const Format& other) const { |
michael@0 | 121 | if(DateFormat::operator==(other)) { |
michael@0 | 122 | // DateFormat::operator== guarantees following cast is safe |
michael@0 | 123 | RelativeDateFormat* that = (RelativeDateFormat*)&other; |
michael@0 | 124 | return (fDateStyle==that->fDateStyle && |
michael@0 | 125 | fDatePattern==that->fDatePattern && |
michael@0 | 126 | fTimePattern==that->fTimePattern && |
michael@0 | 127 | fLocale==that->fLocale); |
michael@0 | 128 | } |
michael@0 | 129 | return FALSE; |
michael@0 | 130 | } |
michael@0 | 131 | |
michael@0 | 132 | static const UChar APOSTROPHE = (UChar)0x0027; |
michael@0 | 133 | |
michael@0 | 134 | UnicodeString& RelativeDateFormat::format( Calendar& cal, |
michael@0 | 135 | UnicodeString& appendTo, |
michael@0 | 136 | FieldPosition& pos) const { |
michael@0 | 137 | |
michael@0 | 138 | UErrorCode status = U_ZERO_ERROR; |
michael@0 | 139 | UnicodeString relativeDayString; |
michael@0 | 140 | |
michael@0 | 141 | // calculate the difference, in days, between 'cal' and now. |
michael@0 | 142 | int dayDiff = dayDifference(cal, status); |
michael@0 | 143 | |
michael@0 | 144 | // look up string |
michael@0 | 145 | int32_t len = 0; |
michael@0 | 146 | const UChar *theString = getStringForDay(dayDiff, len, status); |
michael@0 | 147 | if(U_SUCCESS(status) && (theString!=NULL)) { |
michael@0 | 148 | // found a relative string |
michael@0 | 149 | relativeDayString.setTo(theString, len); |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | if (fDatePattern.isEmpty()) { |
michael@0 | 153 | fDateTimeFormatter->applyPattern(fTimePattern); |
michael@0 | 154 | fDateTimeFormatter->format(cal,appendTo,pos); |
michael@0 | 155 | } else if (fTimePattern.isEmpty() || fCombinedFormat == NULL) { |
michael@0 | 156 | if (relativeDayString.length() > 0) { |
michael@0 | 157 | appendTo.append(relativeDayString); |
michael@0 | 158 | } else { |
michael@0 | 159 | fDateTimeFormatter->applyPattern(fDatePattern); |
michael@0 | 160 | fDateTimeFormatter->format(cal,appendTo,pos); |
michael@0 | 161 | } |
michael@0 | 162 | } else { |
michael@0 | 163 | UnicodeString datePattern; |
michael@0 | 164 | if (relativeDayString.length() > 0) { |
michael@0 | 165 | // Need to quote the relativeDayString to make it a legal date pattern |
michael@0 | 166 | relativeDayString.findAndReplace(UNICODE_STRING("'", 1), UNICODE_STRING("''", 2)); // double any existing APOSTROPHE |
michael@0 | 167 | relativeDayString.insert(0, APOSTROPHE); // add APOSTROPHE at beginning... |
michael@0 | 168 | relativeDayString.append(APOSTROPHE); // and at end |
michael@0 | 169 | datePattern.setTo(relativeDayString); |
michael@0 | 170 | } else { |
michael@0 | 171 | datePattern.setTo(fDatePattern); |
michael@0 | 172 | } |
michael@0 | 173 | UnicodeString combinedPattern; |
michael@0 | 174 | Formattable timeDatePatterns[] = { fTimePattern, datePattern }; |
michael@0 | 175 | fCombinedFormat->format(timeDatePatterns, 2, combinedPattern, pos, status); // pos is ignored by this |
michael@0 | 176 | fDateTimeFormatter->applyPattern(combinedPattern); |
michael@0 | 177 | fDateTimeFormatter->format(cal,appendTo,pos); |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | return appendTo; |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | |
michael@0 | 184 | |
michael@0 | 185 | UnicodeString& |
michael@0 | 186 | RelativeDateFormat::format(const Formattable& obj, |
michael@0 | 187 | UnicodeString& appendTo, |
michael@0 | 188 | FieldPosition& pos, |
michael@0 | 189 | UErrorCode& status) const |
michael@0 | 190 | { |
michael@0 | 191 | // this is just here to get around the hiding problem |
michael@0 | 192 | // (the previous format() override would hide the version of |
michael@0 | 193 | // format() on DateFormat that this function correspond to, so we |
michael@0 | 194 | // have to redefine it here) |
michael@0 | 195 | return DateFormat::format(obj, appendTo, pos, status); |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | |
michael@0 | 199 | void RelativeDateFormat::parse( const UnicodeString& text, |
michael@0 | 200 | Calendar& cal, |
michael@0 | 201 | ParsePosition& pos) const { |
michael@0 | 202 | |
michael@0 | 203 | int32_t startIndex = pos.getIndex(); |
michael@0 | 204 | if (fDatePattern.isEmpty()) { |
michael@0 | 205 | // no date pattern, try parsing as time |
michael@0 | 206 | fDateTimeFormatter->applyPattern(fTimePattern); |
michael@0 | 207 | fDateTimeFormatter->parse(text,cal,pos); |
michael@0 | 208 | } else if (fTimePattern.isEmpty() || fCombinedFormat == NULL) { |
michael@0 | 209 | // no time pattern or way to combine, try parsing as date |
michael@0 | 210 | // first check whether text matches a relativeDayString |
michael@0 | 211 | UBool matchedRelative = FALSE; |
michael@0 | 212 | for (int n=0; n < fDatesLen && !matchedRelative; n++) { |
michael@0 | 213 | if (fDates[n].string != NULL && |
michael@0 | 214 | text.compare(startIndex, fDates[n].len, fDates[n].string) == 0) { |
michael@0 | 215 | // it matched, handle the relative day string |
michael@0 | 216 | UErrorCode status = U_ZERO_ERROR; |
michael@0 | 217 | matchedRelative = TRUE; |
michael@0 | 218 | |
michael@0 | 219 | // Set the calendar to now+offset |
michael@0 | 220 | cal.setTime(Calendar::getNow(),status); |
michael@0 | 221 | cal.add(UCAL_DATE,fDates[n].offset, status); |
michael@0 | 222 | |
michael@0 | 223 | if(U_FAILURE(status)) { |
michael@0 | 224 | // failure in setting calendar field, set offset to beginning of rel day string |
michael@0 | 225 | pos.setErrorIndex(startIndex); |
michael@0 | 226 | } else { |
michael@0 | 227 | pos.setIndex(startIndex + fDates[n].len); |
michael@0 | 228 | } |
michael@0 | 229 | } |
michael@0 | 230 | } |
michael@0 | 231 | if (!matchedRelative) { |
michael@0 | 232 | // just parse as normal date |
michael@0 | 233 | fDateTimeFormatter->applyPattern(fDatePattern); |
michael@0 | 234 | fDateTimeFormatter->parse(text,cal,pos); |
michael@0 | 235 | } |
michael@0 | 236 | } else { |
michael@0 | 237 | // Here we replace any relativeDayString in text with the equivalent date |
michael@0 | 238 | // formatted per fDatePattern, then parse text normally using the combined pattern. |
michael@0 | 239 | UnicodeString modifiedText(text); |
michael@0 | 240 | FieldPosition fPos; |
michael@0 | 241 | int32_t dateStart = 0, origDateLen = 0, modDateLen = 0; |
michael@0 | 242 | UErrorCode status = U_ZERO_ERROR; |
michael@0 | 243 | for (int n=0; n < fDatesLen; n++) { |
michael@0 | 244 | int32_t relativeStringOffset; |
michael@0 | 245 | if (fDates[n].string != NULL && |
michael@0 | 246 | (relativeStringOffset = modifiedText.indexOf(fDates[n].string, fDates[n].len, startIndex)) >= startIndex) { |
michael@0 | 247 | // it matched, replace the relative date with a real one for parsing |
michael@0 | 248 | UnicodeString dateString; |
michael@0 | 249 | Calendar * tempCal = cal.clone(); |
michael@0 | 250 | |
michael@0 | 251 | // Set the calendar to now+offset |
michael@0 | 252 | tempCal->setTime(Calendar::getNow(),status); |
michael@0 | 253 | tempCal->add(UCAL_DATE,fDates[n].offset, status); |
michael@0 | 254 | if(U_FAILURE(status)) { |
michael@0 | 255 | pos.setErrorIndex(startIndex); |
michael@0 | 256 | delete tempCal; |
michael@0 | 257 | return; |
michael@0 | 258 | } |
michael@0 | 259 | |
michael@0 | 260 | fDateTimeFormatter->applyPattern(fDatePattern); |
michael@0 | 261 | fDateTimeFormatter->format(*tempCal, dateString, fPos); |
michael@0 | 262 | dateStart = relativeStringOffset; |
michael@0 | 263 | origDateLen = fDates[n].len; |
michael@0 | 264 | modDateLen = dateString.length(); |
michael@0 | 265 | modifiedText.replace(dateStart, origDateLen, dateString); |
michael@0 | 266 | delete tempCal; |
michael@0 | 267 | break; |
michael@0 | 268 | } |
michael@0 | 269 | } |
michael@0 | 270 | UnicodeString combinedPattern; |
michael@0 | 271 | Formattable timeDatePatterns[] = { fTimePattern, fDatePattern }; |
michael@0 | 272 | fCombinedFormat->format(timeDatePatterns, 2, combinedPattern, fPos, status); // pos is ignored by this |
michael@0 | 273 | fDateTimeFormatter->applyPattern(combinedPattern); |
michael@0 | 274 | fDateTimeFormatter->parse(modifiedText,cal,pos); |
michael@0 | 275 | |
michael@0 | 276 | // Adjust offsets |
michael@0 | 277 | UBool noError = (pos.getErrorIndex() < 0); |
michael@0 | 278 | int32_t offset = (noError)? pos.getIndex(): pos.getErrorIndex(); |
michael@0 | 279 | if (offset >= dateStart + modDateLen) { |
michael@0 | 280 | // offset at or after the end of the replaced text, |
michael@0 | 281 | // correct by the difference between original and replacement |
michael@0 | 282 | offset -= (modDateLen - origDateLen); |
michael@0 | 283 | } else if (offset >= dateStart) { |
michael@0 | 284 | // offset in the replaced text, set it to the beginning of that text |
michael@0 | 285 | // (i.e. the beginning of the relative day string) |
michael@0 | 286 | offset = dateStart; |
michael@0 | 287 | } |
michael@0 | 288 | if (noError) { |
michael@0 | 289 | pos.setIndex(offset); |
michael@0 | 290 | } else { |
michael@0 | 291 | pos.setErrorIndex(offset); |
michael@0 | 292 | } |
michael@0 | 293 | } |
michael@0 | 294 | } |
michael@0 | 295 | |
michael@0 | 296 | UDate |
michael@0 | 297 | RelativeDateFormat::parse( const UnicodeString& text, |
michael@0 | 298 | ParsePosition& pos) const { |
michael@0 | 299 | // redefined here because the other parse() function hides this function's |
michael@0 | 300 | // cunterpart on DateFormat |
michael@0 | 301 | return DateFormat::parse(text, pos); |
michael@0 | 302 | } |
michael@0 | 303 | |
michael@0 | 304 | UDate |
michael@0 | 305 | RelativeDateFormat::parse(const UnicodeString& text, UErrorCode& status) const |
michael@0 | 306 | { |
michael@0 | 307 | // redefined here because the other parse() function hides this function's |
michael@0 | 308 | // counterpart on DateFormat |
michael@0 | 309 | return DateFormat::parse(text, status); |
michael@0 | 310 | } |
michael@0 | 311 | |
michael@0 | 312 | |
michael@0 | 313 | const UChar *RelativeDateFormat::getStringForDay(int32_t day, int32_t &len, UErrorCode &status) const { |
michael@0 | 314 | if(U_FAILURE(status)) { |
michael@0 | 315 | return NULL; |
michael@0 | 316 | } |
michael@0 | 317 | |
michael@0 | 318 | // Is it outside the resource bundle's range? |
michael@0 | 319 | if(day < fDayMin || day > fDayMax) { |
michael@0 | 320 | return NULL; // don't have it. |
michael@0 | 321 | } |
michael@0 | 322 | |
michael@0 | 323 | // Linear search the held strings |
michael@0 | 324 | for(int n=0;n<fDatesLen;n++) { |
michael@0 | 325 | if(fDates[n].offset == day) { |
michael@0 | 326 | len = fDates[n].len; |
michael@0 | 327 | return fDates[n].string; |
michael@0 | 328 | } |
michael@0 | 329 | } |
michael@0 | 330 | |
michael@0 | 331 | return NULL; // not found. |
michael@0 | 332 | } |
michael@0 | 333 | |
michael@0 | 334 | UnicodeString& |
michael@0 | 335 | RelativeDateFormat::toPattern(UnicodeString& result, UErrorCode& status) const |
michael@0 | 336 | { |
michael@0 | 337 | if (!U_FAILURE(status)) { |
michael@0 | 338 | result.remove(); |
michael@0 | 339 | if (fDatePattern.isEmpty()) { |
michael@0 | 340 | result.setTo(fTimePattern); |
michael@0 | 341 | } else if (fTimePattern.isEmpty() || fCombinedFormat == NULL) { |
michael@0 | 342 | result.setTo(fDatePattern); |
michael@0 | 343 | } else { |
michael@0 | 344 | Formattable timeDatePatterns[] = { fTimePattern, fDatePattern }; |
michael@0 | 345 | FieldPosition pos; |
michael@0 | 346 | fCombinedFormat->format(timeDatePatterns, 2, result, pos, status); |
michael@0 | 347 | } |
michael@0 | 348 | } |
michael@0 | 349 | return result; |
michael@0 | 350 | } |
michael@0 | 351 | |
michael@0 | 352 | UnicodeString& |
michael@0 | 353 | RelativeDateFormat::toPatternDate(UnicodeString& result, UErrorCode& status) const |
michael@0 | 354 | { |
michael@0 | 355 | if (!U_FAILURE(status)) { |
michael@0 | 356 | result.remove(); |
michael@0 | 357 | result.setTo(fDatePattern); |
michael@0 | 358 | } |
michael@0 | 359 | return result; |
michael@0 | 360 | } |
michael@0 | 361 | |
michael@0 | 362 | UnicodeString& |
michael@0 | 363 | RelativeDateFormat::toPatternTime(UnicodeString& result, UErrorCode& status) const |
michael@0 | 364 | { |
michael@0 | 365 | if (!U_FAILURE(status)) { |
michael@0 | 366 | result.remove(); |
michael@0 | 367 | result.setTo(fTimePattern); |
michael@0 | 368 | } |
michael@0 | 369 | return result; |
michael@0 | 370 | } |
michael@0 | 371 | |
michael@0 | 372 | void |
michael@0 | 373 | RelativeDateFormat::applyPatterns(const UnicodeString& datePattern, const UnicodeString& timePattern, UErrorCode &status) |
michael@0 | 374 | { |
michael@0 | 375 | if (!U_FAILURE(status)) { |
michael@0 | 376 | fDatePattern.setTo(datePattern); |
michael@0 | 377 | fTimePattern.setTo(timePattern); |
michael@0 | 378 | } |
michael@0 | 379 | } |
michael@0 | 380 | |
michael@0 | 381 | const DateFormatSymbols* |
michael@0 | 382 | RelativeDateFormat::getDateFormatSymbols() const |
michael@0 | 383 | { |
michael@0 | 384 | return fDateTimeFormatter->getDateFormatSymbols(); |
michael@0 | 385 | } |
michael@0 | 386 | |
michael@0 | 387 | void RelativeDateFormat::loadDates(UErrorCode &status) { |
michael@0 | 388 | CalendarData calData(fLocale, "gregorian", status); |
michael@0 | 389 | |
michael@0 | 390 | UErrorCode tempStatus = status; |
michael@0 | 391 | UResourceBundle *dateTimePatterns = calData.getByKey(DT_DateTimePatternsTag, tempStatus); |
michael@0 | 392 | if(U_SUCCESS(tempStatus)) { |
michael@0 | 393 | int32_t patternsSize = ures_getSize(dateTimePatterns); |
michael@0 | 394 | if (patternsSize > kDateTime) { |
michael@0 | 395 | int32_t resStrLen = 0; |
michael@0 | 396 | |
michael@0 | 397 | int32_t glueIndex = kDateTime; |
michael@0 | 398 | if (patternsSize >= (DateFormat::kDateTimeOffset + DateFormat::kShort + 1)) { |
michael@0 | 399 | // Get proper date time format |
michael@0 | 400 | switch (fDateStyle) { |
michael@0 | 401 | case kFullRelative: |
michael@0 | 402 | case kFull: |
michael@0 | 403 | glueIndex = kDateTimeOffset + kFull; |
michael@0 | 404 | break; |
michael@0 | 405 | case kLongRelative: |
michael@0 | 406 | case kLong: |
michael@0 | 407 | glueIndex = kDateTimeOffset + kLong; |
michael@0 | 408 | break; |
michael@0 | 409 | case kMediumRelative: |
michael@0 | 410 | case kMedium: |
michael@0 | 411 | glueIndex = kDateTimeOffset + kMedium; |
michael@0 | 412 | break; |
michael@0 | 413 | case kShortRelative: |
michael@0 | 414 | case kShort: |
michael@0 | 415 | glueIndex = kDateTimeOffset + kShort; |
michael@0 | 416 | break; |
michael@0 | 417 | default: |
michael@0 | 418 | break; |
michael@0 | 419 | } |
michael@0 | 420 | } |
michael@0 | 421 | |
michael@0 | 422 | const UChar *resStr = ures_getStringByIndex(dateTimePatterns, glueIndex, &resStrLen, &tempStatus); |
michael@0 | 423 | fCombinedFormat = new MessageFormat(UnicodeString(TRUE, resStr, resStrLen), fLocale, tempStatus); |
michael@0 | 424 | } |
michael@0 | 425 | } |
michael@0 | 426 | |
michael@0 | 427 | UResourceBundle *rb = ures_open(NULL, fLocale.getBaseName(), &status); |
michael@0 | 428 | UResourceBundle *sb = ures_getByKeyWithFallback(rb, "fields", NULL, &status); |
michael@0 | 429 | rb = ures_getByKeyWithFallback(sb, "day", rb, &status); |
michael@0 | 430 | sb = ures_getByKeyWithFallback(rb, "relative", sb, &status); |
michael@0 | 431 | ures_close(rb); |
michael@0 | 432 | // set up min/max |
michael@0 | 433 | fDayMin=-1; |
michael@0 | 434 | fDayMax=1; |
michael@0 | 435 | |
michael@0 | 436 | if(U_FAILURE(status)) { |
michael@0 | 437 | fDatesLen=0; |
michael@0 | 438 | ures_close(sb); |
michael@0 | 439 | return; |
michael@0 | 440 | } |
michael@0 | 441 | |
michael@0 | 442 | fDatesLen = ures_getSize(sb); |
michael@0 | 443 | fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*fDatesLen); |
michael@0 | 444 | |
michael@0 | 445 | // Load in each item into the array... |
michael@0 | 446 | int n = 0; |
michael@0 | 447 | |
michael@0 | 448 | UResourceBundle *subString = NULL; |
michael@0 | 449 | |
michael@0 | 450 | while(ures_hasNext(sb) && U_SUCCESS(status)) { // iterate over items |
michael@0 | 451 | subString = ures_getNextResource(sb, subString, &status); |
michael@0 | 452 | |
michael@0 | 453 | if(U_FAILURE(status) || (subString==NULL)) break; |
michael@0 | 454 | |
michael@0 | 455 | // key = offset # |
michael@0 | 456 | const char *key = ures_getKey(subString); |
michael@0 | 457 | |
michael@0 | 458 | // load the string and length |
michael@0 | 459 | int32_t aLen; |
michael@0 | 460 | const UChar* aString = ures_getString(subString, &aLen, &status); |
michael@0 | 461 | |
michael@0 | 462 | if(U_FAILURE(status) || aString == NULL) break; |
michael@0 | 463 | |
michael@0 | 464 | // calculate the offset |
michael@0 | 465 | int32_t offset = atoi(key); |
michael@0 | 466 | |
michael@0 | 467 | // set min/max |
michael@0 | 468 | if(offset < fDayMin) { |
michael@0 | 469 | fDayMin = offset; |
michael@0 | 470 | } |
michael@0 | 471 | if(offset > fDayMax) { |
michael@0 | 472 | fDayMax = offset; |
michael@0 | 473 | } |
michael@0 | 474 | |
michael@0 | 475 | // copy the string pointer |
michael@0 | 476 | fDates[n].offset = offset; |
michael@0 | 477 | fDates[n].string = aString; |
michael@0 | 478 | fDates[n].len = aLen; |
michael@0 | 479 | |
michael@0 | 480 | n++; |
michael@0 | 481 | } |
michael@0 | 482 | ures_close(subString); |
michael@0 | 483 | ures_close(sb); |
michael@0 | 484 | |
michael@0 | 485 | // the fDates[] array could be sorted here, for direct access. |
michael@0 | 486 | } |
michael@0 | 487 | |
michael@0 | 488 | |
michael@0 | 489 | // this should to be in DateFormat, instead it was copied from SimpleDateFormat. |
michael@0 | 490 | |
michael@0 | 491 | Calendar* |
michael@0 | 492 | RelativeDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status) |
michael@0 | 493 | { |
michael@0 | 494 | if(!U_FAILURE(status)) { |
michael@0 | 495 | fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status); |
michael@0 | 496 | } |
michael@0 | 497 | if (U_SUCCESS(status) && fCalendar == NULL) { |
michael@0 | 498 | status = U_MEMORY_ALLOCATION_ERROR; |
michael@0 | 499 | } |
michael@0 | 500 | return fCalendar; |
michael@0 | 501 | } |
michael@0 | 502 | |
michael@0 | 503 | int32_t RelativeDateFormat::dayDifference(Calendar &cal, UErrorCode &status) { |
michael@0 | 504 | if(U_FAILURE(status)) { |
michael@0 | 505 | return 0; |
michael@0 | 506 | } |
michael@0 | 507 | // TODO: Cache the nowCal to avoid heap allocs? Would be difficult, don't know the calendar type |
michael@0 | 508 | Calendar *nowCal = cal.clone(); |
michael@0 | 509 | nowCal->setTime(Calendar::getNow(), status); |
michael@0 | 510 | |
michael@0 | 511 | // For the day difference, we are interested in the difference in the (modified) julian day number |
michael@0 | 512 | // which is midnight to midnight. Using fieldDifference() is NOT correct here, because |
michael@0 | 513 | // 6pm Jan 4th to 10am Jan 5th should be considered "tomorrow". |
michael@0 | 514 | int32_t dayDiff = cal.get(UCAL_JULIAN_DAY, status) - nowCal->get(UCAL_JULIAN_DAY, status); |
michael@0 | 515 | |
michael@0 | 516 | delete nowCal; |
michael@0 | 517 | return dayDiff; |
michael@0 | 518 | } |
michael@0 | 519 | |
michael@0 | 520 | U_NAMESPACE_END |
michael@0 | 521 | |
michael@0 | 522 | #endif |
michael@0 | 523 |