Boolean CFCalendarGetTimeRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit, CFAbsoluteTime at, CFAbsoluteTime *startp, CFTimeInterval *tip) { CF_OBJC_FUNCDISPATCH4(CFCalendarGetTypeID(), Boolean, calendar, "_rangeOfUnit:startTime:interval:forAT:", unit, startp, tip, at); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (kCFCalendarUnitWeekdayOrdinal == unit) return false; if (kCFCalendarUnitWeekday == unit) unit = kCFCalendarUnitDay; if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { ucal_clear(calendar->_cal); __CFCalendarSetToFirstInstant(calendar, unit, at); UErrorCode status = U_ZERO_ERROR; UDate start = ucal_getMillis(calendar->_cal, &status); UCalendarDateFields field = __CFCalendarGetICUFieldCode(unit); ucal_add(calendar->_cal, field, 1, &status); UDate end = ucal_getMillis(calendar->_cal, &status); if (end == start && kCFCalendarUnitEra == unit) { // ICU refuses to do the addition, probably because we are // at the limit of UCAL_ERA. Use alternate strategy. CFIndex limit = ucal_getLimit(calendar->_cal, UCAL_YEAR, UCAL_MAXIMUM, &status); if (100000 < limit) limit = 100000; ucal_add(calendar->_cal, UCAL_YEAR, limit, &status); end = ucal_getMillis(calendar->_cal, &status); } if (U_SUCCESS(status)) { if (startp) *startp = (double)start / 1000.0 - kCFAbsoluteTimeIntervalSince1970; if (tip) *tip = (double)(end - start) / 1000.0; return true; } } return false; }
void CFCalendarSetFirstWeekday(CFCalendarRef calendar, CFIndex wkdy) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), void, calendar, setFirstWeekday:wkdy); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { ucal_setAttribute(calendar->_cal, UCAL_FIRST_DAY_OF_WEEK, wkdy); } }
CFIndex CFCalendarGetFirstWeekday(CFCalendarRef calendar) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFIndex, calendar, firstWeekday); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { return ucal_getAttribute(calendar->_cal, UCAL_FIRST_DAY_OF_WEEK); } return -1; }
CFIndex CFCalendarGetOrdinalityOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { CFIndex result = kCFNotFound; if (!__validUnits(smallerUnit, biggerUnit)) return result; CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), CFIndex, calendar, "_ordinalityOfUnit:inUnit:forAT:", smallerUnit, biggerUnit, at); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { UErrorCode status = U_ZERO_ERROR; ucal_clear(calendar->_cal); if (kCFCalendarUnitWeek == smallerUnit && kCFCalendarUnitYear == biggerUnit) { UDate udate = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); ucal_setMillis(calendar->_cal, udate, &status); int32_t val = ucal_get(calendar->_cal, UCAL_WEEK_OF_YEAR, &status); return val; } else if (kCFCalendarUnitWeek == smallerUnit && kCFCalendarUnitMonth == biggerUnit) { UDate udate = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); ucal_setMillis(calendar->_cal, udate, &status); int32_t val = ucal_get(calendar->_cal, UCAL_WEEK_OF_MONTH, &status); return val; } UCalendarDateFields smallField = __CFCalendarGetICUFieldCode(smallerUnit); // Set calendar to first instant of big unit __CFCalendarSetToFirstInstant(calendar, biggerUnit, at); UDate curr = ucal_getMillis(calendar->_cal, &status); UDate goal = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); result = 1; const int multiple_table[] = {0, 0, 16, 19, 24, 26, 24, 28, 14, 14, 14}; int multiple = (1 << multiple_table[flsl(smallerUnit) - 1]); Boolean divide = false, alwaysDivide = false; while (curr < goal) { ucal_add(calendar->_cal, smallField, multiple, &status); UDate newcurr = ucal_getMillis(calendar->_cal, &status); if (curr < newcurr && newcurr <= goal) { result += multiple; curr = newcurr; } else { // Either newcurr is going backwards, or not making // progress, or has overshot the goal; reset date // and try smaller multiples. ucal_setMillis(calendar->_cal, curr, &status); divide = true; // once we start overshooting the goal, the add at // smaller multiples will succeed at most once for // each multiple, so we reduce it every time through // the loop. if (goal < newcurr) alwaysDivide = true; } if (divide) { multiple = multiple / 2; if (0 == multiple) break; divide = alwaysDivide; } } } return result; }
void CFCalendarSetTimeZone(CFCalendarRef calendar, CFTimeZoneRef tz) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), void, calendar, setTimeZone:tz); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (tz) __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); if (tz != calendar->_tz) { CFRelease(calendar->_tz); calendar->_tz = tz ? (CFTimeZoneRef)CFRetain(tz) : CFTimeZoneCopyDefault(); if (calendar->_cal) __CFCalendarZapCal(calendar); } }
void CFCalendarSetLocale(CFCalendarRef calendar, CFLocaleRef locale) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), void, calendar, setLocale:locale); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); __CFGenericValidateType(locale, CFLocaleGetTypeID()); CFStringRef localeID = CFLocaleGetIdentifier(locale); if (localeID != calendar->_localeID) { CFRelease(calendar->_localeID); CFRetain(localeID); calendar->_localeID = localeID; if (calendar->_cal) __CFCalendarZapCal(calendar); } }
CFDateRef CFCalendarCopyGregorianStartDate(CFCalendarRef calendar) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFDateRef, calendar, _gregorianStartDate); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); UErrorCode status = U_ZERO_ERROR; UDate udate = calendar->_cal ? ucal_getGregorianChange(calendar->_cal, &status) : 0; if (calendar->_cal && U_SUCCESS(status)) { CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970; return CFDateCreate(CFGetAllocator(calendar), at); } return NULL; }
Boolean CFCalendarAddComponents(CFCalendarRef calendar, /* inout */ CFAbsoluteTime *atp, CFOptionFlags options, const char *componentDesc, ...) { va_list args; va_start(args, componentDesc); CF_OBJC_FUNCDISPATCH4(CFCalendarGetTypeID(), Boolean, calendar, "_addComponents::::", atp, options, componentDesc, args); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); int idx, cnt = strlen((char *)componentDesc); STACK_BUFFER_DECL(int, vector, cnt); for (idx = 0; idx < cnt; idx++) { int arg = va_arg(args, int); vector[idx] = arg; } va_end(args); return _CFCalendarAddComponentsV(calendar, atp, options, componentDesc, vector, cnt); }
Boolean CFCalendarDecomposeAbsoluteTime(CFCalendarRef calendar, CFAbsoluteTime at, const char *componentDesc, ...) { va_list args; va_start(args, componentDesc); CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), Boolean, calendar, "_decomposeAbsoluteTime:::", at, componentDesc, args); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); int idx, cnt = strlen((char *)componentDesc); STACK_BUFFER_DECL(int *, vector, cnt); for (idx = 0; idx < cnt; idx++) { int *arg = va_arg(args, int *); vector[idx] = arg; } va_end(args); return _CFCalendarDecomposeAbsoluteTimeV(calendar, at, componentDesc, vector, cnt); }
Boolean CFCalendarGetComponentDifference(CFCalendarRef calendar, CFAbsoluteTime startingAT, CFAbsoluteTime resultAT, CFOptionFlags options, const char *componentDesc, ...) { va_list args; va_start(args, componentDesc); CF_OBJC_FUNCDISPATCH5(CFCalendarGetTypeID(), Boolean, calendar, "_diffComponents:::::", startingAT, resultAT, options, componentDesc, args); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); int idx, cnt = strlen((char *)componentDesc); STACK_BUFFER_DECL(int *, vector, cnt); for (idx = 0; idx < cnt; idx++) { int *arg = va_arg(args, int *); vector[idx] = arg; } va_end(args); Boolean ret = _CFCalendarGetComponentDifferenceV(calendar, startingAT, resultAT, options, componentDesc, vector, cnt); return ret; }
CFCalendarRef CFCalendarCreateWithIdentifier(CFAllocatorRef allocator, CFStringRef identifier) { if (allocator == NULL) allocator = __CFGetDefaultAllocator(); __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); __CFGenericValidateType(identifier, CFStringGetTypeID()); // return NULL until Chinese calendar is available if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar) { // if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar && identifier != kCFChineseCalendar) { if (CFEqual(kCFGregorianCalendar, identifier)) identifier = kCFGregorianCalendar; else if (CFEqual(kCFBuddhistCalendar, identifier)) identifier = kCFBuddhistCalendar; else if (CFEqual(kCFJapaneseCalendar, identifier)) identifier = kCFJapaneseCalendar; else if (CFEqual(kCFIslamicCalendar, identifier)) identifier = kCFIslamicCalendar; else if (CFEqual(kCFIslamicCivilCalendar, identifier)) identifier = kCFIslamicCivilCalendar; else if (CFEqual(kCFHebrewCalendar, identifier)) identifier = kCFHebrewCalendar; // else if (CFEqual(kCFChineseCalendar, identifier)) identifier = kCFChineseCalendar; else return NULL; } struct __CFCalendar *calendar = NULL; uint32_t size = sizeof(struct __CFCalendar) - sizeof(CFRuntimeBase); calendar = (struct __CFCalendar *)_CFRuntimeCreateInstance(allocator, CFCalendarGetTypeID(), size, NULL); if (NULL == calendar) { return NULL; } calendar->_identifier = (CFStringRef)CFRetain(identifier); calendar->_locale = NULL; calendar->_localeID = CFLocaleGetIdentifier(CFLocaleGetSystem()); calendar->_tz = CFTimeZoneCopyDefault(); calendar->_cal = NULL; return (CFCalendarRef)calendar; }
CFRange CFCalendarGetMaximumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit) { CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), CFRange, calendar, "_maximumRangeOfUnit:", unit); CFRange range = {kCFNotFound, kCFNotFound}; __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { ucal_clear(calendar->_cal); UCalendarDateFields field = __CFCalendarGetICUFieldCode(unit); UErrorCode status = U_ZERO_ERROR; range.location = ucal_getLimit(calendar->_cal, field, UCAL_MINIMUM, &status); range.length = ucal_getLimit(calendar->_cal, field, UCAL_MAXIMUM, &status) - range.location + 1; if (UCAL_MONTH == field) range.location++; if (100000 < range.length) range.length = 100000; } return range; }
void CFCalendarSetGregorianStartDate(CFCalendarRef calendar, CFDateRef date) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), void, calendar, _setGregorianStartDate:date); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (date) __CFGenericValidateType(date, CFDateGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (!calendar->_cal) return; if (!date) { UErrorCode status = U_ZERO_ERROR; UCalendar *cal = __CFCalendarCreateUCalendar(calendar->_identifier, calendar->_localeID, calendar->_tz); UDate udate = cal ? ucal_getGregorianChange(cal, &status) : 0; if (cal && U_SUCCESS(status)) { status = U_ZERO_ERROR; if (calendar->_cal) ucal_setGregorianChange(calendar->_cal, udate, &status); } if (cal) ucal_close(cal); } else { CFAbsoluteTime at = CFDateGetAbsoluteTime(date); UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0; UErrorCode status = U_ZERO_ERROR; if (calendar->_cal) ucal_setGregorianChange(calendar->_cal, udate, &status); } }
static CFRange __CFCalendarGetRangeOfUnit1(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { CFRange range = {kCFNotFound, kCFNotFound}; if (!__validUnits(smallerUnit, biggerUnit)) return range; CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), CFRange, calendar, "_rangeOfUnit:inUnit:forAT:", smallerUnit, biggerUnit, at); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { int32_t dow = -1; ucal_clear(calendar->_cal); UCalendarDateFields smallField = __CFCalendarGetICUFieldCode(smallerUnit); UCalendarDateFields bigField = __CFCalendarGetICUFieldCode(biggerUnit); if (kCFCalendarUnitWeekdayOrdinal == smallerUnit) { UErrorCode status = U_ZERO_ERROR; UDate udate = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); ucal_setMillis(calendar->_cal, udate, &status); dow = ucal_get(calendar->_cal, UCAL_DAY_OF_WEEK, &status); } // Set calendar to first instant of big unit __CFCalendarSetToFirstInstant(calendar, biggerUnit, at); UErrorCode status = U_ZERO_ERROR; UDate start = ucal_getMillis(calendar->_cal, &status); if (kCFCalendarUnitWeek == biggerUnit) { range.location = ucal_get(calendar->_cal, smallField, &status); if (kCFCalendarUnitMonth == smallerUnit) range.location++; } else { range.location = (kCFCalendarUnitHour == smallerUnit || kCFCalendarUnitMinute == smallerUnit || kCFCalendarUnitSecond == smallerUnit) ? 0 : 1; } // Set calendar to first instant of next value of big unit if (UCAL_ERA == bigField) { // ICU refuses to do the addition, probably because we are // at the limit of UCAL_ERA. Use alternate strategy. CFIndex limit = ucal_getLimit(calendar->_cal, UCAL_YEAR, UCAL_MAXIMUM, &status); if (100000 < limit) limit = 100000; ucal_add(calendar->_cal, UCAL_YEAR, limit, &status); } else { ucal_add(calendar->_cal, bigField, 1, &status); } if (kCFCalendarUnitWeek == smallerUnit && kCFCalendarUnitYear == biggerUnit) { ucal_add(calendar->_cal, UCAL_SECOND, -1, &status); range.length = ucal_get(calendar->_cal, UCAL_WEEK_OF_YEAR, &status); while (1 == range.length) { ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, -1, &status); range.length = ucal_get(calendar->_cal, UCAL_WEEK_OF_YEAR, &status); } range.location = 1; return range; } else if (kCFCalendarUnitWeek == smallerUnit && kCFCalendarUnitMonth == biggerUnit) { ucal_add(calendar->_cal, UCAL_SECOND, -1, &status); range.length = ucal_get(calendar->_cal, UCAL_WEEK_OF_YEAR, &status); range.location = 1; return range; } UDate goal = ucal_getMillis(calendar->_cal, &status); // Set calendar back to first instant of big unit ucal_setMillis(calendar->_cal, start, &status); if (kCFCalendarUnitWeekdayOrdinal == smallerUnit) { // roll day forward to first 'dow' while (ucal_get(calendar->_cal, (kCFCalendarUnitMonth == biggerUnit) ? UCAL_WEEK_OF_MONTH : UCAL_WEEK_OF_YEAR, &status) != 1) { ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, 1, &status); } while (ucal_get(calendar->_cal, UCAL_DAY_OF_WEEK, &status) != dow) { ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, 1, &status); } start = ucal_getMillis(calendar->_cal, &status); goal -= 1000; range.location = 1; // constant here works around ICU -- see 3948293 } UDate curr = start; range.length = (kCFCalendarUnitWeekdayOrdinal == smallerUnit) ? 1 : 0; const int multiple_table[] = {0, 0, 16, 19, 24, 26, 24, 28, 14, 14, 14}; int multiple = (1 << multiple_table[flsl(smallerUnit) - 1]); Boolean divide = false, alwaysDivide = false; while (curr < goal) { ucal_add(calendar->_cal, smallField, multiple, &status); UDate newcurr = ucal_getMillis(calendar->_cal, &status); if (curr < newcurr && newcurr <= goal) { range.length += multiple; curr = newcurr; } else { // Either newcurr is going backwards, or not making // progress, or has overshot the goal; reset date // and try smaller multiples. ucal_setMillis(calendar->_cal, curr, &status); divide = true; // once we start overshooting the goal, the add at // smaller multiples will succeed at most once for // each multiple, so we reduce it every time through // the loop. if (goal < newcurr) alwaysDivide = true; } if (divide) { multiple = multiple / 2; if (0 == multiple) break; divide = alwaysDivide; } } } return range; }
CFLocaleRef CFCalendarCopyLocale(CFCalendarRef calendar) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFLocaleRef, calendar, _copyLocale); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); return (CFLocaleRef)CFLocaleCreate(kCFAllocatorSystemDefault, calendar->_localeID); }
void CFCalendarSetMinimumDaysInFirstWeek(CFCalendarRef calendar, CFIndex mwd) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), void, calendar, setMinimumDaysInFirstWeek:mwd); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) ucal_setAttribute(calendar->_cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK, mwd); }
CFIndex CFCalendarGetMinimumDaysInFirstWeek(CFCalendarRef calendar) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFIndex, calendar, minimumDaysInFirstWeek); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); return calendar->_cal ? ucal_getAttribute(calendar->_cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK) : -1; }
static CFRange __CFCalendarGetRangeOfUnit2(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), CFRange, calendar, "_rangeOfUnit:inUnit:forAT:", smallerUnit, biggerUnit, at); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); CFRange range = {kCFNotFound, kCFNotFound}; if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { switch (smallerUnit) { case kCFCalendarUnitSecond: switch (biggerUnit) { case kCFCalendarUnitMinute: case kCFCalendarUnitHour: case kCFCalendarUnitDay: case kCFCalendarUnitWeekday: case kCFCalendarUnitWeek: case kCFCalendarUnitMonth: case kCFCalendarUnitYear: case kCFCalendarUnitEra: // goto calculate; range.location = 0; range.length = 60; break; } break; case kCFCalendarUnitMinute: switch (biggerUnit) { case kCFCalendarUnitHour: case kCFCalendarUnitDay: case kCFCalendarUnitWeekday: case kCFCalendarUnitWeek: case kCFCalendarUnitMonth: case kCFCalendarUnitYear: case kCFCalendarUnitEra: // goto calculate; range.location = 0; range.length = 60; break; } break; case kCFCalendarUnitHour: switch (biggerUnit) { case kCFCalendarUnitDay: case kCFCalendarUnitWeekday: case kCFCalendarUnitWeek: case kCFCalendarUnitMonth: case kCFCalendarUnitYear: case kCFCalendarUnitEra: // goto calculate; range.location = 0; range.length = 24; break; } break; case kCFCalendarUnitDay: switch (biggerUnit) { case kCFCalendarUnitWeek: case kCFCalendarUnitMonth: case kCFCalendarUnitYear: case kCFCalendarUnitEra: goto calculate; break; } break; case kCFCalendarUnitWeekday: switch (biggerUnit) { case kCFCalendarUnitWeek: case kCFCalendarUnitMonth: case kCFCalendarUnitYear: case kCFCalendarUnitEra: goto calculate; break; } break; case kCFCalendarUnitWeekdayOrdinal: switch (biggerUnit) { case kCFCalendarUnitMonth: case kCFCalendarUnitYear: case kCFCalendarUnitEra: goto calculate; break; } break; case kCFCalendarUnitWeek: switch (biggerUnit) { case kCFCalendarUnitMonth: case kCFCalendarUnitYear: case kCFCalendarUnitEra: goto calculate; break; } break; case kCFCalendarUnitMonth: switch (biggerUnit) { case kCFCalendarUnitYear: case kCFCalendarUnitEra: goto calculate; break; } break; case kCFCalendarUnitYear: switch (biggerUnit) { case kCFCalendarUnitEra: goto calculate; break; } break; case kCFCalendarUnitEra: break; } } return range; calculate:; ucal_clear(calendar->_cal); UCalendarDateFields smallField = __CFCalendarGetICUFieldCode(smallerUnit); UCalendarDateFields bigField = __CFCalendarGetICUFieldCode(biggerUnit); UCalendarDateFields yearField = __CFCalendarGetICUFieldCode(kCFCalendarUnitYear); UCalendarDateFields fieldToAdd = smallField; if (kCFCalendarUnitWeekday == smallerUnit) { fieldToAdd = __CFCalendarGetICUFieldCode(kCFCalendarUnitDay); } int32_t dow = -1; if (kCFCalendarUnitWeekdayOrdinal == smallerUnit) { UErrorCode status = U_ZERO_ERROR; UDate udate = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); ucal_setMillis(calendar->_cal, udate, &status); dow = ucal_get(calendar->_cal, UCAL_DAY_OF_WEEK, &status); fieldToAdd = __CFCalendarGetICUFieldCode(kCFCalendarUnitWeek); } // Set calendar to first instant of big unit __CFCalendarSetToFirstInstant(calendar, biggerUnit, at); if (kCFCalendarUnitWeekdayOrdinal == smallerUnit) { UErrorCode status = U_ZERO_ERROR; // roll day forward to first 'dow' while (ucal_get(calendar->_cal, (kCFCalendarUnitMonth == biggerUnit) ? UCAL_WEEK_OF_MONTH : UCAL_WEEK_OF_YEAR, &status) != 1) { ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, 1, &status); } while (ucal_get(calendar->_cal, UCAL_DAY_OF_WEEK, &status) != dow) { ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, 1, &status); } } int32_t minSmallValue = INT32_MAX; int32_t maxSmallValue = INT32_MIN; UErrorCode status = U_ZERO_ERROR; int32_t bigValue = ucal_get(calendar->_cal, bigField, &status); for (;;) { int32_t smallValue = ucal_get(calendar->_cal, smallField, &status); if (smallValue < minSmallValue) minSmallValue = smallValue; if (smallValue > maxSmallValue) maxSmallValue = smallValue; ucal_add(calendar->_cal, fieldToAdd, 1, &status); if (bigValue != ucal_get(calendar->_cal, bigField, &status)) break; if (biggerUnit == kCFCalendarUnitEra && ucal_get(calendar->_cal, yearField, &status) > 10000) break; // we assume an answer for 10000 years can be extrapolated to 100000 years, to save time } status = U_ZERO_ERROR; range.location = minSmallValue; if (smallerUnit == kCFCalendarUnitMonth) range.location = 1; range.length = maxSmallValue - minSmallValue + 1; if (biggerUnit == kCFCalendarUnitEra && ucal_get(calendar->_cal, yearField, &status) > 10000) range.length = 100000; return range; }
CFStringRef CFCalendarGetIdentifier(CFCalendarRef calendar) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFStringRef, calendar, calendarIdentifier); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); return calendar->_identifier; }
CFTimeZoneRef CFCalendarCopyTimeZone(CFCalendarRef calendar) { CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFTimeZoneRef, calendar_copyTimeZone); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); return (CFTimeZoneRef)CFRetain(calendar->_tz); }