1<?php
2/* vim: set expandtab tabstop=4 shiftwidth=4: */
3/**
4 * Driver for Christian holidays
5 *
6 * PHP Version 5
7 *
8 * Copyright (c) 1997-2008 The PHP Group
9 *
10 * This source file is subject to version 3.0 of the PHP license,
11 * that is bundled with this package in the file LICENSE, and is
12 * available at through the world-wide-web at
13 * http://www.php.net/license/3_01.txt.
14 * If you did not receive a copy of the PHP license and are unable to
15 * obtain it through the world-wide-web, please send a note to
16 * license@php.net so we can mail you a copy immediately.
17 *
18 * @category Date
19 * @package  Date_Holidays
20 * @author   Carsten Lucke <luckec@tool-garage.de>
21 * @license  http://www.php.net/license/3_01.txt PHP License 3.0.1
22 * @version  CVS: $Id$
23 * @link     http://pear.php.net/package/Date_Holidays
24 */
25
26/**
27 * class that calculates Christian holidays
28 *
29 * @category   Date
30 * @package    Date_Holidays
31 * @subpackage Driver
32 * @author     Carsten Lucke <luckec@tool-garage.de>
33 * @license    http://www.php.net/license/3_01.txt PHP License 3.0.1
34 * @version    CVS: $Id$
35 * @link       http://pear.php.net/package/Date_Holidays
36 */
37class Date_Holidays_Driver_Christian extends Date_Holidays_Driver
38{
39    /**
40     * this driver's name
41     *
42     * @access   protected
43     * @var      string
44     */
45    var $_driverName = 'Christian';
46
47    /**
48     * Constructor
49     *
50     * Use the Date_Holidays::factory() method to construct an object of a
51     * certain driver
52     *
53     * @access   protected
54     */
55    function Date_Holidays_Driver_Christian()
56    {
57    }
58
59    /**
60     * Build the internal arrays that contain data about the calculated holidays
61     *
62     * @access   protected
63     * @return   boolean true on success, otherwise a PEAR_ErrorStack object
64     * @throws   object PEAR_ErrorStack
65     */
66    function _buildHolidays()
67    {
68        /**
69         * Circumcision of Jesus
70         */
71        $this->_addHoliday('jesusCircumcision',
72                           $this->_year . '-01-01',
73                           'Circumcision of Jesus');
74
75        /**
76         * Epiphanias
77         */
78        $this->_addHoliday('epiphany', $this->_year . '-01-06', 'Epiphany');
79
80        /**
81         * Cleaning of Mariä
82         */
83        $this->_addHoliday('mariaCleaning',
84                           $this->_year . '-02-02',
85                           'Cleaning of Maria');
86
87        /**
88         * Josef's Day
89         */
90        $this->_addHoliday('josefsDay',
91                           $this->_year . '-03-19',
92                           'Josef\'s Day');
93
94        /**
95         * Maria Announcement
96         */
97        $this->_addHoliday('mariaAnnouncement',
98                            $this->_year . '-03-25',
99                            'Maria Announcement');
100
101        /**
102         * Easter Sunday
103         */
104        $easterDate = Date_Holidays_Driver_Christian::calcEaster($this->_year);
105        $this->_addHoliday('easter', $easterDate, 'Easter Sunday');
106
107        /**
108         * Palm Sunday
109         */
110        $palmSundayDate = $this->_addDays($easterDate, -7);
111        $this->_addHoliday('palmSunday', $palmSundayDate, 'Palm Sunday');
112
113        /**
114         * Passion Sunday
115         */
116        $passionSundayDate = $this->_addDays($palmSundayDate, -7);
117        $this->_addHoliday('passionSunday', $passionSundayDate, 'Passion Sunday');
118
119        /**
120         * Painful Friday
121         */
122        $painfulFridayDate = $this->_addDays($palmSundayDate, -2);
123        $this->_addHoliday('painfulFriday', $painfulFridayDate, 'Painful Friday');
124
125        /**
126         * White Sunday
127         */
128        $whiteSundayDate = $this->_addDays($easterDate, 7);
129        $this->_addHoliday('whiteSunday', $whiteSundayDate, 'White Sunday');
130
131        /**
132         * Ash Wednesday
133         */
134        $ashWednesdayDate = $this->_addDays($easterDate, -46);
135        $this->_addHoliday('ashWednesday', $ashWednesdayDate, 'Ash Wednesday');
136
137        /**
138         * Good Friday / Black Friday
139         */
140        $goodFridayDate = $this->_addDays($easterDate, -2);
141        $this->_addHoliday('goodFriday', $goodFridayDate, 'Good Friday');
142
143        /**
144         * Green Thursday
145         */
146        $this->_addHoliday('greenThursday',
147                           $goodFridayDate->getPrevDay(),
148                           'Green Thursday');
149
150        /**
151         * Easter Monday
152         */
153        $this->_addHoliday('easterMonday',
154                           $easterDate->getNextDay(),
155                           'Easter Monday');
156
157        /**
158         * Whitsun (determines Whit Monday, Ascension Day and
159         * Feast of Corpus Christi)
160         */
161        $whitsunDate = $this->_addDays($easterDate, 49);
162        $this->_addHoliday('whitsun', $whitsunDate, 'Whitsun');
163
164        /**
165         * Request Sunday
166         */
167        $requestSunday = $this->_addDays($whitsunDate, -14);
168        $this->_addHoliday('requestSunday', $requestSunday, 'Request Sunday');
169
170        /**
171         * Ascension Day
172         */
173        $ascensionDayDate = $this->_addDays($whitsunDate, -10);
174        $this->_addHoliday('ascensionDay', $ascensionDayDate, 'Ascension Day');
175
176        /**
177         * Whit Monday
178         */
179        $this->_addHoliday('whitMonday', $whitsunDate->getNextDay(), 'Whit Monday');
180
181        /**
182         * Haunting of Mariä
183         */
184        $this->_addHoliday('mariaHaunting',
185                           $this->_year . '-05-31',
186                           'Haunting of Maria');
187
188        /**
189         * Trinitatis
190         */
191        $trinitatisDate = $this->_addDays($whitsunDate, 7);
192        $this->_addHoliday('trinitatis',
193                           $trinitatisDate,
194                           'Trinitatis');
195
196        /**
197         * Feast of Corpus Christi
198         */
199        $corpusChristiDate = $this->_addDays($whitsunDate, 11);
200        $this->_addHoliday('corpusChristi',
201                           $corpusChristiDate,
202                           'Feast of Corpus Christi');
203
204        /**
205         * Heart of Jesus
206         *
207         * Friday of the 3rd week past Whitsun
208         */
209        $heartJesusDate = $this->_addDays($whitsunDate, 19);
210        $this->_addHoliday('heartJesus',
211                           $heartJesusDate,
212                           'Heart of Jesus celebration');
213
214        /**
215         * Johannis celebration
216         */
217        $this->_addHoliday('johannisCelebration',
218                           $this->_year . '-06-24',
219                           'Johannis celebration');
220
221        /**
222         * Petrus and Paulus
223         */
224        $this->_addHoliday('petrusAndPaulus',
225                           $this->_year . '-06-29',
226                           'Petrus and Paulus');
227
228        /**
229         * Ascension of Maria
230         */
231        $this->_addHoliday('mariaAscension',
232                           $this->_year . '-08-15',
233                           'Ascension of Maria');
234
235        /**
236         * Celebration of raising the Cross
237         */
238        $this->_addHoliday('crossRaising',
239                           $this->_year . '-09-14',
240                           'Celebration of raising the Cross');
241
242        /**
243         * Thanks Giving
244         *
245         * Sunday past Michaelis (29. September)
246         */
247        $michaelisDate = new Date($this->_year . '-09-29');
248        $dayOfWeek     = $michaelisDate->getDayOfWeek();
249        $michaelisDate = $this->_addDays($michaelisDate, 7 - $dayOfWeek);
250        $thanksGivingDate = $michaelisDate;
251        $this->_addHoliday('thanksGiving', $thanksGivingDate, 'Thanks Giving');
252
253        /**
254         * Kermis
255         *
256         * 3rd Sunday in October
257         */
258        $kermisDate = new Date($this->_year . '-10-01');
259        $dayOfWeek  = $kermisDate->getDayOfWeek();
260        if ($dayOfWeek != 0) {
261            $kermisDate = $this->_addDays($kermisDate, 7 - $dayOfWeek);
262        }
263        $kermisDate = $this->_addDays($kermisDate, 14);
264        $this->_addHoliday('kermis', $kermisDate, 'Kermis');
265
266        /**
267         * Reformation Day
268         */
269        $this->_addHoliday('reformationDay',
270                           $this->_year . '-10-31',
271                           'Reformation Day');
272
273        /**
274         * All Saints' Day
275         */
276        $this->_addHoliday('allSaintsDay',
277                           $this->_year . '-11-01',
278                           'All Saints\' Day');
279
280        /**
281         * All Souls' Day
282         */
283        $this->_addHoliday('allSoulsDay',
284                            $this->_year . '-11-02',
285                            'All Souls\' Day');
286
287        /**
288         * Martin's Day
289         */
290        $this->_addHoliday('martinsDay', $this->_year . '-11-11', 'Martin\'s Day');
291
292        /**
293         * 4th Advent
294         */
295        $Advent4Date = new Date($this->_year . '-12-25');
296        $dayOfWeek   = $Advent4Date->getDayOfWeek();
297        if ($dayOfWeek == 0) {
298            $dayOfWeek = 7;
299        }
300        $Advent4Date = $this->_addDays($Advent4Date, -$dayOfWeek);
301        $this->_addHoliday('advent4', $Advent4Date, '4th Advent');
302
303        /**
304         * 1st Advent
305         */
306        $Advent1Date = $this->_addDays($Advent4Date, -21);
307        $this->_addHoliday('advent1', $Advent1Date, '1st Advent');
308
309        /**
310         * 2nd Advent
311         */
312        $Advent2Date = $this->_addDays($Advent4Date, -14);
313        $this->_addHoliday('advent2', $Advent2Date, '2nd Advent');
314
315        /**
316         * 3rd Advent
317         */
318        $Advent3Date = $this->_addDays($Advent4Date, -7);
319        $this->_addHoliday('advent3', $Advent3Date, '3rd Advent');
320
321        /**
322         * Death' Sunday
323         */
324        $deathSundayDate = $this->_addDays($Advent1Date, -7);
325        $this->_addHoliday('deathSunday', $deathSundayDate, 'Death\' Sunday');
326
327        /**
328         * Day of Repentance
329         */
330        $dayOfRepentance = $this->_addDays($deathSundayDate, -4);
331        $this->_addHoliday('dayOfRepentance', $dayOfRepentance, 'Day of Repentance');
332
333        /**
334         * St. Nicholas' Day
335         */
336        $this->_addHoliday('stNicholasDay',
337                           $this->_year . '-12-06',
338                           'St. Nicholas\' Day');
339
340        /**
341         * Maria' conception
342         */
343        $this->_addHoliday('mariaConception',
344                           $this->_year . '-12-08',
345                           'Conception of Maria');
346
347        /**
348         * Christmas Eve
349         */
350        $this->_addHoliday('christmasEve', $this->_year . '-12-24', 'Christmas Eve');
351
352        /**
353         * Christmas day
354         */
355        $this->_addHoliday('christmasDay', $this->_year . '-12-25', 'Christmas Day');
356
357        /**
358         * Boxing day
359         */
360        $this->_addHoliday('boxingDay', $this->_year . '-12-26', 'Boxing Day');
361
362        /**
363         * New Year's Eve
364         */
365        $this->_addHoliday('newYearsEve',
366                           $this->_year . '-12-31',
367                           'New Year\'s Eve');
368
369        if (Date_Holidays::errorsOccurred()) {
370            return Date_Holidays::getErrorStack();
371        }
372        return true;
373    }
374
375    /**
376     * Calculates date for Easter using the Gaussian algorithm.
377     *
378     * @param int $year year
379     *
380     * @static
381     * @access   public
382     * @return   object Date
383     */
384    function calcEaster($year)
385    {
386        if (function_exists("easter_days")) {
387            $easter = new Date();
388            $easter->setDate(
389                strtotime("$year-03-21 + " . easter_days($year) . " days"),
390                DATE_FORMAT_UNIXTIME
391            );
392            return $easter;
393        }
394        // golden number
395        $golden  = null;
396        $century = null;
397        // 23-Epact (modulo 30)
398        $epact = null;
399        // number of days from 21 March to the Paschal Full Moon
400        $i = null;
401        // weekday of the Full Moon (0=Sunday,...)
402        $j = null;
403
404        if ($year > 1582) {
405            $golden  = $year % 19;
406            $century = floor($year / 100);
407            $l       = floor($century / 4);
408            $epact   = ($century - $l - floor((8 * $century + 13) / 25)
409                        + 19 * $golden + 15) % 30;
410            $i       = $epact - floor($epact / 28) * (1 - floor($epact / 28) *
411                       floor(29 / ($epact + 1)) * floor((21 - $golden) / 11));
412            $j       = ($year + floor($year / 4) + $i + 2 - $century + $l);
413            $j       = $j % 7;
414        } else {
415            $golden = $year % 19;
416            $i      = (19 * $golden + 15) % 30;
417            $j      = ($year + floor($year / 4) + $i) % 7;
418        }
419        $l     = $i - $j;
420        $month = 3 + floor(($l + 40) / 44);
421        $day   = $l + 28 - 31 * floor($month / 4);
422
423        $date = new Date(sprintf('%04d-%02d-%02d', $year, $month, $day));
424        return $date;
425    }
426}
427?>
428