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