1<?php
2/* vim: set expandtab tabstop=4 shiftwidth=4: */
3/**
4 * Driver for holidays in Japanese
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   Hideyuki Shimooka <shimooka@doyouphp.jp>
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 * @see      http://www.h3.dion.ne.jp/~sakatsu/holiday_topic.htm
25 */
26
27/**
28 * Extends Date_Holidays_Driver
29 */
30require_once 'Date/Holidays/Driver.php';
31
32/**
33 * the gradient parameter of the approximate expression
34 * to calculate equinox day
35 *
36 * @access  public
37 */
38define('DATE_HOLIDAYS_EQUINOX_GRADIENT', 0.242194);
39
40/**
41 * the initial parameter of the approximate expression
42 * to calculate vernal equinox day from 1948 to 1979
43 *
44 * @access  public
45 */
46define('DATE_HOLIDAYS_VERNAL_EQUINOX_PARAM_1979', 20.8357);
47
48/**
49 * the initial parameter of the approximate expression
50 * to calculate vernal equinox day from 1980 to 2099
51 *
52 * @access  public
53 */
54define('DATE_HOLIDAYS_VERNAL_EQUINOX_PARAM_2099', 20.8431);
55
56/**
57 * the initial parameter of the approximate expression
58 * to calculate vernal equinox day from 2100 to 2150
59 *
60 * @access  public
61 */
62define('DATE_HOLIDAYS_VERNAL_EQUINOX_PARAM_2150', 21.8510);
63
64/**
65 * the initial parameter of the approximate expression
66 * to calculate autumnal equinox day from 1948 to 1979
67 *
68 * @access  public
69 */
70define('DATE_HOLIDAYS_AUTUMNAL_EQUINOX_PARAM_1979', 23.2588);
71
72/**
73 * the initial parameter of the approximate expression
74 * to calculate autumnal equinox day from 1980 to 2099
75 *
76 * @access  public
77 */
78define('DATE_HOLIDAYS_AUTUMNAL_EQUINOX_PARAM_2099', 23.2488);
79
80/**
81 * the initial parameter of the approximate expression
82 * to calculate autumnal equinox day from 2100 to 2150
83 *
84 * @access  public
85 */
86define('DATE_HOLIDAYS_AUTUMNAL_EQUINOX_PARAM_2150', 24.2488);
87
88/**
89 * class that calculates Japanese holidays
90 *
91 * @category   Date
92 * @package    Date_Holidays
93 * @subpackage Driver
94 * @author     Hideyuki Shimooka <shimooka@doyouphp.jp>
95 * @license    http://www.php.net/license/3_01.txt PHP License 3.0.1
96 * @version    CVS: $Id$
97 * @link       http://pear.php.net/package/Date_Holidays
98 * @see        http://www.h3.dion.ne.jp/~sakatsu/holiday_topic.htm
99 */
100class Date_Holidays_Driver_Japan extends Date_Holidays_Driver
101{
102    /**
103     * this driver's name
104     *
105     * @access   protected
106     * @var      string
107     */
108    var $_driverName = 'Japan';
109
110    /**
111     * a translation file name
112     *
113     * @access  private
114     */
115    var $_translationFile = null;
116
117    /**
118     * a translation locale
119     *
120     * @access  private
121     */
122    var $_translationLocale = null;
123
124    /**
125     * Constructor
126     *
127     * Use the Date_Holidays::factory() method to construct an object of a
128     * certain driver
129     *
130     * @access   protected
131     */
132    public function __construct()
133    {
134    }
135
136    /**
137     * Build the internal arrays that contain data about the calculated holidays
138     *
139     * @access   protected
140     * @return   boolean true on success, otherwise a PEAR_ErrorStack object
141     * @throws   object PEAR_ErrorStack
142     */
143    function _buildHolidays()
144    {
145        parent::_buildHolidays();
146
147        $this->_clearHolidays();
148
149        $this->_buildNewYearsDay();
150        $this->_buildComingofAgeDay();
151        $this->_buildNationalFoundationDay();
152        $this->_buildVernalEquinoxDay();
153        $this->_buildShowaDay();
154        $this->_buildConstitutionMemorialDay();
155        $this->_buildGreeneryDay();
156        $this->_buildChildrensDay();
157        $this->_buildMarineDay();
158        $this->_buildMountainDay();
159        $this->_buildRespectfortheAgedDay();
160        $this->_buildAutumnalEquinoxDay();
161        $this->_buildHealthandSportsDay();
162        $this->_buildNationalCultureDay();
163        $this->_buildLaborThanksgivingDay();
164        $this->_buildEmperorsBirthday();
165
166        $this->_buildOtherMemorialDays();
167
168        $this->_buildSubstituteHolidays();
169
170        return true;
171    }
172
173    /**
174     * Method that returns an array containing the ISO3166 codes that may possibly
175     * identify a driver.
176     *
177     * @static
178     * @access public
179     * @return array possible ISO3166 codes
180     */
181    function getISO3166Codes()
182    {
183        return array('jp', 'jpn');
184    }
185
186    /**
187     * build day of New Year's Day
188     *
189     * @access   private
190     * @return   void
191     */
192    function _buildNewYearsDay()
193    {
194        if ($this->_year >= 1949) {
195            $this->_addHoliday('newYearsDay',
196                               $this->_year . '-01-01',
197                               'New Year\'s Day');
198        }
199    }
200
201    /**
202     * build day of Coming of Age Day
203     *
204     * @access   private
205     * @return   void
206     */
207    function _buildComingofAgeDay()
208    {
209        $date = null;
210        if ($this->_year >= 2000) {
211            $date = $this->_calcNthMondayInMonth(1, 2);
212        } else if ($this->_year >= 1949) {
213            $date = $this->_year . '-01-15';
214        }
215        if (!is_null($date)) {
216            $this->_addHoliday('comingOfAgeDay',
217                               $date,
218                               'Coming of Age Day');
219        }
220    }
221
222    /**
223     * build day of National Foundation Day
224     *
225     * @access   private
226     * @return   void
227     */
228    function _buildNationalFoundationDay()
229    {
230        if ($this->_year >= 1949) {
231            $this->_addHoliday('nationalFoundationDay',
232                               $this->_year . '-02-11',
233                               'National Foundation Day');
234        }
235    }
236
237    /**
238     * build day of Vernal Equinox Day
239     *
240     * use approximate expression to calculate equinox day internally.
241     *
242     * @access   private
243     * @return   void
244     * @see      http://www.h3.dion.ne.jp/~sakatsu/holiday_topic.htm (in Japanese)
245     */
246    function _buildVernalEquinoxDay()
247    {
248        $day = null;
249        if ($this->_year >= 1948 && $this->_year <= 1979) {
250            $day = floor(DATE_HOLIDAYS_VERNAL_EQUINOX_PARAM_1979 +
251                         DATE_HOLIDAYS_EQUINOX_GRADIENT *
252                         ($this->_year - 1980) -
253                         floor(($this->_year - 1980) / 4));
254        } else if ($this->_year <= 2099) {
255            $day = floor(DATE_HOLIDAYS_VERNAL_EQUINOX_PARAM_2099 +
256                         DATE_HOLIDAYS_EQUINOX_GRADIENT *
257                         ($this->_year - 1980) -
258                         floor(($this->_year - 1980) / 4));
259        } else if ($this->_year <= 2150) {
260            $day = floor(DATE_HOLIDAYS_VERNAL_EQUINOX_PARAM_2150 +
261                         DATE_HOLIDAYS_EQUINOX_GRADIENT *
262                         ($this->_year - 1980) -
263                         floor(($this->_year - 1980) / 4));
264        }
265        if (!is_null($day)) {
266            $this->_addHoliday('vernalEquinoxDay',
267                               sprintf('%04d-%02d-%02d', $this->_year, 3, $day),
268                               'Vernal Equinox Day');
269        }
270    }
271
272    /**
273     * build day of Showa Day
274     *
275     * @access   private
276     * @return   void
277     */
278    function _buildShowaDay()
279    {
280        $internalName = null;
281        $title = null;
282        if ($this->_year >= 2007) {
283            $internalName = 'showaDay';
284            $title = 'Showa Day';
285        } else if ($this->_year >= 1989) {
286            $internalName = 'greeneryDay';
287            $title = 'Greenery Day';
288        } else if ($this->_year >= 1949) {
289            $internalName = 'showaEmperorsBirthday';
290            $title = 'Showa Emperor\'s Birthday';
291        }
292        if (!is_null($internalName)) {
293            $this->_addHoliday($internalName,
294                               $this->_year . '-04-29',
295                               $title);
296        }
297    }
298
299    /**
300     * build day of Constitution Memorial Day
301     *
302     * @access   private
303     * @return   void
304     */
305    function _buildConstitutionMemorialDay()
306    {
307        if ($this->_year >= 1949) {
308            $this->_addHoliday('constitutionMemorialDay',
309                               $this->_year . '-05-03',
310                               'Constitution Memorial Day');
311        }
312    }
313
314    /**
315     * build day of Greenery Day
316     *
317     * @access   private
318     * @return   void
319     */
320    function _buildGreeneryDay()
321    {
322        $internalName = null;
323        $title = null;
324        if ($this->_year >= 2007) {
325            $internalName = 'greeneryDay';
326            $title = 'Greenery Day';
327        } else if ($this->_year >= 1986) {
328            $date =& new Date($this->_year . '-05-04');
329            if ($date->getDayOfWeek() != 0) {
330                $internalName = 'nationalHoliday';
331                $title = 'National Holiday';
332            }
333        }
334        if (!is_null($internalName)) {
335            $this->_addHoliday($internalName,
336                               $this->_year . '-05-04',
337                               $title);
338        }
339    }
340
341    /**
342     * build day of Children's Day
343     *
344     * @access   private
345     * @return   void
346     */
347    function _buildChildrensDay()
348    {
349        if ($this->_year >= 1949) {
350            $this->_addHoliday('childrensDay',
351                               $this->_year . '-05-05',
352                               'Children\'s Day');
353        }
354    }
355
356    /**
357     * build day of Marine Day
358     *
359     * @access   private
360     * @return   void
361     */
362    function _buildMarineDay()
363    {
364        $date = null;
365        if ($this->_year >= 2003) {
366            $date = $this->_calcNthMondayInMonth(7, 3);
367        } else if ($this->_year >= 1996) {
368            $date = $this->_year . '-07-20';
369        }
370        if (!is_null($date)) {
371            $this->_addHoliday('marineDay',
372                               $date,
373                               'Marine Day');
374        }
375    }
376
377    /**
378     * build day of Mountain Day
379     *
380     * @access   private
381     * @return   void
382     */
383    function _buildMountainDay()
384    {
385        $date = null;
386        if ($this->_year >= 2016) {
387            $date = $this->_year . '-08-11';
388        }
389        if (!is_null($date)) {
390            $this->_addHoliday('mountainDay',
391                               $date,
392                               'Mountain Day');
393        }
394    }
395
396    /**
397     * build day of Respect for the Aged Day
398     *
399     * @access   private
400     * @return   void
401     */
402    function _buildRespectfortheAgedDay()
403    {
404        $date = null;
405        if ($this->_year >= 2003) {
406            $date = $this->_calcNthMondayInMonth(9, 3);
407        } else if ($this->_year >= 1966) {
408            $date = $this->_year . '-09-15';
409        }
410        if (!is_null($date)) {
411            $this->_addHoliday('respectfortheAgedDay',
412                               $date,
413                               'Respect for the Aged Day');
414        }
415    }
416
417    /**
418     * build day of Health and Sports Day
419     *
420     * @access   private
421     * @return   void
422     */
423    function _buildHealthandSportsDay()
424    {
425        $date = null;
426        if ($this->_year >= 2000) {
427            $date = $this->_calcNthMondayInMonth(10, 2);
428        } else if ($this->_year >= 1966) {
429            $date = $this->_year . '-10-10';
430        }
431        if (!is_null($date)) {
432            $this->_addHoliday('healthandSportsDay',
433                               $date,
434                               'Health and Sports Day');
435        }
436    }
437
438    /**
439     * build day of Autumnal Equinox Day
440     *
441     * use approximate expression to calculate equinox day internally.
442     *
443     * @access   private
444     * @return   void
445     * @see      http://www.h3.dion.ne.jp/~sakatsu/holiday_topic.htm (in Japanese)
446     */
447    function _buildAutumnalEquinoxDay()
448    {
449        $day = null;
450        if ($this->_year >= 1948 && $this->_year <= 1979) {
451            $day = floor(DATE_HOLIDAYS_AUTUMNAL_EQUINOX_PARAM_1979 +
452                         DATE_HOLIDAYS_EQUINOX_GRADIENT *
453                         ($this->_year - 1980) -
454                         floor(($this->_year - 1980) / 4));
455        } else if ($this->_year <= 2099) {
456            $day = floor(DATE_HOLIDAYS_AUTUMNAL_EQUINOX_PARAM_2099 +
457                         DATE_HOLIDAYS_EQUINOX_GRADIENT *
458                         ($this->_year - 1980) -
459                         floor(($this->_year - 1980) / 4));
460        } else if ($this->_year <= 2150) {
461            $day = floor(DATE_HOLIDAYS_AUTUMNAL_EQUINOX_PARAM_2150 +
462                         DATE_HOLIDAYS_EQUINOX_GRADIENT *
463                         ($this->_year - 1980) -
464                         floor(($this->_year - 1980) / 4));
465        }
466        if (!is_null($day)) {
467            $this->_addHoliday('autumnalEquinoxDay',
468                               sprintf('%04d-%02d-%02d', $this->_year, 9, $day),
469                               'Autumnal Equinox Day');
470
471            if ($this->_year >= 2003 &&
472                $this->getHolidayDate('autumnalEquinoxDay')->getDayOfWeek() == 3) {
473                $this->_addHoliday('nationalHolidayBeforeAutumnalEquinoxDay',
474                    $this->getHolidayDate('autumnalEquinoxDay')->getPrevDay(),
475                    'National Holiday before Autumnal Equinox Day');
476            }
477        }
478    }
479
480    /**
481     * build day of National Culture Day
482     *
483     * @access   private
484     * @return   void
485     */
486    function _buildNationalCultureDay()
487    {
488        if ($this->_year >= 1948) {
489            $this->_addHoliday('nationalCultureDay',
490                               $this->_year . '-11-03',
491                               'National Culture Day');
492        }
493    }
494
495    /**
496     * build day of Labor Thanksgiving Day
497     *
498     * @access   private
499     * @return   void
500     */
501    function _buildLaborThanksgivingDay()
502    {
503        if ($this->_year >= 1948) {
504            $this->_addHoliday('laborThanksgivingDay',
505                               $this->_year . '-11-23',
506                               'Labor Thanksgiving Day');
507        }
508    }
509
510    /**
511     * build day of Emperor's Birthday
512     *
513     * @access   private
514     * @return   void
515     */
516    function _buildEmperorsBirthday()
517    {
518        if ($this->_year >= 1989) {
519            $this->_addHoliday('emperorsBirthday',
520                               $this->_year . '-12-23',
521                               'Emperor\'s Birthday');
522        }
523    }
524
525    /**
526     * build day of Emperor's Birthday
527     *
528     * @access   private
529     * @return   void
530     */
531    function _buildOtherMemorialDays()
532    {
533        if ($this->_year == 1959) {
534            $this->_addHoliday('theRiteofWeddingofHIHCrownPrinceAkihito',
535                               $this->_year . '-04-10',
536                               'The Rite of Wedding of HIH Crown Prince Akihito');
537        }
538        if ($this->_year == 1989) {
539            $this->_addHoliday('theFuneralCeremonyofEmperorShowa.',
540                               $this->_year . '-02-24',
541                               'The Funeral Ceremony of Emperor Showa.');
542        }
543        if ($this->_year == 1990) {
544            $this->_addHoliday('theCeremonyoftheEnthronementof'
545                             . 'HisMajestytheEmperor(attheSeiden)',
546                               $this->_year . '-11-12',
547                               'The Ceremony of the Enthronement of ' .
548                               'His Majesty the Emperor (at the Seiden)');
549        }
550        if ($this->_year == 1993) {
551            $this->_addHoliday('theRiteofWeddingofHIHCrownPrinceNaruhito',
552                               $this->_year . '-06-09',
553                               'The Rite of Wedding of HIH Crown Prince Naruhito');
554        }
555    }
556
557    /**
558     * build day of substitute holiday
559     *
560     * @access   private
561     * @return   void
562     */
563    function _buildSubstituteHolidays()
564    {
565        // calculate 'current' substitute holidays
566        foreach ($this->_dates as $internalName => $date) {
567            if ($date->getDayOfWeek() == 0) {
568                if ($this->_year >= 2007) {
569                    while (in_array($date, $this->_dates)) {
570                        $date = $date->getNextDay();
571                    }
572                } else if ($date->getDate() >= '1973-04-12') {
573                    $date = $date->getNextDay();
574                    if (in_array($date, $this->_dates)) {
575                        continue;
576                    }
577                } else {
578                    continue;
579                }
580                if (!is_null($date)) {
581                    $name = 'substituteHolidayFor' . $internalName;
582                    $this->_addHoliday($name,
583                                       $date,
584                                       'Substitute Holiday for ' .
585                                       $this->_titles['C'][$internalName]);
586                }
587            }
588        }
589
590        // reset translated titles if set.
591        // because substitute Holidays change each year.
592        if (!is_null($this->_translationFile)) {
593            $ext = substr($this->_translationFile, -3);
594            if ($ext === 'xml') {
595                $this->addTranslationFile($this->_translationFile,
596                                          $this->_translationLocale);
597            } else if ($ext === 'ser') {
598                $this->addCompiledTranslationFile($this->_translationFile,
599                                                  $this->_translationLocale);
600            }
601        }
602    }
603
604
605    /**
606     * Add a language-file's content
607     *
608     * The language-file's content will be parsed and translations,
609     * properties, etc. for holidays will be made available with the specified
610     * locale.
611     *
612     * @param string $file   filename of the language file
613     * @param string $locale locale-code of the translation
614     *
615     * @access   public
616     * @return   boolean true on success, otherwise a PEAR_ErrorStack object
617     * @throws   object PEAR_Errorstack
618     */
619    function addTranslationFile($file, $locale)
620    {
621        $result = parent::addTranslationFile($file, $locale);
622        if (PEAR::isError($result)) {
623            return $result;
624        }
625        $this->_translationFile   = $file;
626        $this->_translationLocale = $locale;
627        return $result;
628    }
629
630    /**
631     * Add a compiled language-file's content
632     *
633     * The language-file's content will be unserialized and translations,
634     * properties, etc. for holidays will be made available with the
635     * specified locale.
636     *
637     * @param string $file   filename of the compiled language file
638     * @param string $locale locale-code of the translation
639     *
640     * @access   public
641     * @return   boolean true on success, otherwise a PEAR_ErrorStack object
642     * @throws   object PEAR_Errorstack
643     */
644    function addCompiledTranslationFile($file, $locale)
645    {
646        $result = parent::addCompiledTranslationFile($file, $locale);
647        if (PEAR::isError($result)) {
648            return $result;
649        }
650        $this->_translationFile   = $file;
651        $this->_translationLocale = $locale;
652        return $result;
653    }
654
655    /**
656     * clear all holidays
657     *
658     * @access   private
659     * @return   void
660     */
661    function _clearHolidays()
662    {
663        $this->_holidays      = array();
664        $this->_internalNames = array();
665        $this->_dates         = array();
666        $this->_titles        = array();
667    }
668}
669?>
670