Question

Comment effectuez-vous réellement des opérations datetime telles que l'ajout de date, la recherche de différence, le nombre de jours hors week-end dans un intervalle ?J'ai personnellement commencé à transmettre certaines de ces opérations à mon système de base de données postgresql, car en général, je n'aurais besoin que d'émettre une seule instruction SQL pour obtenir une réponse. Cependant, pour le faire en PHP, je devrais écrire beaucoup plus de code, ce qui signifie plus de chances. pour que des erreurs se produisent...

Existe-t-il des bibliothèques en PHP qui effectuent des opérations datetime d'une manière qui ne nécessite pas beaucoup de code ?cela bat SQL dans une situation où « Étant donné deux dates, combien de jours ouvrables y a-t-il entre les deux dates ?Implémenter en SQL ou $pet_lang' qui est résolu en effectuant cette requête ?

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;
Était-ce utile?

La solution

L'objet DateTime de PHP5 + est utile car il est conscient du temps et de la lumière du jour, mais il a besoin d'une extension pour vraiment résoudre le problème.J'ai écrit ce qui suit pour résoudre un problème similaire.La méthode find_WeekdaysFromThisTo() est une méthode de force brute, mais elle fonctionne assez rapidement si votre période est inférieure à 2 ans.

$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

Autres conseils

Alors que pour la plupart des opérations datetime, je convertirais normalement en Unixtime et effectuerais une soustraction d'addition, etc.sur l'entier Unixtime, vous souhaiterez peut-être consulter la classe Zend_Date du framework Zend.

Cela présente de nombreuses fonctionnalités que vous décrivez.Bien que Zend soit présenté comme un "framework", il fonctionne exceptionnellement bien comme bibliothèque de classes dans laquelle sélectionner des éléments.Nous l'incluons régulièrement dans les projets, puis nous en récupérons simplement des éléments au fur et à mesure que nous en avons besoin.

strtotime() est utile mais il a des comportements étranges qui peuvent apparaître de temps en temps si vous ne l'utilisez pas uniquement pour convertir une chaîne de date/heure formatée.

des choses comme "+1 mois" ou "-3 jours" peuvent parfois ne pas vous donner ce que vous attendez.

Pour ajouter une date, vous pouvez utiliser la méthode DateHeure :: ajouter (Ajoute un nombre de jours, mois, années, heures, minutes et secondes à un objet DateTime), disponible à partir de php 5.3.0.

Pour trouver la différence entre deux dates, il y a le DateHeure ::diff méthode;mais il ne semble pas exister de méthode pour compter les jours ouvrables entre deux dates.

PEAR::Date on dirait qu'il pourrait avoir des fonctionnalités utiles.

PEAR::Calendar pourrait également être utile.

La méthode la plus simple consiste à utiliser un horodatage, représentant le nombre de secondes écoulées depuis le 1er janvier 2008.Avec un type d'horodatage, vous pouvez faire des choses comme...

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

Consultez la documentation pour temps(), date() et mktime() sur les pages Web php.Ce sont les trois méthodes que j’utilise le plus fréquemment.

Vous pouvez utiliser une combinaison de heure strtotime, mktime et date faire l'arithmétique

Voici un exemple qui utilise un combo pour faire du calcul http://rushi.wordpress.com/2008/04/13/php-print-out-age-of-date-in-words/ Je vais reproduire le code ici pour plus de simplicité

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, je n'aime pas strtotime() personnellement..je ne sais pas pourquoi mais j'ai découvert ce matin que passer une chaîne comme celle-ci '2008-09-11 9:5 AM' à strtotime renvoie un faux...

Je ne pense pas que le code que vous avez fourni résolve l'exemple de problème « Étant donné deux dates, combien de jours ouvrables y a-t-il entre les deux dates ?Implémentez en SQL ou en $pet_lang' et je ne me demande pas si j'ai une liste de jours fériés...

Vous pouvez obtenir le nombre de jours entre deux dates comme ceci :

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

Et vous pouvez créer une fonction quelque chose comme ça (je n'ai pas installé php sur mon ordinateur de travail, donc je ne peux pas garantir que la syntaxe est correcte à 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;
}

Si vous n'aimez pas strtotime et que vous avez toujours la date dans le même format, vous pouvez utiliser la fonction d'explosion comme

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

Je recommande fortement d'utiliser PHP 5.2 Objets DateHeure, plutôt que d'utiliser les horodatages UNIX, lors des calculs de date.Lorsque vous utilisez les fonctions de date PHP qui renvoient des horodatages UNIX, vous disposez d'une plage très limitée avec laquelle travailler (par ex.rien avant 1970).

Si vous jetez un oeil à http://php.net/date , vous trouverez quelques exemples d'utilisation mktime() pour effectuer des opérations.

Un exemple simple serait de déterminer quelle serait la date de demain.Vous pouvez le faire en ajoutant simplement 1 à la valeur du jour dans mktime() comme suit:

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

Donc ici, vous recevrez une date au format AAAA-MM-JJ contenant la date de demain.Vous pouvez également soustraire des jours en remplaçant simplement « + » par « - ». mktime() rend la vie beaucoup plus facile et vous évite d'avoir à faire des instructions if imbriquées et d'autres codages difficiles.

pour obtenir les jours ouvrables/vacances, postgresql CTE ftw -- voir http://osssmb.wordpress.com/2009/12/02/business-days-working-days-sql-for-postgres-2/

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top