michael@0: /* michael@0: ******************************************************************************* michael@0: * Copyright (C) 1997-2013, International Business Machines Corporation and * michael@0: * others. All Rights Reserved. * michael@0: ******************************************************************************* michael@0: * michael@0: * File DATEFMT.CPP michael@0: * michael@0: * Modification History: michael@0: * michael@0: * Date Name Description michael@0: * 02/19/97 aliu Converted from java. michael@0: * 03/31/97 aliu Modified extensively to work with 50 locales. michael@0: * 04/01/97 aliu Added support for centuries. michael@0: * 08/12/97 aliu Fixed operator== to use Calendar::equivalentTo. michael@0: * 07/20/98 stephen Changed ParsePosition initialization michael@0: ******************************************************************************** michael@0: */ michael@0: michael@0: #include "unicode/utypes.h" michael@0: michael@0: #if !UCONFIG_NO_FORMATTING michael@0: michael@0: #include "unicode/ures.h" michael@0: #include "unicode/datefmt.h" michael@0: #include "unicode/smpdtfmt.h" michael@0: #include "unicode/dtptngen.h" michael@0: #include "reldtfmt.h" michael@0: michael@0: #include "cstring.h" michael@0: #include "windtfmt.h" michael@0: michael@0: #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL) michael@0: #include michael@0: #endif michael@0: michael@0: // ***************************************************************************** michael@0: // class DateFormat michael@0: // ***************************************************************************** michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: DateFormat::DateFormat() michael@0: : fCalendar(0), michael@0: fNumberFormat(0) michael@0: { michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: DateFormat::DateFormat(const DateFormat& other) michael@0: : Format(other), michael@0: fCalendar(0), michael@0: fNumberFormat(0) michael@0: { michael@0: *this = other; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: DateFormat& DateFormat::operator=(const DateFormat& other) michael@0: { michael@0: if (this != &other) michael@0: { michael@0: delete fCalendar; michael@0: delete fNumberFormat; michael@0: if(other.fCalendar) { michael@0: fCalendar = other.fCalendar->clone(); michael@0: } else { michael@0: fCalendar = NULL; michael@0: } michael@0: if(other.fNumberFormat) { michael@0: fNumberFormat = (NumberFormat*)other.fNumberFormat->clone(); michael@0: } else { michael@0: fNumberFormat = NULL; michael@0: } michael@0: fBoolFlags = other.fBoolFlags; michael@0: } michael@0: return *this; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: DateFormat::~DateFormat() michael@0: { michael@0: delete fCalendar; michael@0: delete fNumberFormat; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: UBool michael@0: DateFormat::operator==(const Format& other) const michael@0: { michael@0: // This protected comparison operator should only be called by subclasses michael@0: // which have confirmed that the other object being compared against is michael@0: // an instance of a sublcass of DateFormat. THIS IS IMPORTANT. michael@0: michael@0: // Format::operator== guarantees that this cast is safe michael@0: DateFormat* fmt = (DateFormat*)&other; michael@0: michael@0: return (this == fmt) || michael@0: (Format::operator==(other) && michael@0: fCalendar&&(fCalendar->isEquivalentTo(*fmt->fCalendar)) && michael@0: (fNumberFormat && *fNumberFormat == *fmt->fNumberFormat)); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: UnicodeString& michael@0: DateFormat::format(const Formattable& obj, michael@0: UnicodeString& appendTo, michael@0: FieldPosition& fieldPosition, michael@0: UErrorCode& status) const michael@0: { michael@0: if (U_FAILURE(status)) return appendTo; michael@0: michael@0: // if the type of the Formattable is double or long, treat it as if it were a Date michael@0: UDate date = 0; michael@0: switch (obj.getType()) michael@0: { michael@0: case Formattable::kDate: michael@0: date = obj.getDate(); michael@0: break; michael@0: case Formattable::kDouble: michael@0: date = (UDate)obj.getDouble(); michael@0: break; michael@0: case Formattable::kLong: michael@0: date = (UDate)obj.getLong(); michael@0: break; michael@0: default: michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return appendTo; michael@0: } michael@0: michael@0: // Is this right? michael@0: //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex()) michael@0: // status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: michael@0: return format(date, appendTo, fieldPosition); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: UnicodeString& michael@0: DateFormat::format(const Formattable& obj, michael@0: UnicodeString& appendTo, michael@0: FieldPositionIterator* posIter, michael@0: UErrorCode& status) const michael@0: { michael@0: if (U_FAILURE(status)) return appendTo; michael@0: michael@0: // if the type of the Formattable is double or long, treat it as if it were a Date michael@0: UDate date = 0; michael@0: switch (obj.getType()) michael@0: { michael@0: case Formattable::kDate: michael@0: date = obj.getDate(); michael@0: break; michael@0: case Formattable::kDouble: michael@0: date = (UDate)obj.getDouble(); michael@0: break; michael@0: case Formattable::kLong: michael@0: date = (UDate)obj.getLong(); michael@0: break; michael@0: default: michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: return appendTo; michael@0: } michael@0: michael@0: // Is this right? michael@0: //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex()) michael@0: // status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: michael@0: return format(date, appendTo, posIter, status); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: // Default implementation for backwards compatibility, subclasses should implement. michael@0: UnicodeString& michael@0: DateFormat::format(Calendar& /* unused cal */, michael@0: UnicodeString& appendTo, michael@0: FieldPositionIterator* /* unused posIter */, michael@0: UErrorCode& status) const { michael@0: if (U_SUCCESS(status)) { michael@0: status = U_UNSUPPORTED_ERROR; michael@0: } michael@0: return appendTo; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: UnicodeString& michael@0: DateFormat::format(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const { michael@0: if (fCalendar != NULL) { michael@0: // Use a clone of our calendar instance michael@0: Calendar* calClone = fCalendar->clone(); michael@0: if (calClone != NULL) { michael@0: UErrorCode ec = U_ZERO_ERROR; michael@0: calClone->setTime(date, ec); michael@0: if (U_SUCCESS(ec)) { michael@0: format(*calClone, appendTo, fieldPosition); michael@0: } michael@0: delete calClone; michael@0: } michael@0: } michael@0: return appendTo; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: UnicodeString& michael@0: DateFormat::format(UDate date, UnicodeString& appendTo, FieldPositionIterator* posIter, michael@0: UErrorCode& status) const { michael@0: if (fCalendar != NULL) { michael@0: Calendar* calClone = fCalendar->clone(); michael@0: if (calClone != NULL) { michael@0: calClone->setTime(date, status); michael@0: if (U_SUCCESS(status)) { michael@0: format(*calClone, appendTo, posIter, status); michael@0: } michael@0: delete calClone; michael@0: } michael@0: } michael@0: return appendTo; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: UnicodeString& michael@0: DateFormat::format(UDate date, UnicodeString& appendTo) const michael@0: { michael@0: // Note that any error information is just lost. That's okay michael@0: // for this convenience method. michael@0: FieldPosition fpos(0); michael@0: return format(date, appendTo, fpos); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: UDate michael@0: DateFormat::parse(const UnicodeString& text, michael@0: ParsePosition& pos) const michael@0: { michael@0: UDate d = 0; // Error return UDate is 0 (the epoch) michael@0: if (fCalendar != NULL) { michael@0: Calendar* calClone = fCalendar->clone(); michael@0: if (calClone != NULL) { michael@0: int32_t start = pos.getIndex(); michael@0: calClone->clear(); michael@0: parse(text, *calClone, pos); michael@0: if (pos.getIndex() != start) { michael@0: UErrorCode ec = U_ZERO_ERROR; michael@0: d = calClone->getTime(ec); michael@0: if (U_FAILURE(ec)) { michael@0: // We arrive here if fCalendar => calClone is non-lenient and michael@0: // there is an out-of-range field. We don't know which field michael@0: // was illegal so we set the error index to the start. michael@0: pos.setIndex(start); michael@0: pos.setErrorIndex(start); michael@0: d = 0; michael@0: } michael@0: } michael@0: delete calClone; michael@0: } michael@0: } michael@0: return d; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: UDate michael@0: DateFormat::parse(const UnicodeString& text, michael@0: UErrorCode& status) const michael@0: { michael@0: if (U_FAILURE(status)) return 0; michael@0: michael@0: ParsePosition pos(0); michael@0: UDate result = parse(text, pos); michael@0: if (pos.getIndex() == 0) { michael@0: #if defined (U_DEBUG_CAL) michael@0: fprintf(stderr, "%s:%d - - failed to parse - err index %d\n" michael@0: , __FILE__, __LINE__, pos.getErrorIndex() ); michael@0: #endif michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: void michael@0: DateFormat::parseObject(const UnicodeString& source, michael@0: Formattable& result, michael@0: ParsePosition& pos) const michael@0: { michael@0: result.setDate(parse(source, pos)); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: DateFormat* U_EXPORT2 michael@0: DateFormat::createTimeInstance(DateFormat::EStyle style, michael@0: const Locale& aLocale) michael@0: { michael@0: return create(style, kNone, aLocale); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: DateFormat* U_EXPORT2 michael@0: DateFormat::createDateInstance(DateFormat::EStyle style, michael@0: const Locale& aLocale) michael@0: { michael@0: // +4 to set the correct index for getting data out of michael@0: // LocaleElements. michael@0: if(style != kNone) michael@0: { michael@0: style = (EStyle) (style + kDateOffset); michael@0: } michael@0: return create(kNone, (EStyle) (style), aLocale); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: DateFormat* U_EXPORT2 michael@0: DateFormat::createDateTimeInstance(EStyle dateStyle, michael@0: EStyle timeStyle, michael@0: const Locale& aLocale) michael@0: { michael@0: if(dateStyle != kNone) michael@0: { michael@0: dateStyle = (EStyle) (dateStyle + kDateOffset); michael@0: } michael@0: return create(timeStyle, dateStyle, aLocale); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: DateFormat* U_EXPORT2 michael@0: DateFormat::createInstance() michael@0: { michael@0: return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault()); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: DateFormat* U_EXPORT2 michael@0: DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale) michael@0: { michael@0: UErrorCode status = U_ZERO_ERROR; michael@0: #if U_PLATFORM_HAS_WIN32_API michael@0: char buffer[8]; michael@0: int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status); michael@0: michael@0: // if the locale has "@compat=host", create a host-specific DateFormat... michael@0: if (count > 0 && uprv_strcmp(buffer, "host") == 0) { michael@0: Win32DateFormat *f = new Win32DateFormat(timeStyle, dateStyle, locale, status); michael@0: michael@0: if (U_SUCCESS(status)) { michael@0: return f; michael@0: } michael@0: michael@0: delete f; michael@0: } michael@0: #endif michael@0: michael@0: // is it relative? michael@0: if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=kNone)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) { michael@0: RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status); michael@0: if(U_SUCCESS(status)) return r; michael@0: delete r; michael@0: status = U_ZERO_ERROR; michael@0: } michael@0: michael@0: // Try to create a SimpleDateFormat of the desired style. michael@0: SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status); michael@0: if (U_SUCCESS(status)) return f; michael@0: delete f; michael@0: michael@0: // If that fails, try to create a format using the default pattern and michael@0: // the DateFormatSymbols for this locale. michael@0: status = U_ZERO_ERROR; michael@0: f = new SimpleDateFormat(locale, status); michael@0: if (U_SUCCESS(status)) return f; michael@0: delete f; michael@0: michael@0: // This should never really happen, because the preceding constructor michael@0: // should always succeed. If the resource data is unavailable, a last michael@0: // resort object should be returned. michael@0: return 0; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: const Locale* U_EXPORT2 michael@0: DateFormat::getAvailableLocales(int32_t& count) michael@0: { michael@0: // Get the list of installed locales. michael@0: // Even if root has the correct date format for this locale, michael@0: // it's still a valid locale (we don't worry about data fallbacks). michael@0: return Locale::getAvailableLocales(count); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: void michael@0: DateFormat::adoptCalendar(Calendar* newCalendar) michael@0: { michael@0: delete fCalendar; michael@0: fCalendar = newCalendar; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: void michael@0: DateFormat::setCalendar(const Calendar& newCalendar) michael@0: { michael@0: Calendar* newCalClone = newCalendar.clone(); michael@0: if (newCalClone != NULL) { michael@0: adoptCalendar(newCalClone); michael@0: } michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: const Calendar* michael@0: DateFormat::getCalendar() const michael@0: { michael@0: return fCalendar; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: void michael@0: DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat) michael@0: { michael@0: delete fNumberFormat; michael@0: fNumberFormat = newNumberFormat; michael@0: newNumberFormat->setParseIntegerOnly(TRUE); michael@0: } michael@0: //---------------------------------------------------------------------- michael@0: michael@0: void michael@0: DateFormat::setNumberFormat(const NumberFormat& newNumberFormat) michael@0: { michael@0: NumberFormat* newNumFmtClone = (NumberFormat*)newNumberFormat.clone(); michael@0: if (newNumFmtClone != NULL) { michael@0: adoptNumberFormat(newNumFmtClone); michael@0: } michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: const NumberFormat* michael@0: DateFormat::getNumberFormat() const michael@0: { michael@0: return fNumberFormat; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: void michael@0: DateFormat::adoptTimeZone(TimeZone* zone) michael@0: { michael@0: if (fCalendar != NULL) { michael@0: fCalendar->adoptTimeZone(zone); michael@0: } michael@0: } michael@0: //---------------------------------------------------------------------- michael@0: michael@0: void michael@0: DateFormat::setTimeZone(const TimeZone& zone) michael@0: { michael@0: if (fCalendar != NULL) { michael@0: fCalendar->setTimeZone(zone); michael@0: } michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: const TimeZone& michael@0: DateFormat::getTimeZone() const michael@0: { michael@0: if (fCalendar != NULL) { michael@0: return fCalendar->getTimeZone(); michael@0: } michael@0: // If calendar doesn't exists, create default timezone. michael@0: // fCalendar is rarely null michael@0: return *(TimeZone::createDefault()); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: void michael@0: DateFormat::setLenient(UBool lenient) michael@0: { michael@0: if (fCalendar != NULL) { michael@0: fCalendar->setLenient(lenient); michael@0: } michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: UBool michael@0: DateFormat::isLenient() const michael@0: { michael@0: if (fCalendar != NULL) { michael@0: return fCalendar->isLenient(); michael@0: } michael@0: // fCalendar is rarely null michael@0: return FALSE; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: DateFormat& michael@0: DateFormat::setBooleanAttribute(UDateFormatBooleanAttribute attr, michael@0: UBool newValue, michael@0: UErrorCode &status) { michael@0: if(!fBoolFlags.isValidValue(newValue)) { michael@0: status = U_ILLEGAL_ARGUMENT_ERROR; michael@0: } else { michael@0: fBoolFlags.set(attr, newValue); michael@0: } michael@0: michael@0: return *this; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: UBool michael@0: DateFormat::getBooleanAttribute(UDateFormatBooleanAttribute attr, UErrorCode &/*status*/) const { michael@0: michael@0: return fBoolFlags.get(attr); michael@0: } michael@0: michael@0: U_NAMESPACE_END michael@0: michael@0: #endif /* #if !UCONFIG_NO_FORMATTING */ michael@0: michael@0: //eof