1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2007 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,v 1.8.2.3.2.3 2007/01/01 09:35:48 sebastian Exp $ */
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 3 : {
28 3 : timelib_sll i = j - 17;
29 3 : timelib_sll c = (4 - i * 2 + (i + 1) / 4) % 7;
30 :
31 3 : 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 3 : {
36 : timelib_sll c1, y1, m1, dow;
37 :
38 : /* Only valid for Gregorian calendar */
39 3 : if (y < 1753) {
40 0 : return -1;
41 : }
42 3 : c1 = century_value(y / 100);
43 3 : y1 = (y % 100);
44 3 : m1 = timelib_is_leap(y) ? m_table_leap[m] : m_table_common[m];
45 3 : dow = (c1 + y1 + m1 + (y1 / 4) + d) % 7;
46 3 : if (iso) {
47 0 : if (dow == 0) {
48 0 : dow = 7;
49 : }
50 : }
51 3 : return dow;
52 : }
53 :
54 : timelib_sll timelib_day_of_week(timelib_sll y, timelib_sll m, timelib_sll d)
55 3 : {
56 3 : return timelib_day_of_week_ex(y, m, d, 0);
57 : }
58 :
59 : timelib_sll timelib_iso_day_of_week(timelib_sll y, timelib_sll m, timelib_sll d)
60 0 : {
61 0 : return timelib_day_of_week_ex(y, m, d, 1);
62 : }
63 :
64 : /* jan feb mar apr may jun jul aug sep oct nov dec */
65 : static int d_table_common[13] = { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
66 : static int d_table_leap[13] = { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
67 : static int ml_table_common[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
68 : static int ml_table_leap[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
69 :
70 : timelib_sll timelib_day_of_year(timelib_sll y, timelib_sll m, timelib_sll d)
71 1 : {
72 1 : return (timelib_is_leap(y) ? d_table_leap[m] : d_table_common[m]) + d - 1;
73 : }
74 :
75 : timelib_sll timelib_days_in_month(timelib_sll y, timelib_sll m)
76 0 : {
77 0 : return timelib_is_leap(y) ? ml_table_leap[m] : ml_table_common[m];
78 : }
79 :
80 : void timelib_isoweek_from_date(timelib_sll y, timelib_sll m, timelib_sll d, timelib_sll *iw, timelib_sll *iy)
81 1 : {
82 : int y_leap, prev_y_leap, doy, jan1weekday, weekday;
83 :
84 1 : y_leap = timelib_is_leap(y);
85 1 : prev_y_leap = timelib_is_leap(y-1);
86 1 : doy = timelib_day_of_year(y, m, d) + 1;
87 1 : if (y_leap && m > 2) {
88 0 : doy++;
89 : }
90 1 : jan1weekday = timelib_day_of_week(y, 1, 1);
91 1 : weekday = timelib_day_of_week(y, m, d);
92 1 : if (weekday == 0) weekday = 7;
93 1 : if (jan1weekday == 0) jan1weekday = 7;
94 : /* Find if Y M D falls in YearNumber Y-1, WeekNumber 52 or 53 */
95 1 : if (doy <= (8 - jan1weekday) && jan1weekday > 4) {
96 0 : *iy = y - 1;
97 0 : if (jan1weekday == 5 || (jan1weekday == 6 && prev_y_leap)) {
98 0 : *iw = 53;
99 : } else {
100 0 : *iw = 52;
101 : }
102 : } else {
103 1 : *iy = y;
104 : }
105 : /* 8. Find if Y M D falls in YearNumber Y+1, WeekNumber 1 */
106 1 : if (*iy == y) {
107 : int i;
108 :
109 1 : i = y_leap ? 366 : 365;
110 1 : if ((i - (doy - y_leap)) < (4 - weekday)) {
111 0 : *iy = y + 1;
112 0 : *iw = 1;
113 0 : return;
114 : }
115 : }
116 : /* 9. Find if Y M D falls in YearNumber Y, WeekNumber 1 through 53 */
117 1 : if (*iy == y) {
118 : int j;
119 :
120 1 : j = doy + (7 - weekday) + (jan1weekday - 1);
121 1 : *iw = j / 7;
122 1 : if (jan1weekday > 4) {
123 0 : *iw -= 1;
124 : }
125 : }
126 : }
127 :
128 : timelib_sll timelib_daynr_from_weeknr(timelib_sll y, timelib_sll w, timelib_sll d)
129 0 : {
130 : timelib_sll dow, day;
131 :
132 : /* Figure out the dayofweek for y-1-1 */
133 0 : dow = timelib_day_of_week(y, 1, 1);
134 : /* then use that to figure out the offset for day 1 of week 1 */
135 0 : day = 0 - (dow > 4 ? dow - 7 : dow);
136 :
137 : /* Add weeks and days */
138 0 : return day + ((w - 1) * 7) + d;
139 : }
140 :
141 : #if 0
142 : int main(void)
143 : {
144 : printf("dow = %d\n", timelib_day_of_week(1978, 12, 22)); /* 5 */
145 : printf("dow = %d\n", timelib_day_of_week(2005, 2, 19)); /* 6 */
146 : }
147 : #endif
|