Date_Holidays
[ class tree: Date_Holidays ] [ index: Date_Holidays ] [ all elements ]

Source for file Driver.php

Documentation is available at Driver.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. /**
  4.  * Driver.php
  5.  *
  6.  * PHP Version 5
  7.  *
  8.  * Copyright (c) 1997-2008 The PHP Group
  9.  *
  10.  * This source file is subject to version 2.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/2_02.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.  * Authors:   Carsten Lucke <luckec@tool-garage.de>
  19.  *
  20.  * CVS file id: $Id$
  21.  *
  22.  * @category Date
  23.  * @package  Date_Holidays
  24.  * @author   Carsten Lucke <luckec@tool-garage.de>
  25.  * @license  http://www.php.net/license/3_01.txt PHP License 3.0.1
  26.  * @version  CVS: $Id$
  27.  * @link     http://pear.php.net/package/Date_Holidays
  28.  */
  29.  
  30. /**
  31.  * DriverClass and associated defines.
  32.  *
  33.  * @abstract
  34.  * @category Date
  35.  * @package  Date_Holidays
  36.  * @author   Carsten Lucke <luckec@tool-garage.de>
  37.  * @license  http://www.php.net/license/3_01.txt PHP License 3.0.1
  38.  * @version  CVS: $Id$
  39.  * @link     http://pear.php.net/package/Date_Holidays
  40.  */
  41.  
  42. /**
  43.  * uses PEAR_Errorstack
  44.  */
  45. require_once 'PEAR/ErrorStack.php';
  46. require_once 'Date/Holidays/Filter.php';
  47. require_once 'Date/Holidays/Filter/Whitelist.php';
  48. require_once 'Date/Holidays/Filter/Blacklist.php';
  49.  
  50. /**
  51.  * invalid internal name
  52.  *
  53.  * @access  public
  54.  */
  55. define('DATE_HOLIDAYS_INVALID_INTERNAL_NAME'51);
  56.  
  57. /**
  58.  * title for a holiday is not available
  59.  *
  60.  * @access  public
  61.  */
  62. define('DATE_HOLIDAYS_TITLE_UNAVAILABLE'52);
  63.  
  64. /**
  65.  * date could not be converted into a PEAR::Date object
  66.  *
  67.  * date was neither a timestamp nor a string
  68.  *
  69.  * @access  public
  70.  * @deprecated   will certainly be removed
  71.  */
  72. define('DATE_HOLIDAYS_INVALID_DATE'53);
  73.  
  74. /**
  75.  * string that represents a date has wrong format
  76.  *
  77.  * format must be YYYY-MM-DD
  78.  *
  79.  * @access  public
  80.  * @deprecated   will certainly be removed
  81.  */
  82. define('DATE_HOLIDAYS_INVALID_DATE_FORMAT'54);
  83.  
  84. /**
  85.  * date for a holiday is not available
  86.  *
  87.  * @access  public
  88.  */
  89. define('DATE_HOLIDAYS_DATE_UNAVAILABLE'55);
  90.  
  91. /**
  92.  * language-file doesn't exist
  93.  *
  94.  * @access  public
  95.  */
  96. define('DATE_HOLIDAYS_LANGUAGEFILE_NOT_FOUND'56);
  97.  
  98. /**
  99.  * unable to read language-file
  100.  *
  101.  * @access  public
  102.  */
  103. define('DATE_HOLIDAYS_UNABLE_TO_READ_TRANSLATIONDATA'57);
  104.  
  105. /**
  106.  * Name of the static {@link Date_Holidays_Driver} method returning
  107.  * a array of possible ISO3166 codes that identify itself.
  108.  *
  109.  * @access  public
  110.  */
  111. define('DATE_HOLIDAYS_DRIVER_IDENTIFY_ISO3166_METHOD''getISO3166Codes');
  112.  
  113. /**
  114.  * class that helps you to locate holidays for a year
  115.  *
  116.  * @abstract
  117.  * @category   Date
  118.  * @package    Date_Holidays
  119.  * @subpackage Driver
  120.  * @author     Carsten Lucke <luckec@tool-garage.de>
  121.  * @license    http://www.php.net/license/3_01.txt PHP License 3.0.1
  122.  * @version    CVS: $Id$
  123.  * @link       http://pear.php.net/package/Date_Holidays
  124.  */
  125. {
  126.     /**
  127.      * this driver's name
  128.      *
  129.      * @access   protected
  130.      * @var      string 
  131.      */
  132.     var $_driverName;
  133.  
  134.     /**
  135.      * locale setting for output
  136.      *
  137.      * @access   protected
  138.      * @var      string 
  139.      */
  140.     var $_locale;
  141.  
  142.     /**
  143.      * locales for which translations of holiday titles are available
  144.      *
  145.      * @access   private
  146.      * @var      array 
  147.      */
  148.     var $_availableLocales = array('C');
  149.  
  150.     /**
  151.      * object's current year
  152.      *
  153.      * @access   protected
  154.      * @var      int 
  155.      */
  156.     var $_year;
  157.  
  158.     /**
  159.      * internal names for the available holidays
  160.      *
  161.      * @access   protected
  162.      * @var      array 
  163.      */
  164.     var $_internalNames = array();
  165.  
  166.     /**
  167.      * dates of the available holidays
  168.      *
  169.      * @access   protected
  170.      * @var      array 
  171.      */
  172.     var $_dates = array();
  173.  
  174.     /**
  175.      * array of the available holidays indexed by date
  176.      *
  177.      * @access   protected
  178.      * @var      array 
  179.      */
  180.     var $_holidays = array();
  181.  
  182.     /**
  183.      * localized names of the available holidays
  184.      *
  185.      * @access   protected
  186.      * @var      array 
  187.      */
  188.     var $_titles = array();
  189.  
  190.     /**
  191.      * Array of holiday-properties indexed by internal-names and
  192.      * furthermore by locales.
  193.      *
  194.      * <code>
  195.      * $_holidayProperties = array(
  196.      *       'internalName1' =>  array(
  197.      *                               'de_DE' => array(),
  198.      *                               'en_US' => array(),
  199.      *                               'fr_FR' => array()
  200.      *                           )
  201.      *       'internalName2' =>  array(
  202.      *                               'de_DE' => array(),
  203.      *                               'en_US' => array(),
  204.      *                               'fr_FR' => array()
  205.      *                           )
  206.      * );
  207.      * </code>
  208.      */
  209.     var $_holidayProperties = array();
  210.  
  211.     /**
  212.      * Constructor
  213.      *
  214.      * Use the Date_Holidays::factory() method to construct an object of a
  215.      * certain driver
  216.      *
  217.      * @access   protected
  218.      */
  219.     function Date_Holidays_Driver()
  220.     {
  221.     }
  222.  
  223.     /**
  224.      * Method that returns an array containing the ISO3166 codes that may possibly
  225.      * identify a driver.
  226.      *
  227.      * @static
  228.      * @access public
  229.      * @return array possible ISO3166 codes
  230.      */
  231.     function getISO3166Codes()
  232.     {
  233.         return array();
  234.     }
  235.  
  236.     /**
  237.      * Sets the driver's current year
  238.      *
  239.      * Calling this method forces the object to rebuild the holidays
  240.      *
  241.      * @param int $year year
  242.      *
  243.      * @access   public
  244.      * @return   boolean true on success, otherwise a PEAR_ErrorStack object
  245.      * @throws   object PEAR_ErrorStack
  246.      * @uses     _buildHolidays()
  247.      */
  248.     function setYear($year)
  249.     {
  250.         $this->_year = $year;
  251.         return $this->_buildHolidays();
  252.     }
  253.  
  254.     /**
  255.      * Returns the driver's current year
  256.      *
  257.      * @access   public
  258.      * @return   int     current year
  259.      */
  260.     function getYear()
  261.     {
  262.         return $this->_year;
  263.     }
  264.  
  265.     /**
  266.      * Build the internal arrays that contain data about the calculated holidays
  267.      *
  268.      * @abstract
  269.      * @access   protected
  270.      * @return   boolean true on success, otherwise a PEAR_ErrorStack object
  271.      * @throws   object PEAR_ErrorStack
  272.      */
  273.     function _buildHolidays()
  274.     {
  275.     }
  276.  
  277.     /**
  278.      * Add a driver component
  279.      *
  280.      * @param object $driver Date_Holidays_Driver object
  281.      *
  282.      * @abstract
  283.      * @access public
  284.      * @return void 
  285.      */
  286.     function addDriver($driver)
  287.     {
  288.     }
  289.  
  290.     /**
  291.      * addTranslation
  292.      *
  293.      * Search for installed language files appropriate for the specified
  294.      * locale and add them to the driver
  295.      *
  296.      * @param string $locale locale setting to be used
  297.      *
  298.      * @access public
  299.      * @return boolean true on success, otherwise false
  300.      */
  301.     function addTranslation($locale)
  302.     {
  303.         $data_dir "@DATA-DIR@";
  304.         $bestLocale $this->_findBestLocale($locale);
  305.         $matches = array();
  306.         $loaded = false;
  307.  
  308.         if ($data_dir == '@'.'DATA-DIR'.'@'{
  309.             $data_dir dirname(dirname(dirname(__FILE__)));
  310.             $stubdirs = array(
  311.                 "$data_dir/lang/{$this->_driverName}/",
  312.                 "$data_dir/lang/Christian/");
  313.         } else {
  314.             //Christian driver is exceptional...
  315.             if ($this->_driverName == 'Christian'{
  316.                 $stubdir = "$data_dir/Date_Holidays/lang/Christian/";
  317.             } else {
  318.                 $stubdir = "$data_dir/Date_Holidays_{$this->_driverName}/lang/{$this->_driverName}/";
  319.                 if (! is_dir($stubdir)) {
  320.                     $stubdir = $data_dir . "/Date_Holidays/lang/";
  321.                 }
  322.             }
  323.             $stubdirs = array(
  324.                 $stubdir,
  325.                 "$data_dir/Date_Holidays_{$this->_driverName}/lang/Christian/");
  326.         }
  327.  
  328.         foreach ($stubdirs as $stubdir) {
  329.             if (is_dir($stubdir)) {
  330.                 if ($dh = opendir($stubdir)) {
  331.                     while (($file = readdir($dh)) !== false) {
  332.                         if (strlen($locale) == 5) {
  333.                             if (((strncasecmp($file, $bestLocale, 5) == 0))
  334.                                 || (strncasecmp($file, $locale, 5) == 0)
  335.                             ) {
  336.                                 array_push($matches, $file);
  337.                             }
  338.                         }
  339.                         if (strlen($locale) == 2) {
  340.                             if (((strncasecmp($file, $bestLocale, 2) == 0))
  341.                                 || (strncasecmp($file, $locale, 2) == 0)
  342.                             ) {
  343.                                 array_push($matches, $file);
  344.                             }
  345.                         }
  346.                     }
  347.                     closedir($dh);
  348.                     $forget = array();
  349.                     sort($matches);
  350.                     foreach ($matches as $am) {
  351.                         if (strpos($am, ".ser") !== false) {
  352.                             $this->addCompiledTranslationFile($stubdir.$am$locale);
  353.                             $loaded = true;
  354.                             array_push($forgetbasename($am".ser"".xml");
  355.                         } else {
  356.                             if (!in_array($am, $forget)) {
  357.                                 $this->addTranslationFile(
  358.                                     $stubdir $am,
  359.                                     str_replace(".xml"""$am)
  360.                                 );
  361.                                 $loaded = true;
  362.                             }
  363.                         }
  364.                     }
  365.                 }
  366.             }
  367.         }
  368.         return $loaded;
  369.     }
  370.  
  371.     /**
  372.      * Remove a driver component
  373.      *
  374.      * @param object $driver Date_Holidays_Driver driver-object
  375.      *
  376.      * @abstract
  377.      * @access   public
  378.      * @return   boolean true on success, otherwise a PEAR_Error object
  379.      * @throws   object PEAR_Error   DATE_HOLIDAYS_DRIVER_NOT_FOUND
  380.      */
  381.     function removeDriver($driver)
  382.     {
  383.     }
  384.  
  385.     /**
  386.      * Returns the internal names of holidays that were calculated
  387.      *
  388.      * @access   public
  389.      * @return   array
  390.      */
  391.     function getInternalHolidayNames()
  392.     {
  393.         return $this->_internalNames;
  394.     }
  395.  
  396.     /**
  397.      * Returns localized titles of all holidays or those accepted by the filter
  398.      *
  399.      * @param Date_Holidays_Filter $filter filter-object (or an array !DEPRECATED!)
  400.      * @param string               $locale locale setting that shall be used
  401.      *                                     by this method
  402.      *
  403.      * @access   public
  404.      * @return   array   $filter array with localized holiday titles on success,
  405.      *                           otherwise a PEAR_Error object
  406.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  407.      * @uses     getHolidayTitle()
  408.      */
  409.     function getHolidayTitles($filter = null, $locale = null)
  410.     {
  411.         if (is_null($filter)) {
  412.             $filter = new Date_Holidays_Filter_Blacklist(array());
  413.         } elseif (is_array($filter)) {
  414.             $filter = new Date_Holidays_Filter_Whitelist($filter);
  415.         }
  416.  
  417.         $titles =   array();
  418.  
  419.         foreach ($this->_internalNames as $internalName{
  420.             if ($filter->accept($internalName)) {
  421.                 $title = $this->getHolidayTitle($internalName$locale);
  422.                 if (Date_Holidays::isError($title)) {
  423.                     return $title;
  424.                 }
  425.                 $titles[$internalName] = $title;
  426.             }
  427.         }
  428.  
  429.         return $titles;
  430.     }
  431.  
  432.     /**
  433.      * Returns localized title for a holiday
  434.      *
  435.      * @param string $internalName internal name for holiday
  436.      * @param string $locale       locale setting to be used by this method
  437.      *
  438.      * @access   public
  439.      * @return   string  title on success, otherwise a PEAR_Error object
  440.      * @throws   object PEAR_Error DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  441.      * @throws   object PEAR_Error DATE_HOLIDAYS_TITLE_UNAVAILABLE
  442.      */
  443.     function getHolidayTitle($internalName, $locale = null)
  444.     {
  445.         if (! in_array($internalName, $this->_internalNames)) {
  446.             $msg = 'Invalid internal name: ' . $internalName;
  447.             return Date_Holidays::raiseError(DATE_HOLIDAYS_INVALID_INTERNAL_NAME,
  448.                                              $msg);
  449.  
  450.         }
  451.  
  452.         if (is_null($locale)) {
  453.             $locale = $this->_findBestLocale($this->_locale);
  454.         } else {
  455.             $locale = $this->_findBestLocale($locale);
  456.         }
  457.  
  458.         if (! isset($this->_titles[$locale][$internalName])) {
  459.             if (Date_Holidays::staticGetProperty('DIE_ON_MISSING_LOCALE')) {
  460.                 $err = DATE_HOLIDAYS_TITLE_UNAVAILABLE;
  461.                 $msg = 'The internal name (' . $internalName . ') ' .
  462.                        'for the holiday was correct but no ' .
  463.                        'localized title could be found';
  464.                 return Date_Holidays::raiseError($err, $msg);
  465.             }
  466.         }
  467.  
  468.         if (isset($this->_titles[$locale][$internalName])) {
  469.             return $this->_titles[$locale][$internalName];
  470.         } else {
  471.             return $this->_titles['C'][$internalName];
  472.         }
  473.     }
  474.  
  475.  
  476.     /**
  477.      * Returns the localized properties of a holiday. If no properties have
  478.      * been stored an empty array will be returned.
  479.      *
  480.      * @param string $internalName internal name for holiday
  481.      * @param string $locale       locale setting that shall be used by this method
  482.      *
  483.      * @access   public
  484.      * @return   array   array of properties on success, otherwise
  485.      *                   a PEAR_Error object
  486.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  487.      */
  488.     function getHolidayProperties($internalName, $locale = null)
  489.     {
  490.         if (! in_array($internalName, $this->_internalNames)) {
  491.             $msg = 'Invalid internal name: ' . $internalName;
  492.             return Date_Holidays::raiseError(DATE_HOLIDAYS_INVALID_INTERNAL_NAME,
  493.                                              $msg);
  494.         }
  495.  
  496.         if (is_null($locale)) {
  497.             $locale =   $this->_findBestLocale($this->_locale);
  498.         } else {
  499.             $locale =   $this->_findBestLocale($locale);
  500.         }
  501.  
  502.  
  503.         $properties = array();
  504.         if (isset($this->_holidayProperties[$internalName][$locale])) {
  505.             $properties = $this->_holidayProperties[$internalName][$locale];
  506.         }
  507.         return $properties;
  508.     }
  509.  
  510.  
  511.     /**
  512.      * Returns all holidays that the driver knows.
  513.      *
  514.      * You can limit the holidays by passing a filter, then only those
  515.      * holidays accepted by the filter will be returned.
  516.      *
  517.      * Return format:
  518.      * <pre>
  519.      *   array(
  520.      *       'easter'        =>  object of type Date_Holidays_Holiday,
  521.      *       'eastermonday'  =>  object of type Date_Holidays_Holiday,
  522.      *       ...
  523.      *   )
  524.      * </pre>
  525.      *
  526.      * @param Date_Holidays_Filter $filter filter-object
  527.      *                                     (or an array !DEPRECATED!)
  528.      * @param string               $locale locale setting that shall be used
  529.      *                                      by this method
  530.      *
  531.      * @access   public
  532.      * @return   array   numeric array containing objects of
  533.      *                   Date_Holidays_Holiday on success, otherwise a
  534.      *                   PEAR_Error object
  535.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  536.      * @see      getHoliday()
  537.      */
  538.     function getHolidays($filter = null, $locale = null)
  539.     {
  540.         if (is_null($filter)) {
  541.             $filter = new Date_Holidays_Filter_Blacklist(array());
  542.         } elseif (is_array($filter)) {
  543.             $filter = new Date_Holidays_Filter_Whitelist($filter);
  544.         }
  545.  
  546.         if (is_null($locale)) {
  547.             $locale = $this->_locale;
  548.         }
  549.  
  550.         $holidays = array();
  551.  
  552.         foreach ($this->_internalNames as $internalName{
  553.             if ($filter->accept($internalName)) {
  554.                 // no need to check for valid internal-name, will be
  555.                 // done by #getHoliday()
  556.                 $holidays[$internalName] = $this->getHoliday($internalName,
  557.                                                              $locale);
  558.             }
  559.         }
  560.  
  561.         return $holidays;
  562.     }
  563.  
  564.     /**
  565.      * Returns the specified holiday
  566.      *
  567.      * Return format:
  568.      * <pre>
  569.      *   array(
  570.      *       'title' =>  'Easter Sunday'
  571.      *       'date'  =>  '2004-04-11'
  572.      *   )
  573.      * </pre>
  574.      *
  575.      * @param string $internalName internal name of the holiday
  576.      * @param string $locale       locale setting that shall be used
  577.      *                              by this method
  578.      *
  579.      * @access   public
  580.      * @return   object Date_Holidays_Holiday holiday's information on
  581.      *                                         success, otherwise a PEAR_Error
  582.      *                                         object
  583.      * @throws   object PEAR_Error       DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  584.      * @uses     getHolidayTitle()
  585.      * @uses     getHolidayDate()
  586.      */
  587.     function getHoliday($internalName, $locale = null)
  588.     {
  589.         if (! in_array($internalName, $this->_internalNames)) {
  590.             return Date_Holidays::raiseError(DATE_HOLIDAYS_INVALID_INTERNAL_NAME,
  591.                 'Invalid internal name: ' . $internalName);
  592.         }
  593.         if (is_null($locale)) {
  594.             $locale = $this->_locale;
  595.         }
  596.  
  597.         $title = $this->getHolidayTitle($internalName$locale);
  598.         if (Date_Holidays::isError($title)) {
  599.             return $title;
  600.         }
  601.         $date = $this->getHolidayDate($internalName);
  602.         if (Date_Holidays::isError($date)) {
  603.             return $date;
  604.         }
  605.         $properties = $this->getHolidayProperties($internalName$locale);
  606.         if (Date_Holidays::isError($properties)) {
  607.             return $properties;
  608.         }
  609.  
  610.         $holiday = new Date_Holidays_Holiday($internalName,
  611.                                              $title,
  612.                                              $date,
  613.                                              $properties);
  614.         return $holiday;
  615.     }
  616.  
  617.     /**
  618.      * Determines whether a date represents a holiday or not
  619.      *
  620.      * @param mixed                $date   a timestamp, string or PEAR::Date object
  621.      * @param Date_Holidays_Filter $filter filter-object (or an array !DEPRECATED!)
  622.      *
  623.      * @access   public
  624.      * @return   boolean true if date represents a holiday, otherwise false
  625.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_DATE_FORMAT
  626.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_DATE
  627.      */
  628.     function isHoliday($date, $filter = null)
  629.     {
  630.         if (! is_a($date, 'Date')) {
  631.             $date = $this->_convertDate($date);
  632.             if (Date_Holidays::isError($date)) {
  633.                 return $date;
  634.             }
  635.         }
  636.  
  637.         //rebuild internal array of holidays if required.
  638.         $compare_year = $date->getYear();
  639.         $this_year $this->getYear();
  640.         if ($this_year !== $compare_year{
  641.             $this->setYear($compare_year);
  642.         }
  643.  
  644.         if (is_null($filter)) {
  645.             $filter = new Date_Holidays_Filter_Blacklist(array());
  646.         } elseif (is_array($filter)) {
  647.             $filter = new Date_Holidays_Filter_Whitelist($filter);
  648.         }
  649.  
  650.         foreach (array_keys($this->_datesas $internalName{
  651.             if ($filter->accept($internalName)) {
  652.                 if (Date_Holidays_Driver::dateSloppyCompare($date,
  653.                                           $this->_dates[$internalName]!= 0{
  654.                     continue;
  655.                 }
  656.                 $this->setYear($this_year);
  657.                 return true;
  658.             }
  659.         }
  660.         $this->setYear($this_year);
  661.         return false;
  662.     }
  663.  
  664.     /**
  665.      * Returns a <code>Date_Holidays_Holiday</code> object, if any was found,
  666.      * matching the specified date.
  667.      *
  668.      * Normally the method will return the object of the first holiday matching
  669.      * the date. If you want the method to continue searching holidays for the
  670.      * specified date, set the 4th param to true.
  671.      *
  672.      * If multiple holidays match your date, the return value will be an array
  673.      * containing a number of <code>Date_Holidays_Holiday</code> items.
  674.      *
  675.      * @param mixed   $date     date (timestamp | string | PEAR::Date object)
  676.      * @param string  $locale   locale setting that shall be used by this method
  677.      * @param boolean $multiple if true, continue searching holidays for
  678.      *                           specified date
  679.      *
  680.      * @access   public
  681.      * @return   object  object of type Date_Holidays_Holiday on success
  682.      *                   (numeric array of those on multiple search),
  683.      *                   if no holiday was found, matching this date,
  684.      *                   null is returned
  685.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_DATE_FORMAT
  686.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_DATE
  687.      * @uses     getHoliday()
  688.      * @uses     getHolidayTitle()
  689.      * @see      getHoliday()
  690.      **/
  691.     function getHolidayForDate($date, $locale = null, $multiple = false)
  692.     {
  693.         if (!is_a($date, 'Date')) {
  694.             $date = $this->_convertDate($date);
  695.             if (Date_Holidays::isError($date)) {
  696.                 return $date;
  697.             }
  698.         }
  699.  
  700.         if ($date->getYear(!= $this->_year{
  701.             return null;
  702.         }
  703.  
  704.         $isodate = mktime(0,
  705.                           0,
  706.                           0,
  707.                           $date->getMonth(),
  708.                           $date->getDay(),
  709.                           $date->getYear());
  710.         unset($date);
  711.         if (is_null($locale)) {
  712.             $locale = $this->_locale;
  713.         }
  714.         if (array_key_exists($isodate, $this->_holidays)) {
  715.             if (!$multiple) {
  716.                 //get only the first feast for this day
  717.                 $internalName = $this->_holidays[$isodate][0];
  718.                 $result       $this->getHoliday($internalName$locale);
  719.                 return Date_Holidays::isError($result? null : $result;
  720.             }
  721.             // array that collects data, if multiple searching is done
  722.             $data = array();
  723.             foreach ($this->_holidays[$isodateas $internalName{
  724.                 $result = $this->getHoliday($internalName$locale);
  725.                 if (Date_Holidays::isError($result)) {
  726.                     continue;
  727.                 }
  728.                 $data[] = $result;
  729.             }
  730.             return $data;
  731.         }
  732.         return null;
  733.     }
  734.  
  735.     /**
  736.      * Returns an array containing a number of
  737.      * <code>Date_Holidays_Holiday</code> items.
  738.      *
  739.      * If no items have been found the returned array will be empty.
  740.      *
  741.      * @param mixed                $start  date: timestamp, string or PEAR::Date
  742.      * @param mixed                $end    date: timestamp, string or PEAR::Date
  743.      * @param Date_Holidays_Filter $filter filter-object (or
  744.      *                                      an array !DEPRECATED!)
  745.      * @param string               $locale locale setting that shall be used
  746.      *                                      by this method
  747.      *
  748.      * @access   public
  749.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_DATE_FORMAT
  750.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_DATE
  751.      * @return   array   an array containing a number
  752.      *                   of <code>Date_Holidays_Holiday</code> items
  753.      */
  754.     function getHolidaysForDatespan($start, $end, $filter = null, $locale = null)
  755.     {
  756.         if (is_null($filter)) {
  757.             $filter = new Date_Holidays_Filter_Blacklist(array());
  758.         } elseif (is_array($filter)) {
  759.             $filter = new Date_Holidays_Filter_Whitelist($filter);
  760.         }
  761.  
  762.         if (!is_a($start, 'Date')) {
  763.             $start = $this->_convertDate($start);
  764.             if (Date_Holidays::isError($start)) {
  765.                 return $start;
  766.             }
  767.         }
  768.         if (!is_a($end, 'Date')) {
  769.             $end = $this->_convertDate($end);
  770.             if (Date_Holidays::isError($end)) {
  771.                 return $end;
  772.             }
  773.         }
  774.  
  775.         $isodateStart = mktime(0,
  776.                                0,
  777.                                0,
  778.                                $start->getMonth(),
  779.                                $start->getDay(),
  780.                                $start->getYear());
  781.         unset($start);
  782.         $isodateEnd = mktime(0,
  783.                              0,
  784.                              0,
  785.                              $end->getMonth(),
  786.                              $end->getDay(),
  787.                              $end->getYear());
  788.         unset($end);
  789.         if (is_null($locale)) {
  790.             $locale = $this->_locale;
  791.         }
  792.  
  793.         $internalNames = array();
  794.  
  795.         foreach ($this->_holidays as $isoDateTS => $arHolidays{
  796.             if ($isoDateTS >= $isodateStart && $isoDateTS <= $isodateEnd) {
  797.                 $internalNames = array_merge($internalNames, $arHolidays);
  798.             }
  799.         }
  800.  
  801.         $retval = array();
  802.         foreach ($internalNames as $internalName) {
  803.             if ($filter->accept($internalName)) {
  804.                 $retval[] = $this->getHoliday($internalName$locale);
  805.             }
  806.         }
  807.         return $retval;
  808.  
  809.     }
  810.  
  811.     /**
  812.      * Converts timestamp or date-string into da PEAR::Date object
  813.      *
  814.      * @param mixed $date date
  815.      *
  816.      * @static
  817.      * @access   private
  818.      * @return   object PEAR_Date
  819.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_DATE_FORMAT
  820.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_DATE
  821.      */
  822.     function _convertDate($date)
  823.     {
  824.         if (is_string($date)) {
  825.             if (! preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}/', $date)) {
  826.                 return Date_Holidays::raiseError(DATE_HOLIDAYS_INVALID_DATE_FORMAT,
  827.                     'Date-string has wrong format (must be YYYY-MM-DD)');
  828.             }
  829.             $date = new Date($date);
  830.             return $date;
  831.         }
  832.  
  833.         if (is_int($date)) {
  834.             $date = new Date(date('Y-m-d', $date));
  835.             return $date;
  836.         }
  837.  
  838.         return Date_Holidays::raiseError(DATE_HOLIDAYS_INVALID_DATE,
  839.             'The date you specified is invalid');
  840.     }
  841.  
  842.     /**
  843.      * Adds all holidays in the array to the driver's internal list of holidays.
  844.      *
  845.      * Format of the array:
  846.      * <pre>
  847.      *   array(
  848.      *       'newYearsDay'   => array(
  849.      *           'date'          => '01-01',
  850.      *           'title'         => 'New Year\'s Day',
  851.      *           'translations'  => array(
  852.      *               'de_DE' =>  'Neujahr',
  853.      *               'en_EN' =>  'New Year\'s Day'
  854.      *           )
  855.      *       ),
  856.      *       'valentinesDay' => array(
  857.      *           ...
  858.      *       )
  859.      *   );
  860.      * </pre>
  861.      *
  862.      * @param array $holidays static holidays' data
  863.      *
  864.      * @access   protected
  865.      * @uses     _addHoliday()
  866.      * @return   void
  867.      */
  868.     function _addStaticHolidays($holidays)
  869.     {
  870.         foreach ($holidays as $internalName => $holiday) {
  871.             // add the holiday's basic data
  872.             $this->_addHoliday($internalName,
  873.                                $this->_year . '-' $holiday['date'],
  874.                                $holiday['title']);
  875.         }
  876.     }
  877.  
  878.     /**
  879.      * Adds a holiday to the driver's holidays
  880.      *
  881.      * @param string $internalName internal name - must not contain characters
  882.      *                              that aren't allowed as variable-names
  883.      * @param mixed  $date         date (timestamp | string | PEAR::Date object)
  884.      * @param string $title        holiday title
  885.      *
  886.      * @access   protected
  887.      * @return   void
  888.      */
  889.     function _addHoliday($internalName, $date, $title)
  890.     {
  891.         if (! is_a($date, 'Date')) {
  892.             $date = new Date($date);
  893.         }
  894.  
  895.         $this->_dates[$internalName]       $date;
  896.         $this->_titles['C'][$internalName$title;
  897.         $isodate                           = mktime(000,
  898.                                                     $date->getMonth(),
  899.                                                     $date->getDay(),
  900.                                                     $date->getYear());
  901.         if (!isset($this->_holidays[$isodate])) {
  902.             $this->_holidays[$isodate= array();
  903.         }
  904.         array_push($this->_holidays[$isodate]$internalName);
  905.         array_push($this->_internalNames$internalName);
  906.     }
  907.  
  908.     /**
  909.      * Add a localized translation for a holiday's title. Overwrites existing data.
  910.      *
  911.      * @param string $internalName internal name of an existing holiday
  912.      * @param string $locale       locale setting that shall be used by this method
  913.      * @param string $title        title
  914.      *
  915.      * @access   protected
  916.      * @return   true on success, otherwise a PEAR_Error object
  917.      * @throws   object PEAR_Error       DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  918.      */
  919.     function _addTranslationForHoliday($internalName, $locale, $title)
  920.     {
  921.         if (! in_array($internalName, $this->_internalNames)) {
  922.             $msg = 'Couldn\'t add translation (' . $locale . ') ' .
  923.                    'for holiday with this internal name: ' . $internalName;
  924.             return Date_Holidays::raiseError(DATE_HOLIDAYS_INVALID_INTERNAL_NAME,
  925.                                              $msg);
  926.         }
  927.  
  928.         if (! in_array($locale, $this->_availableLocales)) {
  929.             array_push($this->_availableLocales$locale);
  930.         }
  931.         $this->_titles[$locale][$internalName$title;
  932.         return true;
  933.     }
  934.  
  935.     /**
  936.      * Adds a localized (regrading translation etc.) string-property for a holiday.
  937.      * Overwrites existing data.
  938.      *
  939.      * @param string $internalName internal-name
  940.      * @param string $locale       locale-setting
  941.      * @param string $propId       property-identifier
  942.      * @param mixed  $propVal      property-value
  943.      *
  944.      * @access   public
  945.      * @return   boolean true on success, false otherwise
  946.      * @throws   PEAR_ErrorStack if internal-name does not exist
  947.      */
  948.     function _addStringPropertyForHoliday($internalName, $locale, $propId, $propVal)
  949.     {
  950.         if (! in_array($internalName, $this->_internalNames)) {
  951.             $msg = 'Couldn\'t add property (locale: ' . $locale . ') '.
  952.                    'for holiday with this internal name: ' . $internalName;
  953.             return Date_Holidays::raiseError(DATE_HOLIDAYS_INVALID_INTERNAL_NAME,
  954.                                              $msg);
  955.         }
  956.  
  957.         if (!isset($this->_holidayProperties[$internalName]||
  958.                 !is_array($this->_holidayProperties[$internalName])) {
  959.  
  960.             $this->_holidayProperties[$internalName= array();
  961.         }
  962.  
  963.         if (! isset($this->_holidayProperties[$internalName][$locale]||
  964.                 !is_array($this->_holidayProperties[$internalName][$locale])) {
  965.  
  966.             $this->_holidayProperties[$internalName][$locale= array();
  967.         }
  968.  
  969.         $this->_holidayProperties[$internalName][$locale][$propId$propVal;
  970.         return true;
  971.     }
  972.  
  973.     /**
  974.      * Adds a arbitrary number of localized string-properties for the
  975.      * specified holiday.
  976.      *
  977.      * @param string $internalName internal-name
  978.      * @param string $locale       locale-setting
  979.      * @param array  $properties   associative array: array(propId1 => val1,...)
  980.      *
  981.      * @access   public
  982.      * @return   boolean true on success, false otherwise
  983.      * @throws   PEAR_ErrorStack if internal-name does not exist
  984.      */
  985.     function _addStringPropertiesForHoliday($internalName, $locale, $properties)
  986.     {
  987.         foreach ($properties as $propId => $propValue) {
  988.             return $this->_addStringPropertyForHoliday($internalName,
  989.                                                        $locale,
  990.                                                        $propId,
  991.                                                        $propValue);
  992.         }
  993.  
  994.         return true;
  995.     }
  996.  
  997.     /**
  998.      * Add a language-file's content
  999.      *
  1000.      * The language-file's content will be parsed and translations,
  1001.      * properties, etc. for holidays will be made available with the specified
  1002.      * locale.
  1003.      *
  1004.      * @param string $file   filename of the language file
  1005.      * @param string $locale locale-code of the translation
  1006.      *
  1007.      * @access   public
  1008.      * @return   boolean true on success, otherwise a PEAR_ErrorStack object
  1009.      * @throws   object PEAR_Errorstack
  1010.      */
  1011.     function addTranslationFile($file, $locale)
  1012.     {
  1013.         if (! file_exists($file)) {
  1014.             Date_Holidays::raiseError(DATE_HOLIDAYS_LANGUAGEFILE_NOT_FOUND,
  1015.                     'Language-file not found: ' . $file);
  1016.             return Date_Holidays::getErrorStack();
  1017.         }
  1018.  
  1019.         // unserialize the document
  1020.         $document = simplexml_load_file($file);
  1021.  
  1022.         $content = array();
  1023.         $content['holidays'] = array();
  1024.         $content['holidays']['holiday'] = array();
  1025.  
  1026.         $nodes = $document->xpath('//holiday');
  1027.         foreach ($nodes as $node{
  1028.             $content['holidays']['holiday'][] = (array)$node;
  1029.         }
  1030.  
  1031.         return $this->_addTranslationData($content$locale);
  1032.     }
  1033.  
  1034.     /**
  1035.      * Add a compiled language-file's content
  1036.      *
  1037.      * The language-file's content will be unserialized and translations,
  1038.      * properties, etc. for holidays will be made available with the
  1039.      * specified locale.
  1040.      *
  1041.      * @param string $file   filename of the compiled language file
  1042.      * @param string $locale locale-code of the translation
  1043.      *
  1044.      * @access   public
  1045.      * @return   boolean true on success, otherwise a PEAR_ErrorStack object
  1046.      * @throws   object PEAR_Errorstack
  1047.      */
  1048.     function addCompiledTranslationFile($file, $locale)
  1049.     {
  1050.         if (! file_exists($file)) {
  1051.             Date_Holidays::raiseError(DATE_HOLIDAYS_LANGUAGEFILE_NOT_FOUND,
  1052.                     'Language-file not found: ' . $file);
  1053.             return Date_Holidays::getErrorStack();
  1054.         }
  1055.  
  1056.         $content = file_get_contents($file);
  1057.         if ($content === false) {
  1058.             return false;
  1059.         }
  1060.         $data = unserialize($content);
  1061.         if ($data === false) {
  1062.             $e   = DATE_HOLIDAYS_UNABLE_TO_READ_TRANSLATIONDATA;
  1063.             $msg = "Unable to read translation-data - file maybe damaged: $file";
  1064.             return Date_Holidays::raiseError($e, $msg);
  1065.         }
  1066.         return $this->_addTranslationData($data$locale);
  1067.     }
  1068.  
  1069.     /**
  1070.      * Add a language-file's content. Translations, properties, etc. for
  1071.      * holidays will be made available with the specified locale.
  1072.      *
  1073.      * @param array  $data   translated data
  1074.      * @param string $locale locale-code of the translation
  1075.      *
  1076.      * @access   public
  1077.      * @return   boolean true on success, otherwise a PEAR_ErrorStack object
  1078.      * @throws   object PEAR_Errorstack
  1079.      */
  1080.     function _addTranslationData($data, $locale)
  1081.     {
  1082.         foreach ($data['holidays']['holiday'] as $holiday) {
  1083.             $this->_addTranslationForHoliday($holiday['internal-name'],
  1084.                                              $locale,
  1085.                                              $holiday['translation']);
  1086.  
  1087.             if (isset($holiday['properties']&& is_array($holiday['properties'])) {
  1088.                 foreach ($holiday['properties'] as $propId => $propVal) {
  1089.                     $this->_addStringPropertyForHoliday($holiday['internal-name'],
  1090.                                                         $locale,
  1091.                                                         $propId,
  1092.                                                         $propVal);
  1093.                 }
  1094.             }
  1095.  
  1096.         }
  1097.  
  1098.         if (Date_Holidays::errorsOccurred()) {
  1099.             return Date_Holidays::getErrorStack();
  1100.         }
  1101.  
  1102.         return true;
  1103.     }
  1104.  
  1105.     /**
  1106.      * Remove a holiday from internal storage
  1107.      *
  1108.      * This method should be used within driver classes to unset holidays that
  1109.      * were inherited from parent-drivers
  1110.      *
  1111.      * @param $string $internalName internal name
  1112.      *
  1113.      * @access   protected
  1114.      * @return   boolean     true on success, otherwise a PEAR_Error object
  1115.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  1116.      */
  1117.     function _removeHoliday($internalName)
  1118.     {
  1119.         if (! in_array($internalName, $this->_internalNames)) {
  1120.             $msg = "Couldn't remove holiday with this internal name: $internalName";
  1121.             return Date_Holidays::raiseError(DATE_HOLIDAYS_INVALID_INTERNAL_NAME,
  1122.                                              $msg);
  1123.         }
  1124.  
  1125.         if (isset($this->_dates[$internalName])) {
  1126.             unset($this->_dates[$internalName]);
  1127.         }
  1128.         $locales = array_keys($this->_titles);
  1129.         foreach ($locales as $locale{
  1130.             if (isset($this->_titles[$locale][$internalName])) {
  1131.                 unset($this->_titles[$locale][$internalName]);
  1132.             }
  1133.         }
  1134.         $index = array_search($internalName, $this->_internalNames);
  1135.         if (is_null($index)) {
  1136.             unset($this->_internalNames[$index]);
  1137.         }
  1138.         return true;
  1139.     }
  1140.  
  1141.     /**
  1142.      * Finds the best internally available locale for the specified one
  1143.      *
  1144.      * @param string $locale locale
  1145.      *
  1146.      * @access   protected
  1147.      * @return   string  best locale available
  1148.      */
  1149.     function _findBestLocale($locale)
  1150.     {
  1151.         /* exact locale is available */
  1152.         if (in_array($locale, $this->_availableLocales)) {
  1153.             return $locale;
  1154.         }
  1155.  
  1156.         /* first two letter are equal */
  1157.         foreach ($this->_availableLocales as $aLocale{
  1158.             if (strncasecmp($aLocale, $locale, 2) == 0) {
  1159.                 return $aLocale;
  1160.             }
  1161.         }
  1162.  
  1163.         /* no appropriate locale available, will use driver's internal locale */
  1164.         return 'C';
  1165.     }
  1166.  
  1167.     /**
  1168.      * Returns date of a holiday
  1169.      *
  1170.      * @param string $internalName internal name for holiday
  1171.      *
  1172.      * @access   public
  1173.      * @return   object Date             date of holiday as PEAR::Date object
  1174.      *                                   on success, otherwise a PEAR_Error object
  1175.      * @throws   object PEAR_Error       DATE_HOLIDAYS_DATE_UNAVAILABLE
  1176.      * @throws   object PEAR_Error       DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  1177.      */
  1178.     function getHolidayDate($internalName)
  1179.     {
  1180.         if (! in_array($internalName, $this->_internalNames)) {
  1181.             $msg = 'Invalid internal name: ' . $internalName;
  1182.             return Date_Holidays::raiseError(DATE_HOLIDAYS_INVALID_INTERNAL_NAME,
  1183.                                              $msg);
  1184.         }
  1185.  
  1186.         if (! isset($this->_dates[$internalName])) {
  1187.             $msg = 'Date for holiday with internal name ' .
  1188.                    $internalName . ' is not available';
  1189.             return Date_Holidays::raiseError(DATE_HOLIDAYS_DATE_UNAVAILABLE, $msg);
  1190.         }
  1191.  
  1192.         return $this->_dates[$internalName];
  1193.     }
  1194.  
  1195.     /**
  1196.      * Returns dates of all holidays or those accepted by the applied filter.
  1197.      *
  1198.      * Structure of the returned array:
  1199.      * <pre>
  1200.      * array(
  1201.      *   'internalNameFoo' => object of type date,
  1202.      *   'internalNameBar' => object of type date
  1203.      * )
  1204.      * </pre>
  1205.      *
  1206.      * @param Date_Holidays_Filter $filter filter-object (or an array !DEPRECATED!)
  1207.      *
  1208.      * @access   public
  1209.      * @return   array with holidays' dates on success, otherwise a PEAR_Error object
  1210.      * @throws   object PEAR_Error   DATE_HOLIDAYS_INVALID_INTERNAL_NAME
  1211.      * @uses     getHolidayDate()
  1212.      */
  1213.     function getHolidayDates($filter = null)
  1214.     {
  1215.         if (is_null($filter)) {
  1216.             $filter = new Date_Holidays_Filter_Blacklist(array());
  1217.         } elseif (is_array($filter)) {
  1218.             $filter = new Date_Holidays_Filter_Whitelist($filter);
  1219.         }
  1220.  
  1221.         $dates = array();
  1222.  
  1223.         foreach ($this->_internalNames as $internalName{
  1224.             if ($filter->accept($internalName)) {
  1225.                 $date = $this->getHolidayDate($internalName);
  1226.                 if (Date_Holidays::isError($date)) {
  1227.                     return $date;
  1228.                 }
  1229.                 $dates[$internalName] = $this->getHolidayDate($internalName);
  1230.             }
  1231.         }
  1232.         return $dates;
  1233.     }
  1234.  
  1235.     /**
  1236.      * Sets the driver's locale
  1237.      *
  1238.      * @param string $locale locale
  1239.      *
  1240.      * @access   public
  1241.      * @return   void
  1242.      */
  1243.     function setLocale($locale)
  1244.     {
  1245.         $this->_locale = $locale;
  1246.         //if possible, load the translation files for this locale
  1247.         $this->addTranslation($locale);
  1248.     }
  1249.  
  1250.     /**
  1251.      * Sloppily compares two date objects (only year, month and day are compared).
  1252.      * Does not take the date's timezone into account.
  1253.      *
  1254.      * @param Date $d1 a date object
  1255.      * @param Date $d2 another date object
  1256.      *
  1257.      * @static
  1258.      * @access private
  1259.      * @return int 0 if the dates are equal,
  1260.      *             -1 if d1 is before d2,
  1261.      *             1 if d1 is after d2
  1262.      */
  1263.     function dateSloppyCompare($d1, $d2)
  1264.     {
  1265.         $d1->setTZ(new Date_TimeZone('UTC'));
  1266.         $d2->setTZ(new Date_TimeZone('UTC'));
  1267.         $days1 = Date_Calc::dateToDays($d1->day$d1->month$d1->year);
  1268.         $days2 = Date_Calc::dateToDays($d2->day$d2->month$d2->year);
  1269.         if ($days1 $days2return -1;
  1270.         if ($days1 $days2return 1;
  1271.         return 0;
  1272.     }
  1273.     /**
  1274.      * Find the date of the first monday in the specified year of the current year.
  1275.      *
  1276.      * @param integer $month month
  1277.      *
  1278.      * @access   private
  1279.      * @return   object Date date of first monday in specified month.
  1280.      */
  1281.     function _calcFirstMonday($month)
  1282.     {
  1283.         $month = sprintf("%02d", $month);
  1284.         $date = new Date($this->_year . "-$month-01");
  1285.         while ($date->getDayOfWeek(!= 1{
  1286.             $date = $date->getNextDay();
  1287.         }
  1288.         return ($date);
  1289.     }
  1290.     /**
  1291.      * Find the date of the last monday in the specified year of the current year.
  1292.      *
  1293.      * @param integer $month month
  1294.      *
  1295.      * @access   private
  1296.      * @return   object Date date of last monday in specified month.
  1297.      */
  1298.     function _calcLastMonday($month)
  1299.     {
  1300.         //work backwards from the first day of the next month.
  1301.         $month = sprintf("%02d", $month);
  1302.         $nm = ((int) $month ) + 1;
  1303.         if ($nm > 12) {
  1304.             $nm = 1;
  1305.         }
  1306.         $nm = sprintf("%02d", $nm);
  1307.  
  1308.         $date = new Date($this->_year . "-$nm-01");
  1309.         $date = $date->getPrevDay();
  1310.         while ($date->getDayOfWeek(!= 1{
  1311.             $date = $date->getPrevDay();
  1312.         }
  1313.         return ($date);
  1314.     }
  1315.     /**
  1316.      * Calculate Nth monday in a month
  1317.      *
  1318.      * @param int $month    month
  1319.      * @param int $position position
  1320.      *
  1321.      * @access   private
  1322.      * @return   object Date date
  1323.      */
  1324.     function _calcNthMondayInMonth($month, $position)
  1325.     {
  1326.         if ($position  == 1) {
  1327.             $startday = '01';
  1328.         } elseif ($position == 2) {
  1329.             $startday = '08';
  1330.         } elseif ($position == 3) {
  1331.             $startday = '15';
  1332.         } elseif ($position == 4) {
  1333.             $startday = '22';
  1334.         } elseif ($position == 5) {
  1335.             $startday = '29';
  1336.         }
  1337.         $month = sprintf("%02d", $month);
  1338.  
  1339.         $date = new Date($this->_year . '-' $month '-' $startday);
  1340.         while ($date->getDayOfWeek(!= 1{
  1341.             $date = $date->getNextDay();
  1342.         }
  1343.         return $date;
  1344.     }
  1345.  
  1346.     /**
  1347.      * Calculate Nth day of the week in a month
  1348.      *
  1349.      * @param int $position position
  1350.      * @param int $weekday  day of the week starting from 1 == sunday
  1351.      * @param int $month    month
  1352.      *
  1353.      * @access   private
  1354.      * @return   object Date date
  1355.      */
  1356.     function _calcNthWeekDayInMonth($position, $weekday, $month)
  1357.     {
  1358.         if ($position  == 1) {
  1359.             $startday = '01';
  1360.         } elseif ($position == 2) {
  1361.             $startday = '08';
  1362.         } elseif ($position == 3) {
  1363.             $startday = '15';
  1364.         } elseif ($position == 4) {
  1365.             $startday = '22';
  1366.         } elseif ($position == 5) {
  1367.             $startday = '29';
  1368.         }
  1369.         $month = sprintf("%02d", $month);
  1370.  
  1371.         $date = new Date($this->_year . '-' $month '-' $startday);
  1372.         while ($date->getDayOfWeek(!= $weekday{
  1373.             $date = $date->getNextDay();
  1374.         }
  1375.         return $date;
  1376.     }
  1377.  
  1378.     /**
  1379.      * Converts the date to the specified no of days from the given date
  1380.      *
  1381.      * To subtract days use a negative value for the '$pn_days' parameter
  1382.      *
  1383.      * @param Date $date Date object
  1384.      * @param int $pn_days days to add
  1385.      *
  1386.      * @return   Date
  1387.      * @access   protected
  1388.      */
  1389.     function _addDays($date, $pn_days)
  1390.     {
  1391.         $new_date = new Date($date);
  1392.         list($new_date->year$new_date->month$new_date->day=
  1393.             explode(' ',
  1394.                     Date_Calc::daysToDate(Date_Calc::dateToDays($date->day,
  1395.                                                                 $date->month,
  1396.                                                                 $date->year+
  1397.                                           $pn_days,
  1398.                                           '%Y %m %d'));
  1399.         if (isset($new_date->on_standardyear)) {
  1400.             $new_date->on_standardyear = $new_date->year;
  1401.             $new_date->on_standardmonth = $new_date->month;
  1402.             $new_date->on_standardday = $new_date->day;
  1403.         }
  1404.         return $new_date;
  1405.     }
  1406.  
  1407. }

Documentation generated on Tue, 22 Jan 2013 01:00:08 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.