1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Derick Rethans <derick@derickrethans.nl> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: dow.c 272374 2008-12-31 11:17:49Z sebastian $ */
20 :
21 : #include "timelib.h"
22 :
23 : static int m_table_common[13] = { -1, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 }; /* 1 = jan */
24 : static int m_table_leap[13] = { -1, 6, 2, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 }; /* 1 = jan */
25 :
26 : static timelib_sll century_value(timelib_sll j)
27 9150 : {
28 9150 : timelib_sll i = j - 17;
29 9150 : timelib_sll c = (4 - i * 2 + (i + 1) / 4) % 7;
30 :
31 9150 : return c < 0 ? c + 7 : c;
32 : }
33 :
34 : static timelib_sll timelib_day_of_week_ex(timelib_sll y, timelib_sll m, timelib_sll d, int iso)
35 9150 : {
36 : timelib_sll c1, y1, m1, dow;
37 :
38 : /* Only valid for Gregorian calendar, commented out as we don't handle
39 : * julian calendar. We just return the 'wrong' day of week to be
40 : * consistent.
41 : if (y < 1753) {
42 : return -1;
43 : } */
44 9150 : c1 = century_value(y / 100);
45 9150 : y1 = (y % 100);
46 9150 : m1 = timelib_is_leap(y) ? m_table_leap[m] : m_table_common[m];
47 9150 : dow = (c1 + y1 + m1 + (y1 / 4) + d) % 7;
48 9150 : if (iso) {
49 4 : if (dow == 0) {
50 2 : dow = 7;
51 : }
52 : }
53 9150 : return dow;
54 : }
55 :
56 : timelib_sll timelib_day_of_week(timelib_sll y, timelib_sll m, timelib_sll d)
57 9146 : {
58 9146 : return timelib_day_of_week_ex(y, m, d, 0);
59 : }
60 :
61 : timelib_sll timelib_iso_day_of_week(timelib_sll y, timelib_sll m, timelib_sll d)
62 4 : {
63 4 : return timelib_day_of_week_ex(y, m, d, 1);
64 : }
65 :
66 : /* jan feb mar apr may jun jul aug sep oct nov dec */
67 : static int d_table_common[13] = { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
68 : static int d_table_leap[13] = { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
69 : static int ml_table_common[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
70 : static int ml_table_leap[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
71 :
72 : timelib_sll timelib_day_of_year(timelib_sll y, timelib_sll m, timelib_sll d)
73 4407 : {
74 4407 : return (timelib_is_leap(y) ? d_table_leap[m] : d_table_common[m]) + d - 1;
75 : }
76 :
77 : timelib_sll timelib_days_in_month(timelib_sll y, timelib_sll m)
78 46 : {
79 46 : return timelib_is_leap(y) ? ml_table_leap[m] : ml_table_common[m];
80 : }
81 :
82 : void timelib_isoweek_from_date(timelib_sll y, timelib_sll m, timelib_sll d, timelib_sll *iw, timelib_sll *iy)
83 3993 : {
84 : int y_leap, prev_y_leap, doy, jan1weekday, weekday;
85 :
86 3993 : y_leap = timelib_is_leap(y);
87 3993 : prev_y_leap = timelib_is_leap(y-1);
88 3993 : doy = timelib_day_of_year(y, m, d) + 1;
89 3993 : if (y_leap && m > 2) {
90 609 : doy++;
91 : }
92 3993 : jan1weekday = timelib_day_of_week(y, 1, 1);
93 3993 : weekday = timelib_day_of_week(y, m, d);
94 3993 : if (weekday == 0) weekday = 7;
95 3993 : if (jan1weekday == 0) jan1weekday = 7;
96 : /* Find if Y M D falls in YearNumber Y-1, WeekNumber 52 or 53 */
97 4097 : if (doy <= (8 - jan1weekday) && jan1weekday > 4) {
98 104 : *iy = y - 1;
99 172 : if (jan1weekday == 5 || (jan1weekday == 6 && prev_y_leap)) {
100 68 : *iw = 53;
101 : } else {
102 36 : *iw = 52;
103 : }
104 : } else {
105 3889 : *iy = y;
106 : }
107 : /* 8. Find if Y M D falls in YearNumber Y+1, WeekNumber 1 */
108 3993 : if (*iy == y) {
109 : int i;
110 :
111 3889 : i = y_leap ? 366 : 365;
112 3889 : if ((i - (doy - y_leap)) < (4 - weekday)) {
113 53 : *iy = y + 1;
114 53 : *iw = 1;
115 53 : return;
116 : }
117 : }
118 : /* 9. Find if Y M D falls in YearNumber Y, WeekNumber 1 through 53 */
119 3940 : if (*iy == y) {
120 : int j;
121 :
122 3836 : j = doy + (7 - weekday) + (jan1weekday - 1);
123 3836 : *iw = j / 7;
124 3836 : if (jan1weekday > 4) {
125 1484 : *iw -= 1;
126 : }
127 : }
128 : }
129 :
130 : timelib_sll timelib_daynr_from_weeknr(timelib_sll y, timelib_sll w, timelib_sll d)
131 104 : {
132 : timelib_sll dow, day;
133 :
134 : /* Figure out the dayofweek for y-1-1 */
135 104 : dow = timelib_day_of_week(y, 1, 1);
136 : /* then use that to figure out the offset for day 1 of week 1 */
137 104 : day = 0 - (dow > 4 ? dow - 7 : dow);
138 :
139 : /* Add weeks and days */
140 104 : return day + ((w - 1) * 7) + d;
141 : }
142 :
143 : #if 0
144 : int main(void)
145 : {
146 : printf("dow = %d\n", timelib_day_of_week(1978, 12, 22)); /* 5 */
147 : printf("dow = %d\n", timelib_day_of_week(2005, 2, 19)); /* 6 */
148 : }
149 : #endif
|