]> git.saurik.com Git - apple/cf.git/blob - CFDate.c
CF-635.tar.gz
[apple/cf.git] / CFDate.c
1 /*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFDate.c
25 Copyright (c) 1998-2011, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
27 */
28
29 #include <CoreFoundation/CFDate.h>
30 #include <CoreFoundation/CFTimeZone.h>
31 #include <CoreFoundation/CFDictionary.h>
32 #include <CoreFoundation/CFArray.h>
33 #include <CoreFoundation/CFString.h>
34 #include <CoreFoundation/CFNumber.h>
35 #include "CFInternal.h"
36 #include <math.h>
37 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX
38 #include <sys/time.h>
39 #elif DEPLOYMENT_TARGET_WINDOWS
40 #else
41 #error Unknown or unspecified DEPLOYMENT_TARGET
42 #endif
43
44
45 /* cjk: The Julian Date for the reference date is 2451910.5,
46 I think, in case that's ever useful. */
47
48 #define DEFINE_CFDATE_FUNCTIONS 1
49
50 #if DEFINE_CFDATE_FUNCTIONS
51
52 const CFTimeInterval kCFAbsoluteTimeIntervalSince1970 = 978307200.0L;
53 const CFTimeInterval kCFAbsoluteTimeIntervalSince1904 = 3061152000.0L;
54
55 __private_extern__ double __CFTSRRate = 0.0;
56 static double __CF1_TSRRate = 0.0;
57
58 __private_extern__ int64_t __CFTimeIntervalToTSR(CFTimeInterval ti) {
59 if ((ti * __CFTSRRate) > INT64_MAX / 2) return (INT64_MAX / 2);
60 return (int64_t)(ti * __CFTSRRate);
61 }
62
63 __private_extern__ CFTimeInterval __CFTSRToTimeInterval(int64_t tsr) {
64 return (CFTimeInterval)((double)tsr * __CF1_TSRRate);
65 }
66
67 CFAbsoluteTime CFAbsoluteTimeGetCurrent(void) {
68 CFAbsoluteTime ret;
69 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX
70 struct timeval tv;
71 gettimeofday(&tv, NULL);
72 ret = (CFTimeInterval)tv.tv_sec - kCFAbsoluteTimeIntervalSince1970;
73 ret += (1.0E-6 * (CFTimeInterval)tv.tv_usec);
74 #elif DEPLOYMENT_TARGET_WINDOWS
75 FILETIME ft;
76 GetSystemTimeAsFileTime(&ft);
77 ret = _CFAbsoluteTimeFromFileTime(&ft);
78 #else
79 #error Unknown or unspecified DEPLOYMENT_TARGET
80 #endif
81 return ret;
82 }
83
84 __private_extern__ void __CFDateInitialize(void) {
85 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
86 struct mach_timebase_info info;
87 mach_timebase_info(&info);
88 __CFTSRRate = (1.0E9 / (double)info.numer) * (double)info.denom;
89 __CF1_TSRRate = 1.0 / __CFTSRRate;
90 #elif DEPLOYMENT_TARGET_WINDOWS
91 LARGE_INTEGER freq;
92 if (!QueryPerformanceFrequency(&freq)) {
93 HALT;
94 }
95 __CFTSRRate = (double)freq.QuadPart;
96 __CF1_TSRRate = 1.0 / __CFTSRRate;
97 #elif DEPLOYMENT_TARGET_LINUX
98 struct timespec res;
99 if (!clock_getres(CLOCK_MONOTONIC, &res)) {
100 HALT;
101 }
102 __CFTSRRate = res.tv_sec + (1000000000 * res.tv_nsec);
103 __CF1_TSRRate = 1.0 / __CFTSRRate;
104 #else
105 #error Unknown or unspecified DEPLOYMENT_TARGET
106 #endif
107 CFDateGetTypeID(); // cause side-effects
108 }
109
110 #if 1
111 struct __CFDate {
112 CFRuntimeBase _base;
113 CFAbsoluteTime _time; /* immutable */
114 };
115
116 static Boolean __CFDateEqual(CFTypeRef cf1, CFTypeRef cf2) {
117 CFDateRef date1 = (CFDateRef)cf1;
118 CFDateRef date2 = (CFDateRef)cf2;
119 if (date1->_time != date2->_time) return false;
120 return true;
121 }
122
123 static CFHashCode __CFDateHash(CFTypeRef cf) {
124 CFDateRef date = (CFDateRef)cf;
125 return (CFHashCode)(float)floor(date->_time);
126 }
127
128 static CFStringRef __CFDateCopyDescription(CFTypeRef cf) {
129 CFDateRef date = (CFDateRef)cf;
130 return CFStringCreateWithFormat(CFGetAllocator(date), NULL, CFSTR("<CFDate %p [%p]>{time = %0.09g}"), cf, CFGetAllocator(date), date->_time);
131 }
132
133 static CFTypeID __kCFDateTypeID = _kCFRuntimeNotATypeID;
134
135 static const CFRuntimeClass __CFDateClass = {
136 0,
137 "CFDate",
138 NULL, // init
139 NULL, // copy
140 NULL, // dealloc
141 __CFDateEqual,
142 __CFDateHash,
143 NULL, //
144 __CFDateCopyDescription
145 };
146
147 CFTypeID CFDateGetTypeID(void) {
148 if (_kCFRuntimeNotATypeID == __kCFDateTypeID) __kCFDateTypeID = _CFRuntimeRegisterClass(&__CFDateClass);
149 return __kCFDateTypeID;
150 }
151
152 CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at) {
153 CFDateRef memory;
154 uint32_t size;
155 size = sizeof(struct __CFDate) - sizeof(CFRuntimeBase);
156 memory = (CFDateRef)_CFRuntimeCreateInstance(allocator, CFDateGetTypeID(), size, NULL);
157 if (NULL == memory) {
158 return NULL;
159 }
160 ((struct __CFDate *)memory)->_time = at;
161 return memory;
162 }
163
164 CFTimeInterval CFDateGetAbsoluteTime(CFDateRef date) {
165 CF_OBJC_FUNCDISPATCH0(CFDateGetTypeID(), CFTimeInterval, date, "timeIntervalSinceReferenceDate");
166 __CFGenericValidateType(date, CFDateGetTypeID());
167 return date->_time;
168 }
169
170 CFTimeInterval CFDateGetTimeIntervalSinceDate(CFDateRef date, CFDateRef otherDate) {
171 CF_OBJC_FUNCDISPATCH1(CFDateGetTypeID(), CFTimeInterval, date, "timeIntervalSinceDate:", otherDate);
172 __CFGenericValidateType(date, CFDateGetTypeID());
173 __CFGenericValidateType(otherDate, CFDateGetTypeID());
174 return date->_time - otherDate->_time;
175 }
176
177 CFComparisonResult CFDateCompare(CFDateRef date, CFDateRef otherDate, void *context) {
178 CF_OBJC_FUNCDISPATCH1(CFDateGetTypeID(), CFComparisonResult, date, "compare:", otherDate);
179 __CFGenericValidateType(date, CFDateGetTypeID());
180 __CFGenericValidateType(otherDate, CFDateGetTypeID());
181 if (date->_time < otherDate->_time) return kCFCompareLessThan;
182 if (date->_time > otherDate->_time) return kCFCompareGreaterThan;
183 return kCFCompareEqualTo;
184 }
185 #endif
186
187 #endif
188
189 CF_INLINE int32_t __CFDoubleModToInt(double d, int32_t modulus) {
190 int32_t result = (int32_t)(float)floor(d - floor(d / modulus) * modulus);
191 if (result < 0) result += modulus;
192 return result;
193 }
194
195 CF_INLINE double __CFDoubleMod(double d, int32_t modulus) {
196 double result = d - floor(d / modulus) * modulus;
197 if (result < 0.0) result += (double)modulus;
198 return result;
199 }
200
201 static const uint8_t daysInMonth[16] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0, 0, 0};
202 static const uint16_t daysBeforeMonth[16] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0};
203 static const uint16_t daysAfterMonth[16] = {365, 334, 306, 275, 245, 214, 184, 153, 122, 92, 61, 31, 0, 0, 0, 0};
204
205 CF_INLINE bool isleap(int64_t year) {
206 int64_t y = (year + 1) % 400; /* correct to nearest multiple-of-400 year, then find the remainder */
207 if (y < 0) y = -y;
208 return (0 == (y & 3) && 100 != y && 200 != y && 300 != y);
209 }
210
211 /* year arg is absolute year; Gregorian 2001 == year 0; 2001/1/1 = absolute date 0 */
212 CF_INLINE uint8_t __CFDaysInMonth(int8_t month, int64_t year, bool leap) {
213 return daysInMonth[month] + (2 == month && leap);
214 }
215
216 /* year arg is absolute year; Gregorian 2001 == year 0; 2001/1/1 = absolute date 0 */
217 CF_INLINE uint16_t __CFDaysBeforeMonth(int8_t month, int64_t year, bool leap) {
218 return daysBeforeMonth[month] + (2 < month && leap);
219 }
220
221 /* year arg is absolute year; Gregorian 2001 == year 0; 2001/1/1 = absolute date 0 */
222 CF_INLINE uint16_t __CFDaysAfterMonth(int8_t month, int64_t year, bool leap) {
223 return daysAfterMonth[month] + (month < 2 && leap);
224 }
225
226 /* year arg is absolute year; Gregorian 2001 == year 0; 2001/1/1 = absolute date 0 */
227 static void __CFYMDFromAbsolute(int64_t absolute, int64_t *year, int8_t *month, int8_t *day) {
228 int64_t b = absolute / 146097; // take care of as many multiples of 400 years as possible
229 int64_t y = b * 400;
230 uint16_t ydays;
231 absolute -= b * 146097;
232 while (absolute < 0) {
233 y -= 1;
234 absolute += __CFDaysAfterMonth(0, y, isleap(y));
235 }
236 /* Now absolute is non-negative days to add to year */
237 ydays = __CFDaysAfterMonth(0, y, isleap(y));
238 while (ydays <= absolute) {
239 y += 1;
240 absolute -= ydays;
241 ydays = __CFDaysAfterMonth(0, y, isleap(y));
242 }
243 /* Now we have year and days-into-year */
244 if (year) *year = y;
245 if (month || day) {
246 int8_t m = absolute / 33 + 1; /* search from the approximation */
247 bool leap = isleap(y);
248 while (__CFDaysBeforeMonth(m + 1, y, leap) <= absolute) m++;
249 if (month) *month = m;
250 if (day) *day = absolute - __CFDaysBeforeMonth(m, y, leap) + 1;
251 }
252 }
253
254 /* year arg is absolute year; Gregorian 2001 == year 0; 2001/1/1 = absolute date 0 */
255 static double __CFAbsoluteFromYMD(int64_t year, int8_t month, int8_t day) {
256 double absolute = 0.0;
257 int64_t idx;
258 int64_t b = year / 400; // take care of as many multiples of 400 years as possible
259 absolute += b * 146097.0;
260 year -= b * 400;
261 if (year < 0) {
262 for (idx = year; idx < 0; idx++)
263 absolute -= __CFDaysAfterMonth(0, idx, isleap(idx));
264 } else {
265 for (idx = 0; idx < year; idx++)
266 absolute += __CFDaysAfterMonth(0, idx, isleap(idx));
267 }
268 /* Now add the days into the original year */
269 absolute += __CFDaysBeforeMonth(month, year, isleap(year)) + day - 1;
270 return absolute;
271 }
272
273 Boolean CFGregorianDateIsValid(CFGregorianDate gdate, CFOptionFlags unitFlags) {
274 if ((unitFlags & kCFGregorianUnitsYears) && (gdate.year <= 0)) return false;
275 if ((unitFlags & kCFGregorianUnitsMonths) && (gdate.month < 1 || 12 < gdate.month)) return false;
276 if ((unitFlags & kCFGregorianUnitsDays) && (gdate.day < 1 || 31 < gdate.day)) return false;
277 if ((unitFlags & kCFGregorianUnitsHours) && (gdate.hour < 0 || 23 < gdate.hour)) return false;
278 if ((unitFlags & kCFGregorianUnitsMinutes) && (gdate.minute < 0 || 59 < gdate.minute)) return false;
279 if ((unitFlags & kCFGregorianUnitsSeconds) && (gdate.second < 0.0 || 60.0 <= gdate.second)) return false;
280 if ((unitFlags & kCFGregorianUnitsDays) && (unitFlags & kCFGregorianUnitsMonths) && (unitFlags & kCFGregorianUnitsYears) && (__CFDaysInMonth(gdate.month, gdate.year - 2001, isleap(gdate.year - 2001)) < gdate.day)) return false;
281 return true;
282 }
283
284 CFAbsoluteTime CFGregorianDateGetAbsoluteTime(CFGregorianDate gdate, CFTimeZoneRef tz) {
285 CFAbsoluteTime at;
286 CFTimeInterval offset0, offset1;
287 if (NULL != tz) {
288 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
289 }
290 at = 86400.0 * __CFAbsoluteFromYMD(gdate.year - 2001, gdate.month, gdate.day);
291 at += 3600.0 * gdate.hour + 60.0 * gdate.minute + gdate.second;
292 if (NULL != tz) {
293 offset0 = CFTimeZoneGetSecondsFromGMT(tz, at);
294 offset1 = CFTimeZoneGetSecondsFromGMT(tz, at - offset0);
295 at -= offset1;
296 }
297 return at;
298 }
299
300 CFGregorianDate CFAbsoluteTimeGetGregorianDate(CFAbsoluteTime at, CFTimeZoneRef tz) {
301 CFGregorianDate gdate;
302 int64_t absolute, year;
303 int8_t month, day;
304 CFAbsoluteTime fixedat;
305 if (NULL != tz) {
306 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
307 }
308 fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0);
309 absolute = (int64_t)floor(fixedat / 86400.0);
310 __CFYMDFromAbsolute(absolute, &year, &month, &day);
311 if (INT32_MAX - 2001 < year) year = INT32_MAX - 2001;
312 gdate.year = year + 2001;
313 gdate.month = month;
314 gdate.day = day;
315 gdate.hour = __CFDoubleModToInt(floor(fixedat / 3600.0), 24);
316 gdate.minute = __CFDoubleModToInt(floor(fixedat / 60.0), 60);
317 gdate.second = __CFDoubleMod(fixedat, 60);
318 if (0.0 == gdate.second) gdate.second = 0.0; // stomp out possible -0.0
319 return gdate;
320 }
321
322 /* Note that the units of years and months are not equal length, but are treated as such. */
323 CFAbsoluteTime CFAbsoluteTimeAddGregorianUnits(CFAbsoluteTime at, CFTimeZoneRef tz, CFGregorianUnits units) {
324 CFGregorianDate gdate;
325 CFGregorianUnits working;
326 CFAbsoluteTime candidate_at0, candidate_at1;
327 uint8_t monthdays;
328
329 if (NULL != tz) {
330 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
331 }
332
333 /* Most people seem to expect years, then months, then days, etc.
334 to be added in that order. Thus, 27 April + (4 days, 1 month)
335 = 31 May, and not 1 June. This is also relatively predictable.
336
337 On another issue, months not being equal length, people also
338 seem to expect late day-of-month clamping (don't clamp as you
339 go through months), but clamp before adding in the days. Late
340 clamping is also more predictable given random starting points
341 and random numbers of months added (ie Jan 31 + 2 months could
342 be March 28 or March 29 in different years with aggressive
343 clamping). Proportionality (28 Feb + 1 month = 31 March) is
344 also not expected.
345
346 Also, people don't expect time zone transitions to have any
347 effect when adding years and/or months and/or days, only.
348 Hours, minutes, and seconds, though, are added in as humans
349 would experience the passing of that time. What this means
350 is that if the date, after adding years, months, and days
351 lands on some date, and then adding hours, minutes, and
352 seconds crosses a time zone transition, the time zone
353 transition is accounted for. If adding years, months, and
354 days gets the date into a different time zone offset period,
355 that transition is not taken into account.
356 */
357 gdate = CFAbsoluteTimeGetGregorianDate(at, tz);
358 /* We must work in a CFGregorianUnits, because the fields in the CFGregorianDate can easily overflow */
359 working.years = gdate.year;
360 working.months = gdate.month;
361 working.days = gdate.day;
362 working.years += units.years;
363 working.months += units.months;
364 while (12 < working.months) {
365 working.months -= 12;
366 working.years += 1;
367 }
368 while (working.months < 1) {
369 working.months += 12;
370 working.years -= 1;
371 }
372 monthdays = __CFDaysInMonth(working.months, working.years - 2001, isleap(working.years - 2001));
373 if (monthdays < working.days) { /* Clamp day to new month */
374 working.days = monthdays;
375 }
376 working.days += units.days;
377 while (monthdays < working.days) {
378 working.months += 1;
379 if (12 < working.months) {
380 working.months -= 12;
381 working.years += 1;
382 }
383 working.days -= monthdays;
384 monthdays = __CFDaysInMonth(working.months, working.years - 2001, isleap(working.years - 2001));
385 }
386 while (working.days < 1) {
387 working.months -= 1;
388 if (working.months < 1) {
389 working.months += 12;
390 working.years -= 1;
391 }
392 monthdays = __CFDaysInMonth(working.months, working.years - 2001, isleap(working.years - 2001));
393 working.days += monthdays;
394 }
395 gdate.year = working.years;
396 gdate.month = working.months;
397 gdate.day = working.days;
398 /* Roll in hours, minutes, and seconds */
399 candidate_at0 = CFGregorianDateGetAbsoluteTime(gdate, tz);
400 candidate_at1 = candidate_at0 + 3600.0 * units.hours + 60.0 * units.minutes + units.seconds;
401 /* If summing in the hours, minutes, and seconds delta pushes us
402 * into a new time zone offset, that will automatically be taken
403 * care of by the fact that we just add the raw time above. To
404 * undo that effect, we'd have to get the time zone offsets for
405 * candidate_at0 and candidate_at1 here, and subtract the
406 * difference (offset1 - offset0) from candidate_at1. */
407 return candidate_at1;
408 }
409
410 /* at1 - at2. The only constraint here is that this needs to be the inverse
411 of CFAbsoluteTimeByAddingGregorianUnits(), but that's a very rigid constraint.
412 Unfortunately, due to the nonuniformity of the year and month units, this
413 inversion essentially has to approximate until it finds the answer. */
414 CFGregorianUnits CFAbsoluteTimeGetDifferenceAsGregorianUnits(CFAbsoluteTime at1, CFAbsoluteTime at2, CFTimeZoneRef tz, CFOptionFlags unitFlags) {
415 const int32_t seconds[5] = {366 * 24 * 3600, 31 * 24 * 3600, 24 * 3600, 3600, 60};
416 CFGregorianUnits units = {0, 0, 0, 0, 0, 0.0};
417 CFAbsoluteTime atold, atnew = at2;
418 int32_t idx, incr;
419 incr = (at2 < at1) ? 1 : -1;
420 /* Successive approximation: years, then months, then days, then hours, then minutes. */
421 for (idx = 0; idx < 5; idx++) {
422 if (unitFlags & (1 << idx)) {
423 ((int32_t *)&units)[idx] = -3 * incr + (int32_t)((at1 - atnew) / seconds[idx]);
424 do {
425 atold = atnew;
426 ((int32_t *)&units)[idx] += incr;
427 atnew = CFAbsoluteTimeAddGregorianUnits(at2, tz, units);
428 } while ((1 == incr && atnew <= at1) || (-1 == incr && at1 <= atnew));
429 ((int32_t *)&units)[idx] -= incr;
430 atnew = atold;
431 }
432 }
433 if (unitFlags & kCFGregorianUnitsSeconds) {
434 units.seconds = at1 - atnew;
435 }
436 if (0.0 == units.seconds) units.seconds = 0.0; // stomp out possible -0.0
437 return units;
438 }
439
440 SInt32 CFAbsoluteTimeGetDayOfWeek(CFAbsoluteTime at, CFTimeZoneRef tz) {
441 int64_t absolute;
442 CFAbsoluteTime fixedat;
443 if (NULL != tz) {
444 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
445 }
446 fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0);
447 absolute = (int64_t)floor(fixedat / 86400.0);
448 return (absolute < 0) ? ((absolute + 1) % 7 + 7) : (absolute % 7 + 1); /* Monday = 1, etc. */
449 }
450
451 SInt32 CFAbsoluteTimeGetDayOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) {
452 CFAbsoluteTime fixedat;
453 int64_t absolute, year;
454 int8_t month, day;
455 if (NULL != tz) {
456 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
457 }
458 fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0);
459 absolute = (int64_t)floor(fixedat / 86400.0);
460 __CFYMDFromAbsolute(absolute, &year, &month, &day);
461 return __CFDaysBeforeMonth(month, year, isleap(year)) + day;
462 }
463
464 /* "the first week of a year is the one which includes the first Thursday" (ISO 8601) */
465 SInt32 CFAbsoluteTimeGetWeekOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) {
466 int64_t absolute, year;
467 int8_t month, day;
468 CFAbsoluteTime fixedat;
469 if (NULL != tz) {
470 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
471 }
472 fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0);
473 absolute = (int64_t)floor(fixedat / 86400.0);
474 __CFYMDFromAbsolute(absolute, &year, &month, &day);
475 double absolute0101 = __CFAbsoluteFromYMD(year, 1, 1);
476 int64_t dow0101 = __CFDoubleModToInt(absolute0101, 7) + 1;
477 /* First three and last three days of a year can end up in a week of a different year */
478 if (1 == month && day < 4) {
479 if ((day < 4 && 5 == dow0101) || (day < 3 && 6 == dow0101) || (day < 2 && 7 == dow0101)) {
480 return 53;
481 }
482 }
483 if (12 == month && 28 < day) {
484 double absolute20101 = __CFAbsoluteFromYMD(year + 1, 1, 1);
485 int64_t dow20101 = __CFDoubleModToInt(absolute20101, 7) + 1;
486 if ((28 < day && 4 == dow20101) || (29 < day && 3 == dow20101) || (30 < day && 2 == dow20101)) {
487 return 1;
488 }
489 }
490 /* Days into year, plus a week-shifting correction, divided by 7. First week is 1. */
491 return (__CFDaysBeforeMonth(month, year, isleap(year)) + day + (dow0101 - 11) % 7 + 2) / 7 + 1;
492 }
493
494