/* ******************************************************************************* * Copyright (C) 1997-2001, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * * File CALENDAR.CPP * * Modification History: * * Date Name Description * 02/03/97 clhuang Creation. * 04/22/97 aliu Cleaned up, fixed memory leak, made * setWeekCountData() more robust. * Moved platform code to TPlatformUtilities. * 05/01/97 aliu Made equals(), before(), after() arguments const. * 05/20/97 aliu Changed logic of when to compute fields and time * to fix bugs. * 08/12/97 aliu Added equivalentTo. Misc other fixes. * 07/28/98 stephen Sync up with JDK 1.2 * 09/02/98 stephen Sync with JDK 1.2 8/31 build (getActualMin/Max) * 03/17/99 stephen Changed adoptTimeZone() - now fAreFieldsSet is * set to FALSE to force update of time. ******************************************************************************* */ #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING #include "unicode/resbund.h" #include "unicode/gregocal.h" #include "buddhcal.h" #include "japancal.h" #include "unicode/calendar.h" #include "cpputils.h" #include "iculserv.h" #include "ucln_in.h" #include "cstring.h" U_NAMESPACE_BEGIN // ------------------------------------------ // // Registration // //------------------------------------------- //#define U_DEBUG_CALSVC 1 // #ifdef U_DEBUG_CALSVC #include #endif static ICULocaleService* gService = NULL; // ------------------------------------- /** * a Calendar Factory which creates the "basic" calendar types, that is, those * shipped with ICU. */ class BasicCalendarFactory : public LocaleKeyFactory { public: /** * @param calendarType static const string (caller owns storage - will be aliased) to calendar type */ BasicCalendarFactory(const char *calendarType) : LocaleKeyFactory(LocaleKeyFactory::INVISIBLE), fType(calendarType), fID(calendarType,"") { } virtual ~BasicCalendarFactory() {} protected: virtual UBool isSupportedID( const UnicodeString& id, UErrorCode& /* status */) const { return (id == fID); } virtual void updateVisibleIDs(Hashtable& result, UErrorCode& status) const { if (U_SUCCESS(status)) { const UnicodeString& id = fID; result.put(id, (void*)this, status); } } virtual UObject* create(const ICUServiceKey& key, const ICUService* /*service*/, UErrorCode& status) const { const LocaleKey& lkey = (LocaleKey&)key; Locale curLoc; // current locale Locale canLoc; // Canonical locale lkey.currentLocale(curLoc); lkey.canonicalLocale(canLoc); UnicodeString str; key.currentID(str); #ifdef U_DEBUG_CALSVC fprintf(stderr, "BasicCalendarFactory[%s] - cur %s, can %s\n", fType, (const char*)curLoc.getName(), (const char*)canLoc.getName()); #endif if(str != fID) { // Do we handle this type? #ifdef U_DEBUG_CALSVC fprintf(stderr, "BasicCalendarFactory[%s] - not handling %s.\n", fType, (const char*) curLoc.getName() ); #endif return NULL; } #ifdef U_DEBUG_CALSVC fprintf(stderr, "BasicCalendarFactory %p: creating %s type for %s\n", this, fType, (const char*)curLoc.getName()); fflush(stderr); #endif if(!fType || !*fType || !uprv_strcmp(fType,"gregorian")) { // Gregorian (default) return new GregorianCalendar(canLoc, status); } else if(!uprv_strcmp(fType, "japanese")) { return new JapaneseCalendar(canLoc, status); } else if(!uprv_strcmp(fType, "buddhist")) { return new BuddhistCalendar(canLoc, status); } else { status = U_UNSUPPORTED_ERROR; return NULL; } } private: const char *fType; const UnicodeString fID; }; /** * A factory which looks up the DefaultCalendar resource to determine which class of calendar to use */ class DefaultCalendarFactory : public ICUResourceBundleFactory { public: DefaultCalendarFactory(): ICUResourceBundleFactory() { } protected: virtual UObject* create(const ICUServiceKey& key, const ICUService* /*service*/, UErrorCode& status) const { LocaleKey &lkey = (LocaleKey&)key; Locale loc; lkey.currentLocale(loc); #ifdef U_DEBUG_CALSVC fprintf(stderr, "DefaultCalendar factory %p: looking up %s\n", this, (const char*)loc.getName()); #endif UErrorCode resStatus = U_ZERO_ERROR; UResourceBundle *rb = ures_open(NULL, (const char*)loc.getName(), &resStatus); #ifdef U_DEBUG_CALSVC fprintf(stderr, "... ures_open -> %s\n", u_errorName(resStatus)); #endif if(U_FAILURE(resStatus) || (resStatus == U_USING_DEFAULT_WARNING) || (resStatus==U_USING_FALLBACK_WARNING)) { //Don't want to handle fallback data. ures_close(rb); status = resStatus; // propagate err back to caller #ifdef U_DEBUG_CALSVC fprintf(stderr, "... exitting (NULL)\n"); #endif return NULL; } int32_t len = 0; UnicodeString myString = ures_getUnicodeStringByKey(rb, Calendar::kDefaultCalendar, &status); #ifdef U_DEBUG_CALSVC UErrorCode debugStatus = U_ZERO_ERROR; const UChar *defCal = ures_getStringByKey(rb, Calendar::kDefaultCalendar, &len, &debugStatus); fprintf(stderr, "... get string(%d) -> %s\n", len, u_errorName(debugStatus)); #endif ures_close(rb); if(U_FAILURE(status)) { return NULL; } #ifdef U_DEBUG_CALSVC { char defCalStr[200]; if(len > 199) { len = 199; } u_UCharsToChars(defCal, defCalStr, len); defCalStr[len]=0; fprintf(stderr, "DefaultCalendarFactory: looked up %s, got DefaultCalendar= %s\n", (const char*)loc.getName(), defCalStr); } #endif return myString.clone(); } }; // ------------------------------------- class CalendarService : public ICULocaleService { public: CalendarService() : ICULocaleService("Calendar") { UErrorCode status = U_ZERO_ERROR; registerFactory(new DefaultCalendarFactory(), status); } virtual UObject* cloneInstance(UObject* instance) const { if(instance->getDynamicClassID() == UnicodeString::getStaticClassID()) { return ((UnicodeString*)instance)->clone(); } else { #ifdef U_DEBUG_CALSVC_F UErrorCode status2 = U_ZERO_ERROR; fprintf(stderr, "Cloning a %s calendar with tz=%ld\n", ((Calendar*)instance)->getType(), ((Calendar*)instance)->get(UCAL_ZONE_OFFSET, status2)); #endif return ((Calendar*)instance)->clone(); } } virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /*actualID*/, UErrorCode& status) const { LocaleKey& lkey = (LocaleKey&)key; //int32_t kind = lkey.kind(); Locale loc; lkey.canonicalLocale(loc); #ifdef U_DEBUG_CALSVC Locale loc2; lkey.currentLocale(loc2); fprintf(stderr, "CalSvc:handleDefault for currentLoc %s, canloc %s\n", (const char*)loc.getName(), (const char*)loc2.getName()); #endif Calendar *nc = new GregorianCalendar(loc, status); #ifdef U_DEBUG_CALSVC UErrorCode status2 = U_ZERO_ERROR; fprintf(stderr, "New default calendar has tz=%d\n", ((Calendar*)nc)->get(UCAL_ZONE_OFFSET, status2)); #endif return nc; } virtual UBool isDefault() const { return countFactories() == 1; } }; // ------------------------------------- static UMTX gnLock = 0; static ICULocaleService* getService(void) { UBool needInit; { Mutex mutex(&gnLock); needInit = (UBool)(gService == NULL); } if (needInit) { UErrorCode status = U_ZERO_ERROR; #ifdef U_DEBUG_CALSVC fprintf(stderr, "Spinning up Calendar Service\n"); #endif ICULocaleService * newservice = new CalendarService(); #ifdef U_DEBUG_CALSVC fprintf(stderr, "Registering classes..\n"); #endif // Register all basic instances. newservice->registerFactory(new BasicCalendarFactory("japanese"),status); newservice->registerFactory(new BasicCalendarFactory("buddhist"),status); newservice->registerFactory(new BasicCalendarFactory("gregorian"),status); #ifdef U_DEBUG_CALSVC fprintf(stderr, "Done..\n"); #endif if(U_FAILURE(status)) { #ifdef U_DEBUG_CALSVC fprintf(stderr, "err (%s) registering classes, deleting service.....\n", u_errorName(status)); #endif delete newservice; newservice = NULL; } if (newservice) { Mutex mutex(&gnLock); if (gService == NULL) { gService = newservice; newservice = NULL; } } if (newservice) { delete newservice; } ucln_i18n_registerCleanup(); } return gService; } // ------------------------------------- // Resource bundle tags read by this class const char Calendar::kDateTimeElements[] = "DateTimeElements"; const char Calendar::kDefaultCalendar[] = "DefaultCalendar"; // Data flow in Calendar // --------------------- // The current time is represented in two ways by Calendar: as UTC // milliseconds from the epoch start (1 January 1970 0:00 UTC), and as local // fields such as MONTH, HOUR, AM_PM, etc. It is possible to compute the // millis from the fields, and vice versa. The data needed to do this // conversion is encapsulated by a TimeZone object owned by the Calendar. // The data provided by the TimeZone object may also be overridden if the // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class // keeps track of what information was most recently set by the caller, and // uses that to compute any other information as needed. // If the user sets the fields using set(), the data flow is as follows. // This is implemented by the Calendar subclass's computeTime() method. // During this process, certain fields may be ignored. The disambiguation // algorithm for resolving which fields to pay attention to is described // above. // local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.) // | // | Using Calendar-specific algorithm // V // local standard millis // | // | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET // V // UTC millis (in time data member) // If the user sets the UTC millis using setTime(), the data flow is as // follows. This is implemented by the Calendar subclass's computeFields() // method. // UTC millis (in time data member) // | // | Using TimeZone getOffset() // V // local standard millis // | // | Using Calendar-specific algorithm // V // local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.) // In general, a round trip from fields, through local and UTC millis, and // back out to fields is made when necessary. This is implemented by the // complete() method. Resolving a partial set of fields into a UTC millis // value allows all remaining fields to be generated from that value. If // the Calendar is lenient, the fields are also renormalized to standard // ranges when they are regenerated. // ------------------------------------- Calendar::Calendar(UErrorCode& success) : UObject(), fIsTimeSet(FALSE), fAreFieldsSet(FALSE), fAreAllFieldsSet(FALSE), fNextStamp(kMinimumUserStamp), fTime(0), fLenient(TRUE), fZone(0) { clear(); fZone = TimeZone::createDefault(); setWeekCountData(Locale::getDefault(), success); } // ------------------------------------- Calendar::Calendar(TimeZone* zone, const Locale& aLocale, UErrorCode& success) : UObject(), fIsTimeSet(FALSE), fAreFieldsSet(FALSE), fAreAllFieldsSet(FALSE), fNextStamp(kMinimumUserStamp), fTime(0), fLenient(TRUE), fZone(0) { if(zone == 0) { success = U_ILLEGAL_ARGUMENT_ERROR; return; } clear(); fZone = zone; setWeekCountData(aLocale, success); } // ------------------------------------- Calendar::Calendar(const TimeZone& zone, const Locale& aLocale, UErrorCode& success) : UObject(), fIsTimeSet(FALSE), fAreFieldsSet(FALSE), fAreAllFieldsSet(FALSE), fNextStamp(kMinimumUserStamp), fTime(0), fLenient(TRUE), fZone(0) { clear(); fZone = zone.clone(); setWeekCountData(aLocale, success); } // ------------------------------------- Calendar::~Calendar() { delete fZone; } // ------------------------------------- Calendar::Calendar(const Calendar &source) : UObject(source) { fZone = 0; *this = source; } // ------------------------------------- Calendar & Calendar::operator=(const Calendar &right) { if (this != &right) { uprv_arrayCopy(right.fFields, fFields, UCAL_FIELD_COUNT); uprv_arrayCopy(right.fIsSet, fIsSet, UCAL_FIELD_COUNT); uprv_arrayCopy(right.fStamp, fStamp, UCAL_FIELD_COUNT); fTime = right.fTime; fIsTimeSet = right.fIsTimeSet; fAreAllFieldsSet = right.fAreAllFieldsSet; fAreFieldsSet = right.fAreFieldsSet; fLenient = right.fLenient; delete fZone; fZone = right.fZone->clone(); fFirstDayOfWeek = right.fFirstDayOfWeek; fMinimalDaysInFirstWeek = right.fMinimalDaysInFirstWeek; fNextStamp = right.fNextStamp; } return *this; } // ------------------------------------- Calendar* Calendar::createInstance(UErrorCode& success) { return createInstance(TimeZone::createDefault(), Locale::getDefault(), success); } // ------------------------------------- Calendar* Calendar::createInstance(const TimeZone& zone, UErrorCode& success) { return createInstance(zone, Locale::getDefault(), success); } // ------------------------------------- Calendar* Calendar::createInstance(const Locale& aLocale, UErrorCode& success) { return createInstance(TimeZone::createDefault(), aLocale, success); } // ------------------------------------- Adopting // Note: this is the bottleneck that actually calls the service routines. Calendar* Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& success) { UObject* u = getService()->get(aLocale, LocaleKey::KIND_ANY, success); Calendar* c = NULL; if(U_FAILURE(success) || !u) { delete zone; if(U_SUCCESS(success)) { // Propagate some kind of err success = U_INTERNAL_PROGRAM_ERROR; } return NULL; } if(u->getDynamicClassID() == UnicodeString::getStaticClassID()) { // It's a unicode string telling us what type of calendar to load ("gregorian", etc) char tmp[200]; const UnicodeString& str = *(UnicodeString*)u; // Extract a char* out of it.. int32_t len = str.length(); if(len > sizeof(tmp)-1) { len = sizeof(tmp)-1; } str.extract(0,len,tmp); tmp[len]=0; #ifdef U_DEBUG_CALSVC // fprintf(stderr, "createInstance(%s) told to look at %s..\n", (const char*)aLocale.getName(), tmp); #endif // Create a Locale over this string Locale l(tmp); delete u; u = NULL; c = (Calendar*)getService()->get(l, LocaleKey::KIND_ANY, success); if(U_FAILURE(success) || !c) { delete zone; if(U_SUCCESS(success)) { success = U_INTERNAL_PROGRAM_ERROR; // Propagate some err } return NULL; } if(c->getDynamicClassID() == UnicodeString::getStaticClassID()) { // recursed! Second lookup returned a UnicodeString. // Perhaps DefaultCalendar{} was set to another locale. success = U_MISSING_RESOURCE_ERROR; // requested a calendar type which could NOT be found. delete c; delete zone; return NULL; } #ifdef U_DEBUG_CALSVC fprintf(stderr, "setting to locale %s\n", (const char*)aLocale.getName()); #endif c->setWeekCountData(aLocale, success); // set the correct locale (this was an indirected calendar) } else { // a calendar was returned - we assume the factory did the right thing. c = (Calendar*)u; } c->adoptTimeZone(zone); // Set the correct time zone return c; } // ------------------------------------- Calendar* Calendar::createInstance(const TimeZone& zone, const Locale& aLocale, UErrorCode& success) { Calendar* c = createInstance(aLocale, success); if(U_SUCCESS(success) && c) { c->setTimeZone(zone); } return c; } // ------------------------------------- UBool Calendar::operator==(const Calendar& that) const { UErrorCode status = U_ZERO_ERROR; return isEquivalentTo(that) && getTimeInMillis(status) == that.getTimeInMillis(status) && U_SUCCESS(status); } UBool Calendar::isEquivalentTo(const Calendar& other) const { return getDynamicClassID() == other.getDynamicClassID() && fLenient == other.fLenient && fFirstDayOfWeek == other.fFirstDayOfWeek && fMinimalDaysInFirstWeek == other.fMinimalDaysInFirstWeek && *fZone == *other.fZone; } // ------------------------------------- UBool Calendar::equals(const Calendar& when, UErrorCode& status) const { return (this == &when || getTime(status) == when.getTime(status)); } // ------------------------------------- UBool Calendar::before(const Calendar& when, UErrorCode& status) const { return (this != &when && getTimeInMillis(status) < when.getTimeInMillis(status)); } // ------------------------------------- UBool Calendar::after(const Calendar& when, UErrorCode& status) const { return (this != &when && getTimeInMillis(status) > when.getTimeInMillis(status)); } // ------------------------------------- const Locale* Calendar::getAvailableLocales(int32_t& count) { return Locale::getAvailableLocales(count); } // ------------------------------------- UDate Calendar::getNow() { return (UDate)uprv_getUTCtime() * U_MILLIS_PER_SECOND; // return as milliseconds } // ------------------------------------- /** * Gets this Calendar's current time as a long. * @return the current time as UTC milliseconds from the epoch. */ double Calendar::getTimeInMillis(UErrorCode& status) const { if(U_FAILURE(status)) return 0.0; if ( ! fIsTimeSet) ((Calendar*)this)->updateTime(status); /* Test for buffer overflows */ if(U_FAILURE(status)) { return 0.0; } return fTime; } // ------------------------------------- /** * Sets this Calendar's current time from the given long value. * @param date the new time in UTC milliseconds from the epoch. */ void Calendar::setTimeInMillis( double millis, UErrorCode& status ) { if(U_FAILURE(status)) return; fIsTimeSet = TRUE; fTime = millis; fAreFieldsSet = FALSE; computeFields(status); /* Test for buffer overflows */ if(U_FAILURE(status)) { return; } fAreFieldsSet = TRUE; fAreAllFieldsSet = TRUE; } // ------------------------------------- int32_t Calendar::get(UCalendarDateFields field, UErrorCode& status) const { // field values are only computed when actually requested; for more on when computation // of various things happens, see the "data flow in Calendar" description at the top // of this file if (U_SUCCESS(status)) ((Calendar*)this)->complete(status); // Cast away const return U_SUCCESS(status) ? fFields[field] : 0; } // ------------------------------------- void Calendar::set(UCalendarDateFields field, int32_t value) { fIsTimeSet = FALSE; fFields[field] = value; fStamp[field] = fNextStamp++; fAreFieldsSet = FALSE; fIsSet[field] = TRUE; // Remove later } // ------------------------------------- void Calendar::set(int32_t year, int32_t month, int32_t date) { set(UCAL_YEAR, year); set(UCAL_MONTH, month); set(UCAL_DATE, date); } // ------------------------------------- void Calendar::set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute) { set(UCAL_YEAR, year); set(UCAL_MONTH, month); set(UCAL_DATE, date); set(UCAL_HOUR_OF_DAY, hour); set(UCAL_MINUTE, minute); } // ------------------------------------- void Calendar::set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute, int32_t second) { set(UCAL_YEAR, year); set(UCAL_MONTH, month); set(UCAL_DATE, date); set(UCAL_HOUR_OF_DAY, hour); set(UCAL_MINUTE, minute); set(UCAL_SECOND, second); } // ------------------------------------- void Calendar::clear() { for (int32_t i=0; i targetMs) { break; } else { max <<= 1; if (max < 0) { // Field difference too large to fit into int32_t ec = U_ILLEGAL_ARGUMENT_ERROR; } } } // Do a binary search while ((max - min) > 1 && U_SUCCESS(ec)) { int32_t t = (min + max) / 2; setTimeInMillis(startMs, ec); add(field, t, ec); double ms = getTimeInMillis(ec); if (ms == targetMs) { return t; } else if (ms > targetMs) { max = t; } else { min = t; } } } else if (startMs > targetMs) { int32_t max = -1; // Find a value that is too small while (U_SUCCESS(ec)) { setTimeInMillis(startMs, ec); add(field, max, ec); double ms = getTimeInMillis(ec); if (ms == targetMs) { return max; } else if (ms < targetMs) { break; } else { max <<= 1; if (max == 0) { // Field difference too large to fit into int32_t ec = U_ILLEGAL_ARGUMENT_ERROR; } } } // Do a binary search while ((min - max) > 1 && U_SUCCESS(ec)) { int32_t t = (min + max) / 2; setTimeInMillis(startMs, ec); add(field, t, ec); double ms = getTimeInMillis(ec); if (ms == targetMs) { return t; } else if (ms < targetMs) { max = t; } else { min = t; } } } // Set calendar to end point setTimeInMillis(startMs, ec); add(field, min, ec); /* Test for buffer overflows */ if(U_FAILURE(ec)) { return 0; } return min; } // ------------------------------------- void Calendar::adoptTimeZone(TimeZone* zone) { // Do nothing if passed-in zone is NULL if (zone == NULL) return; // fZone should always be non-null if (fZone != NULL) delete fZone; fZone = zone; // if the zone changes, we need to recompute the time fields fAreFieldsSet = FALSE; } // ------------------------------------- void Calendar::setTimeZone(const TimeZone& zone) { adoptTimeZone(zone.clone()); } // ------------------------------------- const TimeZone& Calendar::getTimeZone() const { return *fZone; } // ------------------------------------- TimeZone* Calendar::orphanTimeZone() { TimeZone *z = fZone; // we let go of the time zone; the new time zone is the system default time zone fZone = TimeZone::createDefault(); return z; } // ------------------------------------- void Calendar::setLenient(UBool lenient) { fLenient = lenient; } // ------------------------------------- UBool Calendar::isLenient() const { return fLenient; } // ------------------------------------- void Calendar::setFirstDayOfWeek(UCalendarDaysOfWeek value) { if (fFirstDayOfWeek != value && value >= UCAL_SUNDAY && value <= UCAL_SATURDAY) { fFirstDayOfWeek = value; fAreFieldsSet = FALSE; } } // ------------------------------------- Calendar::EDaysOfWeek Calendar::getFirstDayOfWeek() const { return (Calendar::EDaysOfWeek)fFirstDayOfWeek; } UCalendarDaysOfWeek Calendar::getFirstDayOfWeek(UErrorCode & /*status*/) const { return fFirstDayOfWeek; } // ------------------------------------- void Calendar::setMinimalDaysInFirstWeek(uint8_t value) { // Values less than 1 have the same effect as 1; values greater // than 7 have the same effect as 7. However, we normalize values // so operator== and so forth work. if (value < 1) { value = 1; } else if (value > 7) { value = 7; } if (fMinimalDaysInFirstWeek != value) { fMinimalDaysInFirstWeek = value; fAreFieldsSet = FALSE; } } // ------------------------------------- uint8_t Calendar::getMinimalDaysInFirstWeek() const { return fMinimalDaysInFirstWeek; } // ------------------------------------- int32_t Calendar::getActualMinimum(UCalendarDateFields field, UErrorCode& status) const { int32_t fieldValue = getGreatestMinimum(field); int32_t endValue = getMinimum(field); // if we know that the minimum value is always the same, just return it if (fieldValue == endValue) { return fieldValue; } // clone the calendar so we don't mess with the real one, and set it to // accept anything for the field values Calendar *work = (Calendar*)this->clone(); work->setLenient(TRUE); // now try each value from getLeastMaximum() to getMaximum() one by one until // we get a value that normalizes to another value. The last value that // normalizes to itself is the actual minimum for the current date int32_t result = fieldValue; do { work->set(field, fieldValue); if (work->get(field, status) != fieldValue) { break; } else { result = fieldValue; fieldValue--; } } while (fieldValue >= endValue); delete work; /* Test for buffer overflows */ if(U_FAILURE(status)) { return 0; } return result; } // ------------------------------------- int32_t Calendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const { int32_t fieldValue = getLeastMaximum(field); int32_t endValue = getMaximum(field); // if we know that the maximum value is always the same, just return it if (fieldValue == endValue) { return fieldValue; } // clone the calendar so we don't mess with the real one, and set it to // accept anything for the field values Calendar *work = (Calendar*)this->clone(); work->setLenient(TRUE); // if we're counting weeks, set the day of the week to Sunday. We know the // last week of a month or year will contain the first day of the week. if (field == UCAL_WEEK_OF_YEAR || field == UCAL_WEEK_OF_MONTH) work->set(UCAL_DAY_OF_WEEK, fFirstDayOfWeek); // now try each value from getLeastMaximum() to getMaximum() one by one until // we get a value that normalizes to another value. The last value that // normalizes to itself is the actual maximum for the current date int32_t result = fieldValue; do { work->set(field, fieldValue); if(work->get(field, status) != fieldValue) { break; } else { result = fieldValue; fieldValue++; } } while (fieldValue <= endValue); delete work; /* Test for buffer overflows */ if(U_FAILURE(status)) { return 0; } return result; } // ------------------------------------- void Calendar::setWeekCountData(const Locale& desiredLocale, UErrorCode& status) { // Read the week count data from the resource bundle. This should // have the form: // // DateTimeElements:intvector { // 1, // first day of week // 1 // min days in week // } // Both have a range of 1..7 if (U_FAILURE(status)) return; fFirstDayOfWeek = UCAL_SUNDAY; fMinimalDaysInFirstWeek = 1; UResourceBundle *resource = ures_open(NULL, desiredLocale.getName(), &status); // If the resource data doesn't seem to be present at all, then use last-resort // hard-coded data. if (U_FAILURE(status)) { status = U_USING_FALLBACK_WARNING; ures_close(resource); return; } //dateTimeElements = resource.getStringArray(kDateTimeElements, count, status); UResourceBundle *dateTimeElements = ures_getByKey(resource, kDateTimeElements, NULL, &status); if (U_SUCCESS(status)) { int32_t arrLen; const int32_t *dateTimeElementsArr = ures_getIntVector(dateTimeElements, &arrLen, &status); if(U_SUCCESS(status) && arrLen == 2 && 1 <= dateTimeElementsArr[0] && dateTimeElementsArr[0] <= 7 && 1 <= dateTimeElementsArr[1] && dateTimeElementsArr[1] <= 7) { fFirstDayOfWeek = (UCalendarDaysOfWeek)dateTimeElementsArr[0]; fMinimalDaysInFirstWeek = (uint8_t)dateTimeElementsArr[1]; } else { status = U_INVALID_FORMAT_ERROR; } } ures_close(dateTimeElements); ures_close(resource); } /** * Recompute the time and update the status fields isTimeSet * and areFieldsSet. Callers should check isTimeSet and only * call this method if isTimeSet is false. */ void Calendar::updateTime(UErrorCode& status) { computeTime(status); if(U_FAILURE(status)) return; // If we are lenient, we need to recompute the fields to normalize // the values. Also, if we haven't set all the fields yet (i.e., // in a newly-created object), we need to fill in the fields. [LIU] if (isLenient() || ! fAreAllFieldsSet) fAreFieldsSet = FALSE; fIsTimeSet = TRUE; } U_NAMESPACE_END U_CFUNC UBool calendar_cleanup(void) { if (gService) { delete gService; gService = NULL; } umtx_destroy(&gnLock); return TRUE; } #endif /* #if !UCONFIG_NO_FORMATTING */ //eof