Как и обещал, привожу код переведенной с языка C функции FROM_DAYS(), реализованной в MySQL функцией get_date_from_daynr.
<?
/**
*
* @param $year year number
* @return integer
*/
private function calc_days_in_year($year)
{
return (($year & 3) == 0 && ($year%100 || ($year%400 == 0 && $year))) ? 366 : 365;
}
/**
*
* @param $days integer
* @return DateTime
*/
public function from_days($days)
{
$days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0);
$year = 0;
$month = 0;
$day = 0;
$days_in_year = 0;
$day_of_year = 0;
if ($days <= 365 || $days >= 3652500)
{
$year = $month = $day = 0;
}
else
{
$year = floor($days*100/36525);
$temp = floor(((floor(($year-1)/100)+1)*3)/4);
$day_of_year = floor(($days - $year*365) - floor(($year-1)/4) + $temp);
while ($day_of_year > ($days_in_year = $this->calc_days_in_year($year)))
{
$day_of_year -= $days_in_year;
$year++;
}
$leap_day = 0;
if ($days_in_year == 366)
{
if ($day_of_year > 31+28)
{
$day_of_year--;
if ($day_of_year == 31+28)
{
$leap_day = 1;
}
}
}
$month = 1;
for ($i = 0;
$day_of_year > $days_in_month[$i];
$day_of_year -= $days_in_month[$i++], $month++);
$day = $day_of_year+$leap_day;
}
return (new DateTime("$year-$month-$day"));
}
?>
Проверил функцию на совпадение с FROM_DAYS() в диапазоне от 1700 г. до 2300 г.
Функцию я выдрал из своего класса, так что вызовы вроде $this->calc_days_in_year($year) работать в самостоятельной функции не будут.
Приятного использования.
<?
/**
*
* @param $year year number
* @return integer
*/
private function calc_days_in_year($year)
{
return (($year & 3) == 0 && ($year%100 || ($year%400 == 0 && $year))) ? 366 : 365;
}
/**
*
* @param $days integer
* @return DateTime
*/
public function from_days($days)
{
$days_in_month = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0);
$year = 0;
$month = 0;
$day = 0;
$days_in_year = 0;
$day_of_year = 0;
if ($days <= 365 || $days >= 3652500)
{
$year = $month = $day = 0;
}
else
{
$year = floor($days*100/36525);
$temp = floor(((floor(($year-1)/100)+1)*3)/4);
$day_of_year = floor(($days - $year*365) - floor(($year-1)/4) + $temp);
while ($day_of_year > ($days_in_year = $this->calc_days_in_year($year)))
{
$day_of_year -= $days_in_year;
$year++;
}
$leap_day = 0;
if ($days_in_year == 366)
{
if ($day_of_year > 31+28)
{
$day_of_year--;
if ($day_of_year == 31+28)
{
$leap_day = 1;
}
}
}
$month = 1;
for ($i = 0;
$day_of_year > $days_in_month[$i];
$day_of_year -= $days_in_month[$i++], $month++);
$day = $day_of_year+$leap_day;
}
return (new DateTime("$year-$month-$day"));
}
?>
Проверил функцию на совпадение с FROM_DAYS() в диапазоне от 1700 г. до 2300 г.
Функцию я выдрал из своего класса, так что вызовы вроде $this->calc_days_in_year($year) работать в самостоятельной функции не будут.
Приятного использования.