выполнение операций с датой и временем в PHP - PullRequest
7 голосов
/ 11 сентября 2008

Как вы на самом деле выполняете операции даты и времени, такие как добавление даты, нахождение разницы, определение количества дней, исключая выходные в интервале? Лично я начал передавать некоторые из этих операций моим 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;

Ответы [ 12 ]

5 голосов
/ 11 сентября 2008

Хотя для большинства операций с датой и временем я обычно конвертирую в Unixtime и выполняю вычитание сложения и т. Д. Для целого числа Unixtime, вы можете обратиться к классу Zend framework Zend_Date.

В нем много описанных вами функций. Хотя Zend объявлен как «фреймворк», он работает исключительно хорошо, как библиотека классов, из которой можно выбирать элементы. Мы обычно включаем его в проекты, а затем просто добавляем биты по мере необходимости.

2 голосов
/ 06 января 2010

Для добавления даты вы можете использовать метод DateTime :: add ( Добавляет количество дней, месяцев, лет, часов, минут и секунд к объекту DateTime ) , доступно с php 5.3.0 и выше.

Чтобы найти разницу между двумя датами, есть метод DateTime :: diff ; но, похоже, нет способа подсчета рабочих дней между двумя датами.

2 голосов
/ 14 октября 2008

PHP5 + объект DateTime полезен, потому что это високосное время и переход на летнее время, но он нуждается в некотором расширении решать проблему. Я написал следующее, чтобы решить аналогичную проблему. Метод find_WeekdaysFromThisTo () является грубым, но он работает достаточно быстро, если ваш промежуток времени меньше 2 лет.

$tryme = new Extended_DateTime('2007-8-26');
$newer = new Extended_DateTime('2008-9-1');

print 'Weekdays From '.$tryme->format('Y-m-d').' To '.$newer->format('Y-m-d').': '.$tryme -> find_WeekdaysFromThisTo($newer) ."\n";
/*  Output:  Weekdays From 2007-08-26 To 2008-09-01: 265  */
print 'All Days From '.$tryme->format('Y-m-d').' To '.$newer->format('Y-m-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('Y-m-d').' and '.$newer->format('Y-m-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
2 голосов
/ 12 сентября 2008

strtotime () полезна, но имеет некоторые странные поведения, которые могут всплывать время от времени, если вы не просто используете ее для преобразования форматированной строки даты / времени.

такие вещи, как «+1 месяц» или «-3 дня», иногда могут не дать того, что вы ожидаете получить.

2 голосов
/ 11 сентября 2008

PEAR::Date похоже, что он может иметь некоторые полезные функции.

PEAR::Calendar также может быть полезным.

1 голос
/ 11 сентября 2008

Самый простой способ - использовать метку времени, представляющую количество секунд с 1 января 2008 года. С типом метки времени вы можете делать что-то вроде ...

now = time();
tomorrow = now + 24 * 60 * 60; // 24 hours * 60 minutes * 60 seconds

Проверьте документацию для time () , date () и mktime () на веб-страницах php. Это три метода, которые я использую чаще всего.

0 голосов
/ 11 июля 2011

для получения рабочих дней / выходных, postgresql CTE ftw - см. http://osssmb.wordpress.com/2009/12/02/business-days-working-days-sql-for-postgres-2/

0 голосов
/ 13 сентября 2008

Я бы настоятельно рекомендовал использовать PHP 5.2 DateTime объекты , а не использовать метки времени UNIX при выполнении вычислений даты. Когда вы используете функции даты PHP, которые возвращают метки времени UNIX, у вас очень ограниченный диапазон для работы (например, ничего до 1970 года).

0 голосов
/ 12 сентября 2008

Вы можете получить количество дней между двумя датами, например:

$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("Y-m-d",$tmp) ) ) $workdays++;
    $tmp += 60*60*24;
  }
  return $workdays;
}

Если вам не нравится strtotime и у вас всегда есть дата в одном и том же формате, вы можете использовать функцию разнесения, например

list($year, $month, day) = explode("-", $date);
0 голосов
/ 12 сентября 2008

Если вы посмотрите на http://php.net/date, вы найдете несколько примеров использования mktime() для выполнения операций.

Простым примером было бы узнать, какая будет завтрашняя дата. Вы можете сделать это, просто добавив 1 к значению дня в mktime() следующим образом:

$tomorrow = date("Y-m-d", mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")));

Таким образом, здесь вы получите дату в форме ГГГГ-ММ-ДД с датой завтрашнего дня. Вы также можете вычесть дни, просто заменив '+' на '-'. mktime() делает жизнь намного проще и избавляет вас от необходимости делать вложенные, если операторы и другие подобные проблемные кодировки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...