Однажды мне понадобился аналог функции TO_DAYS() в PHP. Я, наивный, полагал что среди огромного набора функций обязательно должна быть реализующая TO_DAYS() из MySQL. Но поиски мои были тщетны. Я перерыл гугл, но так и не нашел нужную мне реализацию. Все что я нашел было из разряда

define(«SECONDS_PER_DAY», 86400);
$now = (int) (time() / SECONDS_PER_DAY);

Меня такой подход не устроил.
Во-первых, данное решение считало дни относительно начала эпохи UNIX, а в MySQL это от даты 0000-00-00, то есть числа мягко говоря не совпадали. Можно было, конечно, прибавить количество дней до начала эпохи UNIX, но это бы сильно сократило диапазон валидных дат.
Во-вторых не учитывалось то, что в некоторых днях 23 часа, а в некотоых 25 (при переходе на летнее и зимнее время).
Кроме того, по метке времени (timestamp) нельзя точно сказать какое сейчас число не зная часового пояса (хотя это не особая проблема).

Самым главным критерием было совпадение результатов выполнения функции с результатами TO_DAYS() из MySQL. Ну раз уж так, то я побрел искать эту функцию, в исходниках самой MySQL. С горем пополам, нашел функцию calc_daynr, которую вызывает функция Item_func_to_days::val_int() для подсчета этих самых дней.

После нехитрых преобразования код, написанный на C превратился в код на PHP. Я немного модернизировал входные параметры с учетом последних веяний работы с датой в PHP, и получил следующую функцию:

<?
    define («YY_PART_YEAR», 70); 
    define («YY_MAGIC_BELOW», 200);   
    
    function to_days(DateTime $date)
    {
        $year = $date->format(«Y»);
        $month = $date->format(«m»);
        $day = $date->format(«d»);
        
        if ($year == 0 && $month == 0 && $day == 0)
        {
          return 0;
        }
        if ($year < YY_MAGIC_BELOW)
        {
            if (($year = $year+1900) < 1900+YY_PART_YEAR)
            {
                $year+=100;
            }
        }
        $delsum = 365*$year+31*($month-1)+$day;
        if ($month <= 2)
        {
            $year--;
        }
        else
        {
            $delsum -= floor(($month*4+23)/10);
        }
        $temp = floor((floor($year/100)+1)*3/4);
        return floor($delsum+$year/4-$temp);
    }
?>

Если вы думаете что я полностью понимаю этот код, то вы ошибаетесь. Чего стоит хотя бы эта сточка:

$delsum -= floor(($month*4+23)/10);

Но этого на данном этапе и не требуется, главное чтобы работало.
Я проверил на совпадение с TO_DAYS() с 1700 г. по 2300 г. — ни единой ошибки.
Так что если кому надо, пользуйте на здоровье.

P.S. Теперь надо то же самое сделать для FROM_DAYS(). Потом поделюсь, если будет чем :)