Pregunta

¿Cómo realizar datetime operaciones como la adición de la fecha, la búsqueda de la diferencia, saber cuántos días excepto los fines de semana en un intervalo?Personalmente me empezó a pasar a algunas de estas operaciones para mi dbms postgresql como normalmente yo sólo tendría que emitir una sentencia sql para obtener una respuesta, sin embargo, de hacerlo en PHP manera en que yo tendría que escribir mucho más código que significa más oportunidades para los errores que se producen...

Hay librerías en PHP que hace datetime operación de una manera que no requieren una gran cantidad de código?que late sql en una situación en la que 'Dado dos fechas, ¿cuántos días de trabajo hay entre las dos fechas?Implementar en SQL, o $pet_lang' que es resuelto por hacer esta consulta?

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;
¿Fue útil?

Solución

PHP5+'s objeto DateTime es útil porque es salto de tiempo y ahorro de la luz del conocimiento, pero se necesita un poco de extensión realmente resolver el problema.Me escribió lo siguiente para resolver un problema similar.El find_WeekdaysFromThisTo() es el método de fuerza bruta, pero funciona razonablemente rápidamente si el lapso de tiempo es de menos de 2 años.

$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

Otros consejos

Mientras que para la mayoría de los datetime operaciones que normalmente debería convertir a Unixtime y realizar la suma la resta, etc.en el Unixtime entero, puede que desee ver en el Zend framework Zend_Date clase.

Esto tiene mucho de la funcionalidad que usted describe.Aunque Zend es considerado como un "marco" que funciona excepcionalmente bien como una biblioteca de clases para escoger y elegir los elementos de.En forma rutinaria se incluyen en los proyectos y, a continuación, sólo tiene que tirar en bits como y cuando se le necesita.

strtotime() es útil pero tiene algunos comportamientos extraños que pueden pop-up de vez en cuando si usted no es sólo la utilizan para convertir un formato de cadena de fecha y hora.

cosas como "+1 mes" o "-3 días", a veces puede no dar lo que te espera a la salida.

Para agregar una fecha, puede utilizar el método DateTime::add (Añade una cantidad de días, meses, años, horas, minutos y segundos a un objeto DateTime), disponible a partir de php 5.3.0 en adelante.

Para encontrar la diferencia entre dos fechas, hay la DateTime::diff método;pero no parece ser un método para el recuento de los días laborables entre dos fechas.

PEAR::Date parece haber algunas funciones útiles.

PEAR::Calendar también puede ser útil.

El método más sencillo es utilizar una marca de tiempo, que representa el número de segundos desde el 1 de enero de 2008.Con un tipo timestamp, usted puede hacer cosas como...

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

Echa un vistazo a la documentación de tiempo(), fecha() y la función mktime() en el php de las páginas web.Esos son los tres métodos que yo tiendo a usar con más frecuencia.

Puede utilizar una combinación de strtotime, la función mktime y fecha todo la aritmética

Aquí hay un ejemplo que utiliza un combo de todo algunos aritmética http://rushi.wordpress.com/2008/04/13/php-print-out-age-of-date-in-words/ Voy a reproducir el código aquí por simplicidad

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&nbsp; = ($total_months - $months)/12;
      echo $years . " Years ";
   }
   if($months > 0)
      echo $months . " Months";
}
?>

@Rushi no me gusta strtotime() personalmente..no sé por qué, pero he descubierto esta mañana que el paso de una cadena como esta '2008-09-11 9:5 AM' a strtotime devuelve un false...

No creo que el código que se proporciona a resolver el problema de ejemplo 'Dado dos fechas, ¿cuántos días de trabajo hay entre las dos fechas?Implementar en SQL, o $pet_lang' y no he considerar si tengo una lista de festivos...

Usted puede obtener el número de días entre dos fechas como esta:

$days = (strtotime("2008-09-10") - strtotime("2008-09-12")) / (60 * 60 * 24);

Y usted puede hacer la función de algo así (no tengo el php instalado en mi equipo de trabajo así que no puedo garantizar la sintaxis es 100% correcto)

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;
}

Si no te gusta strtotime y usted siempre tiene la fecha en el mismo formato, puede utilizar la función de explotar

list($year, $month, day) = explode("-", $date);

Recomiendo el uso de PHP 5.2 del Objetos DateTime, en lugar de utilizar las marcas de tiempo de UNIX, al hacer los cálculos de fecha.Cuando se utiliza la fecha PHP funciones que devuelven UNIX marcas de tiempo, usted tiene una gama muy limitada para trabajar (por ejemplo,nada antes de 1970).

Si usted tiene un vistazo a http://php.net/date encontrará algunos ejemplos de uso mktime() para realizar operaciones.

Un ejemplo sencillo sería el entrenamiento lo mañanas fecha sería.Usted puede hacer que mediante la adición de 1, para que el valor de día en mktime() de la siguiente manera:

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

Así que aquí, usted recibirá una fecha en el formato AAAA-MM-DD contiene mañana la fecha.También puede restar días por una simple sustitución de '+' con '-'. mktime() hace la vida mucho más fácil, y te ahorra tener que hacer declaraciones anidadas y otras problemáticas de codificación.

para obtener días de trabajo/vacaciones, postgresql CTE ftw-ver http://osssmb.wordpress.com/2009/12/02/business-days-working-days-sql-for-postgres-2/

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top