1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
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: Shane Caraveo <shane@caraveo.com> |
16 : | Colin Viebrock <colin@easydns.com> |
17 : | Hartmut Holzgraefe <hholzgra@php.net> |
18 : +----------------------------------------------------------------------+
19 : */
20 : /* $Id: */
21 :
22 : #include "php.h"
23 : #include "php_calendar.h"
24 : #include "sdncal.h"
25 : #include <time.h>
26 :
27 : static void _cal_easter(INTERNAL_FUNCTION_PARAMETERS, int gm)
28 7 : {
29 :
30 : /* based on code by Simon Kershaw, <webmaster@ely.anglican.org> */
31 :
32 : struct tm te;
33 : long year, golden, solar, lunar, pfm, dom, tmp, easter;
34 7 : long method = CAL_EASTER_DEFAULT;
35 :
36 : /* Default to the current year if year parameter is not given */
37 : {
38 : time_t a;
39 : struct tm b, *res;
40 7 : time(&a);
41 7 : res = php_localtime_r(&a, &b);
42 7 : if (!res) {
43 0 : year = 1900;
44 : } else {
45 7 : year = 1900 + b.tm_year;
46 : }
47 : }
48 :
49 7 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
50 : "|ll", &year, &method) == FAILURE) {
51 0 : return;
52 : }
53 :
54 7 : if (gm && (year<1970 || year>2037)) { /* out of range for timestamps */
55 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "This function is only valid for years between 1970 and 2037 inclusive");
56 1 : RETURN_FALSE;
57 : }
58 :
59 6 : golden = (year % 19) + 1; /* the Golden number */
60 :
61 7 : if ((year <= 1582 && method != CAL_EASTER_ALWAYS_GREGORIAN) ||
62 : (year >= 1583 && year <= 1752 && method != CAL_EASTER_ROMAN && method != CAL_EASTER_ALWAYS_GREGORIAN) ||
63 : method == CAL_EASTER_ALWAYS_JULIAN) { /* JULIAN CALENDAR */
64 :
65 1 : dom = (year + (year/4) + 5) % 7; /* the "Dominical number" - finding a Sunday */
66 1 : if (dom < 0) {
67 0 : dom += 7;
68 : }
69 :
70 1 : pfm = (3 - (11*golden) - 7) % 30; /* uncorrected date of the Paschal full moon */
71 1 : if (pfm < 0) {
72 1 : pfm += 30;
73 : }
74 : } else { /* GREGORIAN CALENDAR */
75 5 : dom = (year + (year/4) - (year/100) + (year/400)) % 7; /* the "Domincal number" */
76 5 : if (dom < 0) {
77 0 : dom += 7;
78 : }
79 :
80 5 : solar = (year-1600)/100 - (year-1600)/400; /* the solar and lunar corrections */
81 5 : lunar = (((year-1400) / 100) * 8) / 25;
82 :
83 5 : pfm = (3 - (11*golden) + solar - lunar) % 30; /* uncorrected date of the Paschal full moon */
84 5 : if (pfm < 0) {
85 5 : pfm += 30;
86 : }
87 : }
88 :
89 6 : if ((pfm == 29) || (pfm == 28 && golden > 11)) { /* corrected date of the Paschal full moon */
90 1 : pfm--; /* - days after 21st March */
91 : }
92 :
93 6 : tmp = (4-pfm-dom) % 7;
94 6 : if (tmp < 0) {
95 5 : tmp += 7;
96 : }
97 :
98 6 : easter = pfm + tmp + 1; /* Easter as the number of days after 21st March */
99 :
100 6 : if (gm) { /* return a timestamp */
101 3 : te.tm_isdst = -1;
102 3 : te.tm_year = year-1900;
103 3 : te.tm_sec = 0;
104 3 : te.tm_min = 0;
105 3 : te.tm_hour = 0;
106 :
107 3 : if (easter < 11) {
108 1 : te.tm_mon = 2; /* March */
109 1 : te.tm_mday = easter+21;
110 : } else {
111 2 : te.tm_mon = 3; /* April */
112 2 : te.tm_mday = easter-10;
113 : }
114 :
115 3 : Z_LVAL_P(return_value) = mktime(&te);
116 : } else { /* return the days after March 21 */
117 3 : Z_LVAL_P(return_value) = easter;
118 : }
119 :
120 6 : Z_TYPE_P(return_value) = IS_LONG;
121 :
122 : }
123 :
124 : /* {{{ proto int easter_date([int year]) U
125 : Return the timestamp of midnight on Easter of a given year (defaults to current year) */
126 : PHP_FUNCTION(easter_date)
127 4 : {
128 4 : _cal_easter(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
129 4 : }
130 : /* }}} */
131 :
132 : /* {{{ proto int easter_days([int year, [int method]]) U
133 : Return the number of days after March 21 that Easter falls on for a given year (defaults to current year) */
134 : PHP_FUNCTION(easter_days)
135 3 : {
136 3 : _cal_easter(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
137 3 : }
138 : /* }}} */
139 :
140 : /*
141 : * Local variables:
142 : * tab-width: 4
143 : * c-basic-offset: 4
144 : * End:
145 : */
|