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