#include <CoreFoundation/CFDate.h>
#include <CoreFoundation/CFTimeZone.h>
#include <CoreFoundation/CFDictionary.h>
#include <CoreFoundation/CFArray.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFNumber.h>
#include "CFInternal.h"
#include <math.h>
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
#include <sys/time.h>
#elif DEPLOYMENT_TARGET_WINDOWS
#else
#error Unknown or unspecified DEPLOYMENT_TARGET
#endif
const CFTimeInterval kCFAbsoluteTimeIntervalSince1970 = 978307200.0L;
const CFTimeInterval kCFAbsoluteTimeIntervalSince1904 = 3061152000.0L;
__private_extern__ double __CFTSRRate = 0.0;
static double __CF1_TSRRate = 0.0;
__private_extern__ int64_t __CFTimeIntervalToTSR(CFTimeInterval ti) {
if ((ti * __CFTSRRate) > INT64_MAX / 2) return (INT64_MAX / 2);
return (int64_t)(ti * __CFTSRRate);
}
__private_extern__ CFTimeInterval __CFTSRToTimeInterval(int64_t tsr) {
return (CFTimeInterval)((double)tsr * __CF1_TSRRate);
}
CFAbsoluteTime CFAbsoluteTimeGetCurrent(void) {
CFAbsoluteTime ret;
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_IPHONE
struct timeval tv;
gettimeofday(&tv, NULL);
ret = (CFTimeInterval)tv.tv_sec - kCFAbsoluteTimeIntervalSince1970;
ret += (1.0E-6 * (CFTimeInterval)tv.tv_usec);
#elif DEPLOYMENT_TARGET_WINDOWS_SYNC || DEPLOYMENT_TARGET_CODE011
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
ret = _CFAbsoluteTimeFromFileTime(&ft);
#else
#error Unknown or unspecified DEPLOYMENT_TARGET
#endif
return ret;
}
__private_extern__ void __CFDateInitialize(void) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_IPHONE
struct mach_timebase_info info;
mach_timebase_info(&info);
__CFTSRRate = (1.0E9 / (double)info.numer) * (double)info.denom;
__CF1_TSRRate = 1.0 / __CFTSRRate;
#elif DEPLOYMENT_TARGET_WINDOWS_SYNC || DEPLOYMENT_TARGET_CODE011
LARGE_INTEGER freq;
if (!QueryPerformanceFrequency(&freq)) {
HALT;
}
__CFTSRRate = (double)freq.QuadPart;
__CF1_TSRRate = 1.0 / __CFTSRRate;
#else
#error Unknown or unspecified DEPLOYMENT_TARGET
#endif
CFDateGetTypeID(); }
#if 1
struct __CFDate {
CFRuntimeBase _base;
CFAbsoluteTime _time;
};
static Boolean __CFDateEqual(CFTypeRef cf1, CFTypeRef cf2) {
CFDateRef date1 = (CFDateRef)cf1;
CFDateRef date2 = (CFDateRef)cf2;
if (date1->_time != date2->_time) return false;
return true;
}
static CFHashCode __CFDateHash(CFTypeRef cf) {
CFDateRef date = (CFDateRef)cf;
return (CFHashCode)(float)floor(date->_time);
}
static CFStringRef __CFDateCopyDescription(CFTypeRef cf) {
CFDateRef date = (CFDateRef)cf;
return CFStringCreateWithFormat(CFGetAllocator(date), NULL, CFSTR("<CFDate %p [%p]>{time = %0.09g}"), cf, CFGetAllocator(date), date->_time);
}
static CFTypeID __kCFDateTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __CFDateClass = {
0,
"CFDate",
NULL, NULL, NULL, __CFDateEqual,
__CFDateHash,
NULL, __CFDateCopyDescription
};
CFTypeID CFDateGetTypeID(void) {
if (_kCFRuntimeNotATypeID == __kCFDateTypeID) __kCFDateTypeID = _CFRuntimeRegisterClass(&__CFDateClass);
return __kCFDateTypeID;
}
CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at) {
CFDateRef memory;
uint32_t size;
size = sizeof(struct __CFDate) - sizeof(CFRuntimeBase);
memory = (CFDateRef)_CFRuntimeCreateInstance(allocator, CFDateGetTypeID(), size, NULL);
if (NULL == memory) {
return NULL;
}
((struct __CFDate *)memory)->_time = at;
return memory;
}
CFTimeInterval CFDateGetAbsoluteTime(CFDateRef date) {
CF_OBJC_FUNCDISPATCH0(CFDateGetTypeID(), CFTimeInterval, date, "timeIntervalSinceReferenceDate");
__CFGenericValidateType(date, CFDateGetTypeID());
return date->_time;
}
CFTimeInterval CFDateGetTimeIntervalSinceDate(CFDateRef date, CFDateRef otherDate) {
CF_OBJC_FUNCDISPATCH1(CFDateGetTypeID(), CFTimeInterval, date, "timeIntervalSinceDate:", otherDate);
__CFGenericValidateType(date, CFDateGetTypeID());
__CFGenericValidateType(otherDate, CFDateGetTypeID());
return date->_time - otherDate->_time;
}
CFComparisonResult CFDateCompare(CFDateRef date, CFDateRef otherDate, void *context) {
CF_OBJC_FUNCDISPATCH1(CFDateGetTypeID(), CFComparisonResult, date, "compare:", otherDate);
__CFGenericValidateType(date, CFDateGetTypeID());
__CFGenericValidateType(otherDate, CFDateGetTypeID());
if (date->_time < otherDate->_time) return kCFCompareLessThan;
if (date->_time > otherDate->_time) return kCFCompareGreaterThan;
return kCFCompareEqualTo;
}
#endif
CF_INLINE int32_t __CFDoubleModToInt(double d, int32_t modulus) {
int32_t result = (int32_t)(float)floor(d - floor(d / modulus) * modulus);
if (result < 0) result += modulus;
return result;
}
CF_INLINE double __CFDoubleMod(double d, int32_t modulus) {
double result = d - floor(d / modulus) * modulus;
if (result < 0.0) result += (double)modulus;
return result;
}
static const uint8_t daysInMonth[16] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0, 0, 0};
static const uint16_t daysBeforeMonth[16] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0};
static const uint16_t daysAfterMonth[16] = {365, 334, 306, 275, 245, 214, 184, 153, 122, 92, 61, 31, 0, 0, 0, 0};
CF_INLINE bool isleap(int64_t year) {
int64_t y = (year + 1) % 400;
if (y < 0) y = -y;
return (0 == (y & 3) && 100 != y && 200 != y && 300 != y);
}
CF_INLINE uint8_t __CFDaysInMonth(int8_t month, int64_t year, bool leap) {
return daysInMonth[month] + (2 == month && leap);
}
CF_INLINE uint16_t __CFDaysBeforeMonth(int8_t month, int64_t year, bool leap) {
return daysBeforeMonth[month] + (2 < month && leap);
}
CF_INLINE uint16_t __CFDaysAfterMonth(int8_t month, int64_t year, bool leap) {
return daysAfterMonth[month] + (month < 2 && leap);
}
static void __CFYMDFromAbsolute(int64_t absolute, int64_t *year, int8_t *month, int8_t *day) {
int64_t b = absolute / 146097; int64_t y = b * 400;
uint16_t ydays;
absolute -= b * 146097;
while (absolute < 0) {
y -= 1;
absolute += __CFDaysAfterMonth(0, y, isleap(y));
}
ydays = __CFDaysAfterMonth(0, y, isleap(y));
while (ydays <= absolute) {
y += 1;
absolute -= ydays;
ydays = __CFDaysAfterMonth(0, y, isleap(y));
}
if (year) *year = y;
if (month || day) {
int8_t m = absolute / 33 + 1;
bool leap = isleap(y);
while (__CFDaysBeforeMonth(m + 1, y, leap) <= absolute) m++;
if (month) *month = m;
if (day) *day = absolute - __CFDaysBeforeMonth(m, y, leap) + 1;
}
}
static double __CFAbsoluteFromYMD(int64_t year, int8_t month, int8_t day) {
double absolute = 0.0;
int64_t idx;
int64_t b = year / 400; absolute += b * 146097.0;
year -= b * 400;
if (year < 0) {
for (idx = year; idx < 0; idx++)
absolute -= __CFDaysAfterMonth(0, idx, isleap(idx));
} else {
for (idx = 0; idx < year; idx++)
absolute += __CFDaysAfterMonth(0, idx, isleap(idx));
}
absolute += __CFDaysBeforeMonth(month, year, isleap(year)) + day - 1;
return absolute;
}
Boolean CFGregorianDateIsValid(CFGregorianDate gdate, CFOptionFlags unitFlags) {
if ((unitFlags & kCFGregorianUnitsYears) && (gdate.year <= 0)) return false;
if ((unitFlags & kCFGregorianUnitsMonths) && (gdate.month < 1 || 12 < gdate.month)) return false;
if ((unitFlags & kCFGregorianUnitsDays) && (gdate.day < 1 || 31 < gdate.day)) return false;
if ((unitFlags & kCFGregorianUnitsHours) && (gdate.hour < 0 || 23 < gdate.hour)) return false;
if ((unitFlags & kCFGregorianUnitsMinutes) && (gdate.minute < 0 || 59 < gdate.minute)) return false;
if ((unitFlags & kCFGregorianUnitsSeconds) && (gdate.second < 0.0 || 60.0 <= gdate.second)) return false;
if ((unitFlags & kCFGregorianUnitsDays) && (unitFlags & kCFGregorianUnitsMonths) && (unitFlags & kCFGregorianUnitsYears) && (__CFDaysInMonth(gdate.month, gdate.year - 2001, isleap(gdate.year - 2001)) < gdate.day)) return false;
return true;
}
CFAbsoluteTime CFGregorianDateGetAbsoluteTime(CFGregorianDate gdate, CFTimeZoneRef tz) {
CFAbsoluteTime at;
CFTimeInterval offset0, offset1;
if (NULL != tz) {
__CFGenericValidateType(tz, CFTimeZoneGetTypeID());
}
at = 86400.0 * __CFAbsoluteFromYMD(gdate.year - 2001, gdate.month, gdate.day);
at += 3600.0 * gdate.hour + 60.0 * gdate.minute + gdate.second;
if (NULL != tz) {
offset0 = CFTimeZoneGetSecondsFromGMT(tz, at);
offset1 = CFTimeZoneGetSecondsFromGMT(tz, at - offset0);
at -= offset1;
}
return at;
}
CFGregorianDate CFAbsoluteTimeGetGregorianDate(CFAbsoluteTime at, CFTimeZoneRef tz) {
CFGregorianDate gdate;
int64_t absolute, year;
int8_t month, day;
CFAbsoluteTime fixedat;
if (NULL != tz) {
__CFGenericValidateType(tz, CFTimeZoneGetTypeID());
}
fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0);
absolute = (int64_t)floor(fixedat / 86400.0);
__CFYMDFromAbsolute(absolute, &year, &month, &day);
if (INT32_MAX - 2001 < year) year = INT32_MAX - 2001;
gdate.year = year + 2001;
gdate.month = month;
gdate.day = day;
gdate.hour = __CFDoubleModToInt(floor(fixedat / 3600.0), 24);
gdate.minute = __CFDoubleModToInt(floor(fixedat / 60.0), 60);
gdate.second = __CFDoubleMod(fixedat, 60);
if (0.0 == gdate.second) gdate.second = 0.0; return gdate;
}
CFAbsoluteTime CFAbsoluteTimeAddGregorianUnits(CFAbsoluteTime at, CFTimeZoneRef tz, CFGregorianUnits units) {
CFGregorianDate gdate;
CFGregorianUnits working;
CFAbsoluteTime candidate_at0, candidate_at1;
uint8_t monthdays;
if (NULL != tz) {
__CFGenericValidateType(tz, CFTimeZoneGetTypeID());
}
gdate = CFAbsoluteTimeGetGregorianDate(at, tz);
working.years = gdate.year;
working.months = gdate.month;
working.days = gdate.day;
working.years += units.years;
working.months += units.months;
while (12 < working.months) {
working.months -= 12;
working.years += 1;
}
while (working.months < 1) {
working.months += 12;
working.years -= 1;
}
monthdays = __CFDaysInMonth(working.months, working.years - 2001, isleap(working.years - 2001));
if (monthdays < working.days) {
working.days = monthdays;
}
working.days += units.days;
while (monthdays < working.days) {
working.months += 1;
if (12 < working.months) {
working.months -= 12;
working.years += 1;
}
working.days -= monthdays;
monthdays = __CFDaysInMonth(working.months, working.years - 2001, isleap(working.years - 2001));
}
while (working.days < 1) {
working.months -= 1;
if (working.months < 1) {
working.months += 12;
working.years -= 1;
}
monthdays = __CFDaysInMonth(working.months, working.years - 2001, isleap(working.years - 2001));
working.days += monthdays;
}
gdate.year = working.years;
gdate.month = working.months;
gdate.day = working.days;
candidate_at0 = CFGregorianDateGetAbsoluteTime(gdate, tz);
candidate_at1 = candidate_at0 + 3600.0 * units.hours + 60.0 * units.minutes + units.seconds;
return candidate_at1;
}
CFGregorianUnits CFAbsoluteTimeGetDifferenceAsGregorianUnits(CFAbsoluteTime at1, CFAbsoluteTime at2, CFTimeZoneRef tz, CFOptionFlags unitFlags) {
const int32_t seconds[5] = {366 * 24 * 3600, 31 * 24 * 3600, 24 * 3600, 3600, 60};
CFGregorianUnits units = {0, 0, 0, 0, 0, 0.0};
CFAbsoluteTime atold, atnew = at2;
int32_t idx, incr;
incr = (at2 < at1) ? 1 : -1;
for (idx = 0; idx < 5; idx++) {
if (unitFlags & (1 << idx)) {
((int32_t *)&units)[idx] = -3 * incr + (int32_t)((at1 - atnew) / seconds[idx]);
do {
atold = atnew;
((int32_t *)&units)[idx] += incr;
atnew = CFAbsoluteTimeAddGregorianUnits(at2, tz, units);
} while ((1 == incr && atnew <= at1) || (-1 == incr && at1 <= atnew));
((int32_t *)&units)[idx] -= incr;
atnew = atold;
}
}
if (unitFlags & kCFGregorianUnitsSeconds) {
units.seconds = at1 - atnew;
}
if (0.0 == units.seconds) units.seconds = 0.0; return units;
}
SInt32 CFAbsoluteTimeGetDayOfWeek(CFAbsoluteTime at, CFTimeZoneRef tz) {
int64_t absolute;
CFAbsoluteTime fixedat;
if (NULL != tz) {
__CFGenericValidateType(tz, CFTimeZoneGetTypeID());
}
fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0);
absolute = (int64_t)floor(fixedat / 86400.0);
return (absolute < 0) ? ((absolute + 1) % 7 + 7) : (absolute % 7 + 1);
}
SInt32 CFAbsoluteTimeGetDayOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) {
CFAbsoluteTime fixedat;
int64_t absolute, year;
int8_t month, day;
if (NULL != tz) {
__CFGenericValidateType(tz, CFTimeZoneGetTypeID());
}
fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0);
absolute = (int64_t)floor(fixedat / 86400.0);
__CFYMDFromAbsolute(absolute, &year, &month, &day);
return __CFDaysBeforeMonth(month, year, isleap(year)) + day;
}
SInt32 CFAbsoluteTimeGetWeekOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) {
int64_t absolute, year;
int8_t month, day;
CFAbsoluteTime fixedat;
if (NULL != tz) {
__CFGenericValidateType(tz, CFTimeZoneGetTypeID());
}
fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0);
absolute = (int64_t)floor(fixedat / 86400.0);
__CFYMDFromAbsolute(absolute, &year, &month, &day);
double absolute0101 = __CFAbsoluteFromYMD(year, 1, 1);
int64_t dow0101 = __CFDoubleModToInt(absolute0101, 7) + 1;
if (1 == month && day < 4) {
if ((day < 4 && 5 == dow0101) || (day < 3 && 6 == dow0101) || (day < 2 && 7 == dow0101)) {
return 53;
}
}
if (12 == month && 28 < day) {
double absolute20101 = __CFAbsoluteFromYMD(year + 1, 1, 1);
int64_t dow20101 = __CFDoubleModToInt(absolute20101, 7) + 1;
if ((28 < day && 4 == dow20101) || (29 < day && 3 == dow20101) || (30 < day && 2 == dow20101)) {
return 1;
}
}
return (__CFDaysBeforeMonth(month, year, isleap(year)) + day + (dow0101 - 11) % 7 + 2) / 7 + 1;
}