Как вы фактически выполняете операции datetime, такие как добавление даты, поиск разницы, узнать, сколько дней, за исключением выходных дней в промежутке? Я лично начал передавать некоторые из этих операций в мои postgresql dbms, так как обычно мне нужно было только выдать один SQL-запрос, чтобы получить ответ, однако, чтобы сделать это в PHP-режиме, мне пришлось бы написать намного больше кода, что означает больше шансов для ошибок …
Существуют ли какие-либо библиотеки на PHP, которые делают операцию datetime таким образом, чтобы не требовалось много кода? что бьет sql в ситуации, когда «Учитывая две даты, сколько рабочих дней существует между двумя датами? Реализовать либо SQL, либо $ pet_lang ', который решается путем создания этого запроса?
SELECT COUNT(*) AS total_days FROM (SELECT date '2008-8-26' + generate_series(0, (date '2008-9-1' - date '2008-8-26')) AS all_days) AS calendar WHERE EXTRACT(isodow FROM all_days) < 6;
Объект DateTime PHP5 + полезен, поскольку он знает о прыжке и дневном свете, но для решения этой проблемы требуется некоторое расширение. Для решения подобной проблемы я написал следующее. Метод find_WeekdaysFromThisTo () является грубой силой, но он работает достаточно быстро, если ваш временной интервал составляет менее 2 лет.
$tryme = new Extended_DateTime('2007-8-26'); $newer = new Extended_DateTime('2008-9-1'); print 'Weekdays From '.$tryme->format('Ym-d').' To '.$newer->format('Ym-d').': '.$tryme -> find_WeekdaysFromThisTo($newer) ."\n"; /* Output: Weekdays From 2007-08-26 To 2008-09-01: 265 */ print 'All Days From '.$tryme->format('Ym-d').' To '.$newer->format('Ym-d').': '.$tryme -> find_AllDaysFromThisTo($newer) ."\n"; /* Output: All Days From 2007-08-26 To 2008-09-01: 371 */ $timefrom = $tryme->find_TimeFromThisTo($newer); print 'Between '.$tryme->format('Ym-d').' and '.$newer->format('Ym-d').' there are '. $timefrom['years'].' years, '.$timefrom['months'].' months, and '.$timefrom['days']. ' days.'."\n"; /* Output: Between 2007-08-26 and 2008-09-01 there are 1 years, 0 months, and 5 days. */ class Extended_DateTime extends DateTime { public function find_TimeFromThisTo($newer) { $timefrom = array('years'=>0,'months'=>0,'days'=>0); // Clone because we're using modify(), which will destroy the object that was passed in by reference $testnewer = clone $newer; $timefrom['years'] = $this->find_YearsFromThisTo($testnewer); $mod = '-'.$timefrom['years'].' years'; $testnewer -> modify($mod); $timefrom['months'] = $this->find_MonthsFromThisTo($testnewer); $mod = '-'.$timefrom['months'].' months'; $testnewer -> modify($mod); $timefrom['days'] = $this->find_AllDaysFromThisTo($testnewer); return $timefrom; } // end function find_TimeFromThisTo public function find_YearsFromThisTo($newer) { /* If the passed is: not an object, not of class DateTime or one of its children, or not larger (after) $this return false */ if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U')) return FALSE; $count = 0; // Clone because we're using modify(), which will destroy the object that was passed in by reference $testnewer = clone $newer; $testnewer -> modify ('-1 year'); while ( $this->format('U') < $testnewer->format('U')) { $count ++; $testnewer -> modify ('-1 year'); } return $count; } // end function find_YearsFromThisTo public function find_MonthsFromThisTo($newer) { /* If the passed is: not an object, not of class DateTime or one of its children, or not larger (after) $this return false */ if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U')) return FALSE; $count = 0; // Clone because we're using modify(), which will destroy the object that was passed in by reference $testnewer = clone $newer; $testnewer -> modify ('-1 month'); while ( $this->format('U') < $testnewer->format('U')) { $count ++; $testnewer -> modify ('-1 month'); } return $count; } // end function find_MonthsFromThisTo public function find_AllDaysFromThisTo($newer) { /* If the passed is: not an object, not of class DateTime or one of its children, or not larger (after) $this return false */ if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U')) return FALSE; $count = 0; // Clone because we're using modify(), which will destroy the object that was passed in by reference $testnewer = clone $newer; $testnewer -> modify ('-1 day'); while ( $this->format('U') < $testnewer->format('U')) { $count ++; $testnewer -> modify ('-1 day'); } return $count; } // end function find_AllDaysFromThisTo public function find_WeekdaysFromThisTo($newer) { /* If the passed is: not an object, not of class DateTime or one of its children, or not larger (after) $this return false */ if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U')) return FALSE; $count = 0; // Clone because we're using modify(), which will destroy the object that was passed in by reference $testnewer = clone $newer; $testnewer -> modify ('-1 day'); while ( $this->format('U') < $testnewer->format('U')) { // If the calculated day is not Sunday or Saturday, count this day if ($testnewer->format('w') != '0' && $testnewer->format('w') != '6') $count ++; $testnewer -> modify ('-1 day'); } return $count; } // end function find_WeekdaysFromThisTo public function set_Day($newday) { if (is_int($newday) && $newday > 0 && $newday < 32 && checkdate($this->format('m'),$newday,$this->format('Y'))) $this->setDate($this->format('Y'),$this->format('m'),$newday); } // end function set_Day public function set_Month($newmonth) { if (is_int($newmonth) && $newmonth > 0 && $newmonth < 13) $this->setDate($this->format('Y'),$newmonth,$this->format('d')); } // end function set_Month public function set_Year($newyear) { if (is_int($newyear) && $newyear > 0) $this->setDate($newyear,$this->format('m'),$this->format('d')); } // end function set_Year } // end class Extended_DateTime
В то время как для большинства операций datetime я обычно конвертировал бы в Unixtime и выполнял вычитание сложения и т. Д. В целочисленном Unixtime, вы можете посмотреть на класс Zend Framework Zend_Date.
В этом есть много функций, которые вы описываете. Хотя Zend объявляется как «каркас», он отлично работает как библиотека классов для выбора и выбора элементов. Мы обычно включаем его в проекты, а затем просто вбиваем биты по мере необходимости.
PEAR :: Date также похоже, что у него могут быть некоторые полезные функции: http://pear.php.net/package/Date . PEAR :: Календарь также может быть полезен: http://pear.php.net/package/Calendar
strtotime () полезен, но у него есть некоторые нечетные поведения, которые могут появляться время от времени, если вы не просто используете его для преобразования форматированной строки даты / времени.
такие вещи, как «+1 месяц» или «-3 дня», могут иногда не давать вам то, что вы ожидаете от него.
Для добавления даты вы можете использовать метод DateTime :: add ( добавляет количество дней, месяцев, лет, часов, минут и секунд в объект DateTime ), доступный с php 5.3.0 и далее.
Чтобы найти разницу между двумя датами, существует метод DateTime :: diff ; но, похоже, нет способа подсчета рабочих дней между двумя датами.
Самый простой способ – использовать временную метку, представляющую количество секунд с 1 января 2008 года. С типом метки вы можете делать такие вещи, как …
now = time(); tomorrow = now + 24 * 60 * 60; // 24 hours * 60 minutes * 60 seconds
Ознакомьтесь с документацией по времени () , дате () и mktime () на веб-страницах php. Это три метода, которые я использую чаще всего.
Вы можете использовать комбинацию strtotime , mktime и date для арифметики
Вот пример, который использует комбо, чтобы выполнить некоторую арифметику http://rushi.wordpress.com/2008/04/13/php-print-out-age-of-date-in-words/. Я воспроизведу код здесь для простоты
if ($timestamp_diff < (60*60*24*7)) { echo floor($timestamp_diff/60/60/24)." Days"; } elseif ($timestamp_diff > (60*60*24*7*4)) { echo floor($timestamp_diff/60/60/24/7)." Weeks"; } else { $total_months = $months = floor($timestamp_diff/60/60/24/30); if($months >= 12) { $months = ($total_months % 12); $years = ($total_months - $months)/12; echo $years . " Years "; } if($months > 0) echo $months . " Months"; } ?>
@Rushi Мне не нравится strtotime () лично. Я не знаю, почему, но я обнаружил сегодня утром, что передача строки вроде этого '2008-09-11 9: 5 AM' to strtotime возвращает false …
Я не думаю, что код, который вы предоставили, разрешает пример проблемы «Учитывая две даты, сколько рабочих дней существует между двумя датами? Реализуйте либо SQL, либо $ pet_lang ', и я не считаю, есть ли у меня список праздничных дней …
Вы можете получить количество дней между двумя датами:
$days = (strtotime("2008-09-10") - strtotime("2008-09-12")) / (60 * 60 * 24);
И вы можете сделать что-то вроде этого (у меня нет php, установленного на моем рабочем компьютере, поэтому я не могу гарантировать, что синтаксис на 100% правильный)
function isWorkDay($date) { // check if workday and return true if so } function numberOfWorkDays($startdate, $enddate) { $workdays = 0; $tmp = strtotime($startdate); $end = strtotime($enddate); while($tmp <= $end) { if ( isWorkDay( date("Ymd",$tmp) ) ) $workdays++; $tmp += 60*60*24; } return $workdays; }
Если вам не нравится strtotime, и у вас всегда есть дата в том же формате, вы можете использовать функцию explode, например
list($year, $month, day) = explode("-", $date);
Я бы настоятельно рекомендовал использовать объекты DateTime PHP 5.2 вместо использования временных меток UNIX при выполнении расчетов даты. Когда вы используете функции даты PHP, возвращающие временные метки UNIX, у вас ограниченный диапазон работы (например, ничего до 1970 года).
Если вы посмотрите на http://php.net/date , вы найдете несколько примеров использования mktime()
для выполнения операций.
Простым примером будет тренировка, какая дата завтрашнего дня. Вы можете сделать это, просто добавив 1 к значению дня в mktime()
следующим образом:
$tomorrow = date("Ymd", mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")));
Итак, здесь вы получите дату в виде ГГГГ-ММ-ДД, содержащую дату завтрашнего дня. Вы также можете вычесть дни, просто заменив «+» на «-». mktime()
делает жизнь намного проще и экономит вам от необходимости делать вложенные операторы if и другое подобное неприятное кодирование.
получать рабочие дни / праздники, postgresql CTE ftw – см. http://osssmb.wordpress.com/2009/12/02/business-days-working-days-sql-for-postgres-2/