/* ******************************************************************************* * Copyright (C) 2007, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING //#define DEBUG_RELDTFMT #include #include #include "reldtfmt.h" #include "unicode/msgfmt.h" #include "gregoimp.h" // for CalendarData #include "cmemory.h" U_NAMESPACE_BEGIN /** * An array of URelativeString structs is used to store the resource data loaded out of the bundle. */ struct URelativeString { int32_t offset; /** offset of this item, such as, the relative date **/ int32_t len; /** length of the string **/ const UChar* string; /** string, or NULL if not set **/ }; UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RelativeDateFormat) RelativeDateFormat::RelativeDateFormat(const RelativeDateFormat& other) : DateFormat(other), fDateFormat(NULL), fTimeFormat(NULL), fCombinedFormat(NULL), fDateStyle(other.fDateStyle), fTimeStyle(other.fTimeStyle), fLocale(other.fLocale), fDayMin(other.fDayMin), fDayMax(other.fDayMax), fDatesLen(other.fDatesLen), fDates(NULL) { if(other.fDateFormat != NULL) { fDateFormat = (DateFormat*)other.fDateFormat->clone(); } else { fDateFormat = NULL; } if (fDatesLen > 0) { fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*fDatesLen); uprv_memcpy(fDates, other.fDates, sizeof(fDates[0])*fDatesLen); } //fCalendar = other.fCalendar->clone(); /* if(other.fTimeFormat != NULL) { fTimeFormat = (DateFormat*)other.fTimeFormat->clone(); } else { fTimeFormat = NULL; } */ } RelativeDateFormat::RelativeDateFormat( UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, const Locale& locale, UErrorCode& status) : DateFormat(), fDateFormat(NULL), fTimeFormat(NULL), fCombinedFormat(NULL), fDateStyle(dateStyle), fTimeStyle(timeStyle), fLocale(locale), fDatesLen(0), fDates(NULL) { if(U_FAILURE(status) ) { return; } if(fDateStyle != UDAT_NONE) { EStyle newStyle = (EStyle)(fDateStyle & ~UDAT_RELATIVE); // Create a DateFormat in the non-relative style requested. fDateFormat = createDateInstance(newStyle, locale); } if(fTimeStyle != UDAT_NONE) { // don't support time style, for now status = U_ILLEGAL_ARGUMENT_ERROR; return; } // Initialize the parent fCalendar, so that parse() works correctly. initializeCalendar(NULL, locale, status); loadDates(status); } RelativeDateFormat::~RelativeDateFormat() { delete fDateFormat; delete fTimeFormat; delete fCombinedFormat; uprv_free(fDates); } Format* RelativeDateFormat::clone(void) const { return new RelativeDateFormat(*this); } UBool RelativeDateFormat::operator==(const Format& other) const { if(DateFormat::operator==(other)) { // DateFormat::operator== guarantees following cast is safe RelativeDateFormat* that = (RelativeDateFormat*)&other; return (fDateStyle==that->fDateStyle && fTimeStyle==that->fTimeStyle && fLocale==that->fLocale); } return FALSE; } UnicodeString& RelativeDateFormat::format( Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const { UErrorCode status = U_ZERO_ERROR; // calculate the difference, in days, between 'cal' and now. int dayDiff = dayDifference(cal, status); // look up string int32_t len; const UChar *theString = getStringForDay(dayDiff, len, status); if(U_FAILURE(status) || (theString==NULL)) { // didn't find it. Fall through to the fDateFormat if(fDateFormat != NULL) { return fDateFormat->format(cal,appendTo,pos); } else { return appendTo; // no op } } else { // found a relative string return appendTo.append(theString, len); } } UnicodeString& RelativeDateFormat::format(const Formattable& obj, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const { // this is just here to get around the hiding problem // (the previous format() override would hide the version of // format() on DateFormat that this function correspond to, so we // have to redefine it here) return DateFormat::format(obj, appendTo, pos, status); } void RelativeDateFormat::parse( const UnicodeString& text, Calendar& cal, ParsePosition& pos) const { // Can the fDateFormat parse it? if(fDateFormat != NULL) { ParsePosition aPos(pos); fDateFormat->parse(text,cal,aPos); if((aPos.getIndex() != pos.getIndex()) && (aPos.getErrorIndex()==-1)) { pos=aPos; // copy the sub parse return; // parsed subfmt OK } } // Linear search the relative strings for(int n=0;n fDayMax) { return NULL; // don't have it. } // Linear search the held strings for(int n=0;n fDayMax) { fDayMax = offset; } // copy the string pointer fDates[n].offset = offset; fDates[n].string = aString; fDates[n].len = aLen; n++; } ures_close(subString); // the fDates[] array could be sorted here, for direct access. } // this should to be in DateFormat, instead it was copied from SimpleDateFormat. Calendar* RelativeDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status) { if(!U_FAILURE(status)) { fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status); } if (U_SUCCESS(status) && fCalendar == NULL) { status = U_MEMORY_ALLOCATION_ERROR; } return fCalendar; } int32_t RelativeDateFormat::dayDifference(Calendar &cal, UErrorCode &status) { if(U_FAILURE(status)) { return 0; } // TODO: Cache the nowCal to avoid heap allocs? Calendar *nowCal = cal.clone(); nowCal->setTime(Calendar::getNow(), status); int32_t dayDiff = nowCal->fieldDifference(cal.getTime(status), Calendar::DATE, status); delete nowCal; return dayDiff; } U_NAMESPACE_END #endif