1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2017 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
_cal_easter(INTERNAL_FUNCTION_PARAMETERS,zend_long gm)27 static void _cal_easter(INTERNAL_FUNCTION_PARAMETERS, zend_long gm)
28 {
29
30 /* based on code by Simon Kershaw, <webmaster@ely.anglican.org> */
31
32 struct tm te;
33 zend_long year, golden, solar, lunar, pfm, dom, tmp, easter, result;
34 zend_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 time(&a);
41 res = php_localtime_r(&a, &b);
42 if (!res) {
43 year = 1900;
44 } else {
45 year = 1900 + b.tm_year;
46 }
47 }
48
49 if (zend_parse_parameters(ZEND_NUM_ARGS(),
50 "|ll", &year, &method) == FAILURE) {
51 return;
52 }
53
54 if (gm && (year<1970 || year>2037)) { /* out of range for timestamps */
55 php_error_docref(NULL, E_WARNING, "This function is only valid for years between 1970 and 2037 inclusive");
56 RETURN_FALSE;
57 }
58
59 golden = (year % 19) + 1; /* the Golden number */
60
61 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 dom = (year + (year/4) + 5) % 7; /* the "Dominical number" - finding a Sunday */
66 if (dom < 0) {
67 dom += 7;
68 }
69
70 pfm = (3 - (11*golden) - 7) % 30; /* uncorrected date of the Paschal full moon */
71 if (pfm < 0) {
72 pfm += 30;
73 }
74 } else { /* GREGORIAN CALENDAR */
75 dom = (year + (year/4) - (year/100) + (year/400)) % 7; /* the "Domincal number" */
76 if (dom < 0) {
77 dom += 7;
78 }
79
80 solar = (year-1600)/100 - (year-1600)/400; /* the solar and lunar corrections */
81 lunar = (((year-1400) / 100) * 8) / 25;
82
83 pfm = (3 - (11*golden) + solar - lunar) % 30; /* uncorrected date of the Paschal full moon */
84 if (pfm < 0) {
85 pfm += 30;
86 }
87 }
88
89 if ((pfm == 29) || (pfm == 28 && golden > 11)) { /* corrected date of the Paschal full moon */
90 pfm--; /* - days after 21st March */
91 }
92
93 tmp = (4-pfm-dom) % 7;
94 if (tmp < 0) {
95 tmp += 7;
96 }
97
98 easter = pfm + tmp + 1; /* Easter as the number of days after 21st March */
99
100 if (gm) { /* return a timestamp */
101 te.tm_isdst = -1;
102 te.tm_year = year-1900;
103 te.tm_sec = 0;
104 te.tm_min = 0;
105 te.tm_hour = 0;
106
107 if (easter < 11) {
108 te.tm_mon = 2; /* March */
109 te.tm_mday = easter+21;
110 } else {
111 te.tm_mon = 3; /* April */
112 te.tm_mday = easter-10;
113 }
114 result = mktime(&te);
115 } else { /* return the days after March 21 */
116 result = easter;
117 }
118 ZVAL_LONG(return_value, result);
119 }
120
121 /* {{{ proto int easter_date([int year])
122 Return the timestamp of midnight on Easter of a given year (defaults to current year) */
PHP_FUNCTION(easter_date)123 PHP_FUNCTION(easter_date)
124 {
125 _cal_easter(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
126 }
127 /* }}} */
128
129 /* {{{ proto int easter_days([int year, [int method]])
130 Return the number of days after March 21 that Easter falls on for a given year (defaults to current year) */
PHP_FUNCTION(easter_days)131 PHP_FUNCTION(easter_days)
132 {
133 _cal_easter(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
134 }
135 /* }}} */
136
137 /*
138 * Local variables:
139 * tab-width: 4
140 * c-basic-offset: 4
141 * End:
142 */
143