Come calcolare la differenza tra due date usando PHP?


722

Ho due date del modulo:

Start Date: 2007-03-24 
End Date: 2009-06-26

Ora devo trovare la differenza tra questi due nella seguente forma:

2 years, 3 months and 2 days

Come posso farlo in PHP?


1
2 anni 94 giorni. Il calcolo dei mesi, tenendo conto degli anni bisestili, sarebbe problematico. Quanto deve essere accurato?
dbasnett,

Risposte:


527

Usalo per il codice legacy (PHP <5.3). Per una soluzione aggiornata, vedere la risposta di Jurka di seguito

Puoi usare strtotime () per convertire due date in unix time e quindi calcolare il numero di secondi tra di loro. Da questo è piuttosto facile calcolare diversi periodi di tempo.

$date1 = "2007-03-24";
$date2 = "2009-06-26";

$diff = abs(strtotime($date2) - strtotime($date1));

$years = floor($diff / (365*60*60*24));
$months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
$days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));

printf("%d years, %d months, %d days\n", $years, $months, $days);

Modifica: ovviamente il modo preferito per farlo è come descritto da Jurka di seguito. Il mio codice è generalmente raccomandato solo se non hai PHP 5.3 o superiore.

Diverse persone nei commenti hanno sottolineato che il codice sopra è solo un'approssimazione. Continuo a credere che per la maggior parte degli scopi vada bene, poiché l'uso di un intervallo è più per dare un'idea di quanto tempo è passato o rimane piuttosto che per fornire precisione - se vuoi farlo, basta fornire la data.

Nonostante tutto, ho deciso di affrontare i reclami. Se hai davvero bisogno di un intervallo esatto ma non hai accesso a PHP 5.3, usa il codice seguente (dovrebbe funzionare anche in PHP 4). Questa è una porta diretta del codice che PHP utilizza internamente per calcolare gli intervalli, con l'eccezione che non tiene conto dell'ora legale. Ciò significa che è spento di un'ora al massimo, ma a parte questo dovrebbe essere corretto.

<?php

/**
 * Calculate differences between two dates with precise semantics. Based on PHPs DateTime::diff()
 * implementation by Derick Rethans. Ported to PHP by Emil H, 2011-05-02. No rights reserved.
 * 
 * See here for original code:
 * http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/tm2unixtime.c?revision=302890&view=markup
 * http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/interval.c?revision=298973&view=markup
 */

function _date_range_limit($start, $end, $adj, $a, $b, $result)
{
    if ($result[$a] < $start) {
        $result[$b] -= intval(($start - $result[$a] - 1) / $adj) + 1;
        $result[$a] += $adj * intval(($start - $result[$a] - 1) / $adj + 1);
    }

    if ($result[$a] >= $end) {
        $result[$b] += intval($result[$a] / $adj);
        $result[$a] -= $adj * intval($result[$a] / $adj);
    }

    return $result;
}

function _date_range_limit_days($base, $result)
{
    $days_in_month_leap = array(31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    $days_in_month = array(31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

    _date_range_limit(1, 13, 12, "m", "y", &$base);

    $year = $base["y"];
    $month = $base["m"];

    if (!$result["invert"]) {
        while ($result["d"] < 0) {
            $month--;
            if ($month < 1) {
                $month += 12;
                $year--;
            }

            $leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0);
            $days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month];

            $result["d"] += $days;
            $result["m"]--;
        }
    } else {
        while ($result["d"] < 0) {
            $leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0);
            $days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month];

            $result["d"] += $days;
            $result["m"]--;

            $month++;
            if ($month > 12) {
                $month -= 12;
                $year++;
            }
        }
    }

    return $result;
}

function _date_normalize($base, $result)
{
    $result = _date_range_limit(0, 60, 60, "s", "i", $result);
    $result = _date_range_limit(0, 60, 60, "i", "h", $result);
    $result = _date_range_limit(0, 24, 24, "h", "d", $result);
    $result = _date_range_limit(0, 12, 12, "m", "y", $result);

    $result = _date_range_limit_days(&$base, &$result);

    $result = _date_range_limit(0, 12, 12, "m", "y", $result);

    return $result;
}

/**
 * Accepts two unix timestamps.
 */
function _date_diff($one, $two)
{
    $invert = false;
    if ($one > $two) {
        list($one, $two) = array($two, $one);
        $invert = true;
    }

    $key = array("y", "m", "d", "h", "i", "s");
    $a = array_combine($key, array_map("intval", explode(" ", date("Y m d H i s", $one))));
    $b = array_combine($key, array_map("intval", explode(" ", date("Y m d H i s", $two))));

    $result = array();
    $result["y"] = $b["y"] - $a["y"];
    $result["m"] = $b["m"] - $a["m"];
    $result["d"] = $b["d"] - $a["d"];
    $result["h"] = $b["h"] - $a["h"];
    $result["i"] = $b["i"] - $a["i"];
    $result["s"] = $b["s"] - $a["s"];
    $result["invert"] = $invert ? 1 : 0;
    $result["days"] = intval(abs(($one - $two)/86400));

    if ($invert) {
        _date_normalize(&$a, &$result);
    } else {
        _date_normalize(&$b, &$result);
    }

    return $result;
}

$date = "1986-11-10 19:37:22";

print_r(_date_diff(strtotime($date), time()));
print_r(_date_diff(time(), strtotime($date)));

1
Se stai usando la classe DateTime puoi scegliere $ date-> format ('U') per ottenere il timestamp unix.
Jon Cram,

4
Non è vero se devi occuparti dell'ora legale / estiva. In questo caso particolare quando si regola l'orario estivo / invernale, un giorno equivale a 23 o 25 ore.
Arno,

4
Bene, lo stesso argomento potrebbe essere fatto per gli anni bisestili. Non ne tiene conto neanche. Tuttavia, non sono convinto che tu voglia anche tenerne conto poiché stiamo discutendo una gamma qui. La semantica per un intervallo è leggermente diversa rispetto a una data assoluta.
Emil H,

9
Questa funzione non è corretta È buono per un'approssimazione, ma non è corretto per intervalli esatti. Per uno, presume che ci siano 30 giorni in un mese, vale a dire che avrà la stessa differenza di giorni tra il 1 ° febbraio e il 1 ° marzo rispetto al 1 ° luglio-1 ° agosto (indipendentemente dall'anno bisestile).
enobrev,

1
In PHP, le variabili di riferimento sono nella firma della funzione, non nella chiamata. Sposta tutti i tuoi &nelle firme.
Paul Tarjan,

909

Suggerisco di usare gli oggetti DateTime e DateInterval.

$date1 = new DateTime("2007-03-24");
$date2 = new DateTime("2009-06-26");
$interval = $date1->diff($date2);
echo "difference " . $interval->y . " years, " . $interval->m." months, ".$interval->d." days "; 

// shows the total amount of days (not divided into years, months and days like above)
echo "difference " . $interval->days . " days ";

leggi di più php DateTime :: manuale diff

Dal manuale:

A partire da PHP 5.2.2, gli oggetti DateTime possono essere confrontati usando operatori di confronto.

$date1 = new DateTime("now");
$date2 = new DateTime("tomorrow");

var_dump($date1 == $date2); // bool(false)
var_dump($date1 < $date2);  // bool(true)
var_dump($date1 > $date2);  // bool(false)

14
+1 DateTime gestisce correttamente gli anni bisestili e i fusi orari e c'è un buon libro per lo scaffale: phparch.com/books/…
hakre

3
Esiste un metodo che fornisce il numero totale di secondi tra i due DateTimes? (senza aggiungere i componenti, cioè)
potatoe,

1
@Panique $ intervallo-> giorni e $ intervallo-> d sono misure diverse. il tuo commento sopra è giusto "mostra il numero totale di giorni (non diviso in anni, mesi e giorni come sopra)"
jurka,

1
@potatoe Probabilmente vuoi $date2->format('U') - $date1->format('U').
Paulo Freitas,

3
si noti che esiste un bug in cui DateInterval ha una proprietà giorni errata ( sempre 6015 ) su Windows con alcune versioni di PHP: bugs.php.net/bug.php?id=51184 (fare riferimento ai commenti lì per correzione / soluzione alternativa)
Pim Schaaf

73

Il miglior modo di agire è usare gli oggetti DateTime(e DateInterval) di PHP . Ogni data è incapsulata in un DateTimeoggetto, quindi può essere fatta una differenza tra i due:

$first_date = new DateTime("2012-11-30 17:03:30");
$second_date = new DateTime("2012-12-21 00:00:00");

L' DateTimeoggetto accetterà qualsiasi formato strtotime(). Se è necessario un formato data ancora più specifico, è DateTime::createFromFormat()possibile utilizzare per creare l' DateTimeoggetto.

Dopo che entrambi gli oggetti sono stati istanziati, si sottrae l'uno dall'altro con DateTime::diff().

$difference = $first_date->diff($second_date);

$differenceora contiene un DateIntervaloggetto con le informazioni sulla differenza. A si var_dump()presenta così:

object(DateInterval)
  public 'y' => int 0
  public 'm' => int 0
  public 'd' => int 20
  public 'h' => int 6
  public 'i' => int 56
  public 's' => int 30
  public 'invert' => int 0
  public 'days' => int 20

Per formattare l' DateIntervaloggetto, dovremo controllare ciascun valore ed escluderlo se è 0:

/**
 * Format an interval to show all existing components.
 * If the interval doesn't have a time component (years, months, etc)
 * That component won't be displayed.
 *
 * @param DateInterval $interval The interval
 *
 * @return string Formatted interval string.
 */
function format_interval(DateInterval $interval) {
    $result = "";
    if ($interval->y) { $result .= $interval->format("%y years "); }
    if ($interval->m) { $result .= $interval->format("%m months "); }
    if ($interval->d) { $result .= $interval->format("%d days "); }
    if ($interval->h) { $result .= $interval->format("%h hours "); }
    if ($interval->i) { $result .= $interval->format("%i minutes "); }
    if ($interval->s) { $result .= $interval->format("%s seconds "); }

    return $result;
}

Non resta che chiamare la nostra funzione $difference DateIntervalsull'oggetto:

echo format_interval($difference);

E otteniamo il risultato corretto:

20 giorni 6 ore 56 minuti 30 secondi

Il codice completo utilizzato per raggiungere l'obiettivo:

/**
 * Format an interval to show all existing components.
 * If the interval doesn't have a time component (years, months, etc)
 * That component won't be displayed.
 *
 * @param DateInterval $interval The interval
 *
 * @return string Formatted interval string.
 */
function format_interval(DateInterval $interval) {
    $result = "";
    if ($interval->y) { $result .= $interval->format("%y years "); }
    if ($interval->m) { $result .= $interval->format("%m months "); }
    if ($interval->d) { $result .= $interval->format("%d days "); }
    if ($interval->h) { $result .= $interval->format("%h hours "); }
    if ($interval->i) { $result .= $interval->format("%i minutes "); }
    if ($interval->s) { $result .= $interval->format("%s seconds "); }

    return $result;
}

$first_date = new DateTime("2012-11-30 17:03:30");
$second_date = new DateTime("2012-12-21 00:00:00");

$difference = $first_date->diff($second_date);

echo format_interval($difference);

DateTime()non è una funzione, è un oggetto ed è presente da PHP 5.2. Assicurati che il tuo server lo supporti.
Madara's Ghost il

2
@SecondRikudo DateTime :: Diff need PHP 5.3.0
PhoneixS

Abbiamo un problema, scambia first_date in second_date e stiamo ottenendo lo stesso risultato? Perché non dire 0 giorni 0 ore 0 minuti 0 secondi o solo 0. Esempio: 2012-11-30 17:03:30 - 2012-12-21 00:00:00 e 2012-12-21 00:00:00 - 30/11/2012 17:03:30 ottieni lo stesso risultato.
EgoistDeveloper

Perché diff ti dà la differenza tra le due volte. La differenza non è 0 indipendentemente dalla data successiva.
Madara's Ghost il

1
Questa è davvero una buona risposta in quanto fornisce una chiara funzione che può essere chiamata da qualsiasi parte in una base di codice senza molti calcoli di tempo. Altre risposte ti permettono di eliminare al volo calc echi che affrontano i sintomi piuttosto che risolvere il problema ... L'unico elemento che ho aggiunto (e praticamente tutti gli altri post non coprono questo) è la pluralizzazione di $ intervallo di elementi se più di 1.
nickhar

33

Visualizza ore, minuti e secondi

$date1 = "2008-11-01 22:45:00"; 

$date2 = "2009-12-04 13:44:01"; 

$diff = abs(strtotime($date2) - strtotime($date1)); 

$years   = floor($diff / (365*60*60*24)); 
$months  = floor(($diff - $years * 365*60*60*24) / (30*60*60*24)); 
$days    = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));

$hours   = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24)/ (60*60)); 

$minuts  = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24 - $hours*60*60)/ 60); 

$seconds = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24 - $hours*60*60 - $minuts*60)); 

printf("%d years, %d months, %d days, %d hours, %d minuts\n, %d seconds\n", $years, $months, $days, $hours, $minuts, $seconds); 

7
Probabilmente questo non darà il risultato accurato.
Dolphin,

8
Ed è una soluzione terribile a meno che tu non sia costretto a utilizzare una versione terribilmente obsoleta di PHP ...
rdlowrey

2
Non così ASCIUTTO . Ad esempio, 60 * 60 * 24 viene ripetuto 15 volte. Lunga vita al riutilizzo del copia-incolla!
Peter Mortensen,

Che dire degli anni bisestili? Un anno non è in media 365 giorni.
Peter Mortensen,

Questo codice presuppone che un mese sia in media 30 giorni. Anche ipotizzando 365 giorni per un anno, un mese medio è 365/12 = 30,42 giorni (circa).
Peter Mortensen,

18

Dai un'occhiata al seguente link. Questa è la migliore risposta che ho trovato finora .. :)

function dateDiff ($d1, $d2) {

    // Return the number of days between the two dates:    
    return round(abs(strtotime($d1) - strtotime($d2))/86400);

} // end function dateDiff

Non importa quale data sia precedente o successiva quando si passano i parametri della data. La funzione utilizza il valore assoluto di PHP ABS () per restituire sempre un numero postivo come numero di giorni tra le due date.

Tieni presente che il numero di giorni tra le due date NON è comprensivo di entrambe le date. Quindi, se stai cercando il numero di giorni rappresentato da tutte le date comprese e comprese le date inserite, dovrai aggiungere uno (1) al risultato di questa funzione.

Ad esempio, la differenza (come restituita dalla funzione sopra) tra il 2013-02-09 e il 2013-02-14 è 5. Ma il numero di giorni o date rappresentati dall'intervallo di date 2013-02-09 - 2013-02- 14 è 6.

http://www.bizinfosys.com/php/date-difference.html


La domanda chiedeva la differenza come il numero di anni, mesi e giorni, non il numero totale di giorni.
Peter Mortensen,

14

Ho votato a favore della risposta di Jurka in quanto è la mia preferita, ma ho una versione pre-php.5.3 ...

Mi sono ritrovato a lavorare su un problema simile - che è come ho ottenuto questa domanda in primo luogo - ma avevo solo bisogno di una differenza di ore. Ma la mia funzione ha risolto anche questo abbastanza bene e non ho da nessuna parte nella mia libreria per tenerlo dove non andrà perso e dimenticato, quindi ... spero che questo sia utile a qualcuno.

/**
 *
 * @param DateTime $oDate1
 * @param DateTime $oDate2
 * @return array 
 */
function date_diff_array(DateTime $oDate1, DateTime $oDate2) {
    $aIntervals = array(
        'year'   => 0,
        'month'  => 0,
        'week'   => 0,
        'day'    => 0,
        'hour'   => 0,
        'minute' => 0,
        'second' => 0,
    );

    foreach($aIntervals as $sInterval => &$iInterval) {
        while($oDate1 <= $oDate2){ 
            $oDate1->modify('+1 ' . $sInterval);
            if ($oDate1 > $oDate2) {
                $oDate1->modify('-1 ' . $sInterval);
                break;
            } else {
                $iInterval++;
            }
        }
    }

    return $aIntervals;
}

E il test:

$oDate = new DateTime();
$oDate->modify('+111402189 seconds');
var_dump($oDate);
var_dump(date_diff_array(new DateTime(), $oDate));

E il risultato:

object(DateTime)[2]
  public 'date' => string '2014-04-29 18:52:51' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'America/New_York' (length=16)

array
  'year'   => int 3
  'month'  => int 6
  'week'   => int 1
  'day'    => int 4
  'hour'   => int 9
  'minute' => int 3
  'second' => int 8

Ho avuto l'idea originale da qui , che ho modificato per i miei usi (e spero che la mia modifica verrà mostrata anche su quella pagina).

Puoi rimuovere facilmente gli intervalli che non desideri (ad esempio "settimana") rimuovendoli $aIntervalsdall'array o magari aggiungendo un $aExcludeparametro o semplicemente filtrandoli quando emetti la stringa.


Purtroppo questo non restituisce la stessa cosa di DateInterval a causa di overflow di anno / mese.
Stephen Harris,

2
@StephenHarris: non l'ho provato, ma leggendo il codice sono abbastanza sicuro che dovrebbe restituire lo stesso risultato, a condizione che tu elimini l' weekindice $aIntervals(dal momento che DateDiffnon lo usa mai).
Alix Axel,

Questa è un'ottima soluzione per trovare le date che si verificano ogni intervallo tra due date.
tra il

14
<?php
    $today = strtotime("2011-02-03 00:00:00");
    $myBirthDate = strtotime("1964-10-30 00:00:00");
    printf("Days since my birthday: ", ($today - $myBirthDate)/60/60/24);
?>

La domanda chiedeva la differenza come numero di anni , mesi e giorni . Ciò genera la differenza come numero totale di giorni.
Peter Mortensen,

11

Non so se stai usando un framework PHP o meno, ma molti framework PHP hanno librerie di data / ora e aiutanti per aiutarti a reinventare la ruota.

Ad esempio CodeIgniter ha la timespan()funzione. Basta inserire due timestamp Unix e genererà automaticamente un risultato come questo:

1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes

http://codeigniter.com/user_guide/helpers/date_helper.html


8

Usa esempio:

echo time_diff_string('2013-05-01 00:22:35', 'now');
echo time_diff_string('2013-05-01 00:22:35', 'now', true);

Produzione :

4 months ago
4 months, 2 weeks, 3 days, 1 hour, 49 minutes, 15 seconds ago

Funzione :

function time_diff_string($from, $to, $full = false) {
    $from = new DateTime($from);
    $to = new DateTime($to);
    $diff = $to->diff($from);

    $diff->w = floor($diff->d / 7);
    $diff->d -= $diff->w * 7;

    $string = array(
        'y' => 'year',
        'm' => 'month',
        'w' => 'week',
        'd' => 'day',
        'h' => 'hour',
        'i' => 'minute',
        's' => 'second',
    );
    foreach ($string as $k => &$v) {
        if ($diff->$k) {
            $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
        } else {
            unset($string[$k]);
        }
    }

    if (!$full) $string = array_slice($string, 0, 1);
    return $string ? implode(', ', $string) . ' ago' : 'just now';
}

se voglio determinare se la differenza è maggiore di 30 minuti, cosa devo fare?
Ofir Attia,

@OfirAttia: hai un sacco di domande come questa qui su SO, basta usare la ricerca. Demo semplice
Glavić,

7

Ho una semplice logica per questo:

<?php
    per_days_diff('2011-12-12','2011-12-29')
    function per_days_diff($start_date, $end_date) {
        $per_days = 0;
        $noOfWeek = 0;
        $noOfWeekEnd = 0;
        $highSeason=array("7", "8");

        $current_date = strtotime($start_date);
        $current_date += (24 * 3600);
        $end_date = strtotime($end_date);

        $seassion = (in_array(date('m', $current_date), $highSeason))?"2":"1";

        $noOfdays = array('');

        while ($current_date <= $end_date) {
            if ($current_date <= $end_date) {
                $date = date('N', $current_date);
                array_push($noOfdays,$date);
                $current_date = strtotime('+1 day', $current_date);
            }
        }

        $finalDays = array_shift($noOfdays);
        //print_r($noOfdays);
        $weekFirst = array("week"=>array(),"weekEnd"=>array());
        for($i = 0; $i < count($noOfdays); $i++)
        {
            if ($noOfdays[$i] == 1)
            {
                //echo "This is week";
                //echo "<br/>";
                if($noOfdays[$i+6]==7)
                {
                    $noOfWeek++;
                    $i=$i+6;
                }
                else
                {
                    $per_days++;
                }
                //array_push($weekFirst["week"],$day);
            }
            else if($noOfdays[$i]==5)
            {
                //echo "This is weekend";
                //echo "<br/>";
                if($noOfdays[$i+2] ==7)
                {
                    $noOfWeekEnd++;
                    $i = $i+2;
                }
                else
                {
                    $per_days++;
                }
                //echo "After weekend value:- ".$i;
                //echo "<br/>";
            }
            else
            {
                $per_days++;
            }
        }

        /*echo $noOfWeek;
          echo "<br/>";
          echo $noOfWeekEnd;
          echo "<br/>";
          print_r($per_days);
          echo "<br/>";
          print_r($weekFirst);
        */

        $duration = array("weeks"=>$noOfWeek, "weekends"=>$noOfWeekEnd, "perDay"=>$per_days, "seassion"=>$seassion);
        return $duration;
      ?>

Sembra che manchi qualcosa alla fine del codice di esempio (una parentesi graffa finale e " ?> "?).
Peter Mortensen,

logica "semplice". Queste sono almeno 40 righe di codice puro.
Madjosz,

6

Puoi usare il

getdate()

funzione che restituisce un array contenente tutti gli elementi della data / ora forniti:

$diff = abs($endDate - $startDate);
$my_t=getdate($diff);
print("$my_t[year] years, $my_t[month] months and $my_t[mday] days");

Se le date di inizio e fine sono in formato stringa, utilizzare

$startDate = strtotime($startDateStr);
$endDate = strtotime($endDateStr);

prima del codice sopra


non sembra funzionare. Ricevo un appuntamento all'inizio dell'era del timestamp.
Sirber,

È importante capire che è necessario fare un $my_t["year"] -= 1970per ottenere il numero corretto di anni. È inoltre necessario sottrarre la differenza oraria da GMT per ottenere le ore giuste. Devi sottrarre 1 anche dal mese e dalla data.
Salman,

6
// If you just want to see the year difference then use this function.
// Using the logic I've created you may also create month and day difference
// which I did not provide here so you may have the efforts to use your brain.
// :)
$date1='2009-01-01';
$date2='2010-01-01';
echo getYearDifference ($date1,$date2);
function getYearDifference($date1=strtotime($date1),$date2=strtotime($date2)){
    $year = 0;
    while($date2 > $date1 = strtotime('+1 year', $date1)){
        ++$year;
    }
    return $year;
}

"Strtotime ('+ 1 year', $ date1)" tiene conto degli anni bisestili?
Peter Mortensen,

6

Questa è la mia funzione PHP richiesto> = 5.3.4. Utilizza la classe DateTime. Molto veloce, veloce e può fare la differenza tra due date o anche il cosiddetto "tempo da".

if(function_exists('grk_Datetime_Since') === FALSE){
    function grk_Datetime_Since($From, $To='', $Prefix='', $Suffix=' ago', $Words=array()){
        #   Est-ce qu'on calcul jusqu'à un moment précis ? Probablement pas, on utilise maintenant
        if(empty($To) === TRUE){
            $To = time();
        }

        #   On va s'assurer que $From est numérique
        if(is_int($From) === FALSE){
            $From = strtotime($From);
        };

        #   On va s'assurer que $To est numérique
        if(is_int($To) === FALSE){
            $To = strtotime($To);
        }

        #   On a une erreur ?
        if($From === FALSE OR $From === -1 OR $To === FALSE OR $To === -1){
            return FALSE;
        }

        #   On va créer deux objets de date
        $From = new DateTime(@date('Y-m-d H:i:s', $From), new DateTimeZone('GMT'));
        $To   = new DateTime(@date('Y-m-d H:i:s', $To), new DateTimeZone('GMT'));

        #   On va calculer la différence entre $From et $To
        if(($Diff = $From->diff($To)) === FALSE){
            return FALSE;
        }

        #   On va merger le tableau des noms (par défaut, anglais)
        $Words = array_merge(array(
            'year'      => 'year',
            'years'     => 'years',
            'month'     => 'month',
            'months'    => 'months',
            'week'      => 'week',
            'weeks'     => 'weeks',
            'day'       => 'day',
            'days'      => 'days',
            'hour'      => 'hour',
            'hours'     => 'hours',
            'minute'    => 'minute',
            'minutes'   => 'minutes',
            'second'    => 'second',
            'seconds'   => 'seconds'
        ), $Words);

        #   On va créer la chaîne maintenant
        if($Diff->y > 1){
            $Text = $Diff->y.' '.$Words['years'];
        } elseif($Diff->y == 1){
            $Text = '1 '.$Words['year'];
        } elseif($Diff->m > 1){
            $Text = $Diff->m.' '.$Words['months'];
        } elseif($Diff->m == 1){
            $Text = '1 '.$Words['month'];
        } elseif($Diff->d > 7){
            $Text = ceil($Diff->d/7).' '.$Words['weeks'];
        } elseif($Diff->d == 7){
            $Text = '1 '.$Words['week'];
        } elseif($Diff->d > 1){
            $Text = $Diff->d.' '.$Words['days'];
        } elseif($Diff->d == 1){
            $Text = '1 '.$Words['day'];
        } elseif($Diff->h > 1){
            $Text = $Diff->h.' '.$Words['hours'];
        } elseif($Diff->h == 1){
            $Text = '1 '.$Words['hour'];
        } elseif($Diff->i > 1){
            $Text = $Diff->i.' '.$Words['minutes'];
        } elseif($Diff->i == 1){
            $Text = '1 '.$Words['minute'];
        } elseif($Diff->s > 1){
            $Text = $Diff->s.' '.$Words['seconds'];
        } else {
            $Text = '1 '.$Words['second'];
        }

        return $Prefix.$Text.$Suffix;
    }
}

6

Preferirei usare date_createe date_diffoggetti.

Codice:

$date1 = date_create("2007-03-24");
$date2 = date_create("2009-06-26");

$dateDifference = date_diff($date1, $date2)->format('%y years, %m months and %d days');

echo $dateDifference;

Produzione:

2 years, 3 months and 2 days

Per maggiori informazioni leggi il date_diffmanuale di PHP

Secondo il manuale date_diffè un alias di DateTime :: diff ()


5

Questo tenterà di rilevare se è stato dato un timestamp o meno e restituirà anche date / orari futuri come valori negativi:

<?php

function time_diff($start, $end = NULL, $convert_to_timestamp = FALSE) {
  // If $convert_to_timestamp is not explicitly set to TRUE,
  // check to see if it was accidental:
  if ($convert_to_timestamp || !is_numeric($start)) {
    // If $convert_to_timestamp is TRUE, convert to timestamp:
    $timestamp_start = strtotime($start);
  }
  else {
    // Otherwise, leave it as a timestamp:
    $timestamp_start = $start;
  }
  // Same as above, but make sure $end has actually been overridden with a non-null,
  // non-empty, non-numeric value:
  if (!is_null($end) && (!empty($end) && !is_numeric($end))) {
    $timestamp_end = strtotime($end);
  }
  else {
    // If $end is NULL or empty and non-numeric value, assume the end time desired
    // is the current time (useful for age, etc):
    $timestamp_end = time();
  }
  // Regardless, set the start and end times to an integer:
  $start_time = (int) $timestamp_start;
  $end_time = (int) $timestamp_end;

  // Assign these values as the params for $then and $now:
  $start_time_var = 'start_time';
  $end_time_var = 'end_time';
  // Use this to determine if the output is positive (time passed) or negative (future):
  $pos_neg = 1;

  // If the end time is at a later time than the start time, do the opposite:
  if ($end_time <= $start_time) {
    $start_time_var = 'end_time';
    $end_time_var = 'start_time';
    $pos_neg = -1;
  }

  // Convert everything to the proper format, and do some math:
  $then = new DateTime(date('Y-m-d H:i:s', $$start_time_var));
  $now = new DateTime(date('Y-m-d H:i:s', $$end_time_var));

  $years_then = $then->format('Y');
  $years_now = $now->format('Y');
  $years = $years_now - $years_then;

  $months_then = $then->format('m');
  $months_now = $now->format('m');
  $months = $months_now - $months_then;

  $days_then = $then->format('d');
  $days_now = $now->format('d');
  $days = $days_now - $days_then;

  $hours_then = $then->format('H');
  $hours_now = $now->format('H');
  $hours = $hours_now - $hours_then;

  $minutes_then = $then->format('i');
  $minutes_now = $now->format('i');
  $minutes = $minutes_now - $minutes_then;

  $seconds_then = $then->format('s');
  $seconds_now = $now->format('s');
  $seconds = $seconds_now - $seconds_then;

  if ($seconds < 0) {
    $minutes -= 1;
    $seconds += 60;
  }
  if ($minutes < 0) {
    $hours -= 1;
    $minutes += 60;
  }
  if ($hours < 0) {
    $days -= 1;
    $hours += 24;
  }
  $months_last = $months_now - 1;
  if ($months_now == 1) {
    $years_now -= 1;
    $months_last = 12;
  }

  // "Thirty days hath September, April, June, and November" ;)
  if ($months_last == 9 || $months_last == 4 || $months_last == 6 || $months_last == 11) {
    $days_last_month = 30;
  }
  else if ($months_last == 2) {
    // Factor in leap years:
    if (($years_now % 4) == 0) {
      $days_last_month = 29;
    }
    else {
      $days_last_month = 28;
    }
  }
  else {
    $days_last_month = 31;
  }
  if ($days < 0) {
    $months -= 1;
    $days += $days_last_month;
  }
  if ($months < 0) {
    $years -= 1;
    $months += 12;
  }

  // Finally, multiply each value by either 1 (in which case it will stay the same),
  // or by -1 (in which case it will become negative, for future dates).
  // Note: 0 * 1 == 0 * -1 == 0
  $out = new stdClass;
  $out->years = (int) $years * $pos_neg;
  $out->months = (int) $months * $pos_neg;
  $out->days = (int) $days * $pos_neg;
  $out->hours = (int) $hours * $pos_neg;
  $out->minutes = (int) $minutes * $pos_neg;
  $out->seconds = (int) $seconds * $pos_neg;
  return $out;
}

Esempio di utilizzo:

<?php
  $birthday = 'June 2, 1971';
  $check_age_for_this_date = 'June 3, 1999 8:53pm';
  $age = time_diff($birthday, $check_age_for_this_date)->years;
  print $age;// 28

O:

<?php
  $christmas_2020 = 'December 25, 2020';
  $countdown = time_diff($christmas_2020);
  print_r($countdown);

5

"se" la data è memorizzata in MySQL, trovo più facile fare il calcolo della differenza a livello di database ... Quindi, in base all'output di Giorno, Ora, Min, Sec, analizzare e visualizzare i risultati come appropriato ...

mysql> select firstName, convert_tz(loginDate, '+00:00', '-04:00') as loginDate, TIMESTAMPDIFF(DAY, loginDate, now()) as 'Day', TIMESTAMPDIFF(HOUR, loginDate, now())+4 as 'Hour', TIMESTAMPDIFF(MINUTE, loginDate, now())+(60*4) as 'Min', TIMESTAMPDIFF(SECOND, loginDate, now())+(60*60*4) as 'Sec' from User_ where userId != '10158' AND userId != '10198' group by emailAddress order by loginDate desc;
 +-----------+---------------------+------+------+------+--------+
 | firstName | loginDate           | Day  | Hour | Min  | Sec    |
 +-----------+---------------------+------+------+------+--------+
 | Peter     | 2014-03-30 18:54:40 |    0 |    4 |  244 |  14644 |
 | Keith     | 2014-03-30 18:54:11 |    0 |    4 |  244 |  14673 |
 | Andres    | 2014-03-28 09:20:10 |    2 |   61 | 3698 | 221914 |
 | Nadeem    | 2014-03-26 09:33:43 |    4 |  109 | 6565 | 393901 |
 +-----------+---------------------+------+------+------+--------+
 4 rows in set (0.00 sec)

5

Ho trovato il tuo articolo nella pagina seguente, che contiene una serie di riferimenti per i calcoli della data e ora di PHP .

Calcola la differenza tra due Date (e tempo) usando PHP. La pagina seguente fornisce una gamma di metodi diversi (7 in totale) per eseguire calcoli di data / ora utilizzando PHP, per determinare la differenza di tempo (ore, muniti), giorni, mesi o anni tra due date.

Vedi PHP Date Time - 7 metodi per calcolare la differenza tra 2 date .


4

Puoi anche usare il seguente codice per restituire la data di differenza per frazioni arrotondate fino a $ date1 = $ duedate; // assegna eco data di scadenza $ date2 = data ("Ymd"); // data corrente $ ts1 = strtotime ($ date1); $ ts2 = strtotime ($ date2); $ seconds_diff = $ ts1 - $ ts2; echo $ datiff = ceil (($ seconds_diff / 3600) / 24); // ritorno tra giorni

Se usi il metodo floor di php invece di ceil ti restituirà la frazione rotonda verso il basso. Controlla qui la differenza, alcune volte se il fuso orario dei server di gestione temporanea è diverso dal fuso orario del sito live in tal caso, potresti ottenere risultati diversi, quindi modifica le condizioni di conseguenza.


4
$date1 = date_create('2007-03-24');
$date2 = date_create('2009-06-26');
$interval = date_diff($date1, $date2);
echo "difference : " . $interval->y . " years, " . $interval->m." months, ".$interval->d." days ";

4

puoi sempre utilizzare la seguente funzione che può restituire l'età in anni e mesi (es. 1 anno 4 mesi)

function getAge($dob, $age_at_date)
{  
    $d1 = new DateTime($dob);
    $d2 = new DateTime($age_at_date);
    $age = $d2->diff($d1);
    $years = $age->y;
    $months = $age->m;

    return $years.'.'.months;
}

o se vuoi che l'età sia calcolata alla data corrente, puoi usare

function getAge($dob)
{  
    $d1 = new DateTime($dob);
    $d2 = new DateTime(date());
    $age = $d2->diff($d1);
    $years = $age->y;
    $months = $age->m;

    return $years.'.'.months;
}

4

Per versione php> = 5.3: creare due oggetti data e quindi utilizzare la date_diff()funzione. Restituirà l' oggetto DateInterval php . vedi documentazione

$date1=date_create("2007-03-24");
$date2=date_create("2009-06-26");
$diff=date_diff($date1,$date2);
echo $diff->format("%R%a days");

4

Ecco il codice eseguibile

$date1 = date_create('2007-03-24');
$date2 = date_create('2009-06-26');
$diff1 = date_diff($date1,$date2);
$daysdiff = $diff1->format("%R%a");
$daysdiff = abs($daysdiff);

3

Ho avuto lo stesso problema con PHP 5.2 e risolto con MySQL. Potrebbe non essere esattamente quello che stai cercando, ma questo farà il trucco e restituirà il numero di giorni:

$datediff_q = $dbh->prepare("SELECT DATEDIFF(:date2, :date1)");
$datediff_q->bindValue(':date1', '2007-03-24', PDO::PARAM_STR);
$datediff_q->bindValue(':date2', '2009-06-26', PDO::PARAM_STR);
$datediff = ($datediff_q->execute()) ? $datediff_q->fetchColumn(0) : false;

Maggiori informazioni qui http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_datediff


3

Dal momento che tutti pubblicano esempi di codice, ecco un'altra versione.

Volevo che una funzione mostrasse differenze da secondi a anni (solo una unità). Per periodi superiori a 1 giorno, ho voluto che si ribaltasse a mezzanotte (il lunedì delle 10 visto dalle 9 di mercoledì 2 giorni fa, non 1). E per periodi superiori a un mese, volevo che il rollover avvenisse nello stesso giorno del mese (incluso per 30/31 giorni del mese e anni bisestili).

Questo è quello che mi è venuto in mente:

/**
 * Returns how long ago something happened in the past, showing it
 * as n seconds / minutes / hours / days / weeks / months / years ago.
 *
 * For periods over a day, it rolls over at midnight (so doesn't depend
 * on current time of day), and it correctly accounts for month-lengths
 * and leap-years (months and years rollover on current day of month).
 *
 * $param string $timestamp in DateTime format
 * $return string description of interval
 */
function ago($timestamp)
{
    $then = date_create($timestamp);

    // for anything over 1 day, make it rollover on midnight
    $today = date_create('tomorrow'); // ie end of today
    $diff = date_diff($then, $today);

    if ($diff->y > 0) return $diff->y.' year'.($diff->y>1?'s':'').' ago';
    if ($diff->m > 0) return $diff->m.' month'.($diff->m>1?'s':'').' ago';
    $diffW = floor($diff->d / 7);
    if ($diffW > 0) return $diffW.' week'.($diffW>1?'s':'').' ago';
    if ($diff->d > 1) return $diff->d.' day'.($diff->d>1?'s':'').' ago';

    // for anything less than 1 day, base it off 'now'
    $now = date_create();
    $diff = date_diff($then, $now);

    if ($diff->d > 0) return 'yesterday';
    if ($diff->h > 0) return $diff->h.' hour'.($diff->h>1?'s':'').' ago';
    if ($diff->i > 0) return $diff->i.' minute'.($diff->i>1?'s':'').' ago';
    return $diff->s.' second'.($diff->s==1?'':'s').' ago';
}

3

Qualche tempo fa ho scritto una format_datefunzione in quanto offre molte opzioni su come vuoi la tua data :

function format_date($date, $type, $seperator="-")
{
    if($date)
    {
        $day = date("j", strtotime($date));
        $month = date("n", strtotime($date));
        $year = date("Y", strtotime($date));
        $hour = date("H", strtotime($date));
        $min = date("i", strtotime($date));
        $sec = date("s", strtotime($date));

        switch($type)
        {
            case 0:  $date = date("Y".$seperator."m".$seperator."d",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 1:  $date = date("D, F j, Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 2:  $date = date("d".$seperator."m".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 3:  $date = date("d".$seperator."M".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 4:  $date = date("d".$seperator."M".$seperator."Y h:i A",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 5:  $date = date("m".$seperator."d".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 6:  $date = date("M",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 7:  $date = date("Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 8:  $date = date("j",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 9:  $date = date("n",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 10: 
                     $diff = abs(strtotime($date) - strtotime(date("Y-m-d h:i:s"))); 
                     $years = floor($diff / (365*60*60*24));
                     $months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
                     $days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));
                     $date = $years . " years, " . $months . " months, " . $days . "days";
        }
    }
    return($date);
}    

2
Questa risposta è sbagliata quanto la risposta di Khaldonno. Presuppone (caso 10) che un anno abbia 365 giorni (ogni quarto anno ha 366 giorni (tranne per le regole 100 anni / 400 anni per il calendario gregoriano)) e che un mese ha 30 giorni (sono circa 30,42 giorni circa negli anni non bisestili). Anche con costanti migliori è corretto solo in media, non necessariamente corretto per due date particolari.
Peter Mortensen,

3

Molto semplice:

    <?php
        $date1 = date_create("2007-03-24");
        echo "Start date: ".$date1->format("Y-m-d")."<br>";
        $date2 = date_create("2009-06-26");
        echo "End date: ".$date2->format("Y-m-d")."<br>";
        $diff = date_diff($date1,$date2);
        echo "Difference between start date and end date: ".$diff->format("%y years, %m months and %d days")."<br>";
    ?>

Si prega di controllare il seguente link per i dettagli:

PHP: date_diff - Manuale

Nota che è per PHP 5.3.0 o versioni successive.


3

Una funzione facile

function time_difference($time_1, $time_2, $limit = null)
{

    $val_1 = new DateTime($time_1);
    $val_2 = new DateTime($time_2);

    $interval = $val_1->diff($val_2);

    $output = array(
        "year" => $interval->y,
        "month" => $interval->m,
        "day" => $interval->d,
        "hour" => $interval->h,
        "minute" => $interval->i,
        "second" => $interval->s
    );

    $return = "";
    foreach ($output AS $key => $value) {

        if ($value == 1)
            $return .= $value . " " . $key . " ";
        elseif ($value >= 1)
            $return .= $value . " " . $key . "s ";

        if ($key == $limit)
            return trim($return);
    }
    return trim($return);
}

Usa come

echo time_difference ($time_1, $time_2, "day");

Tornerà come 2 years 8 months 2 days


3

Prova questa risposta molto semplice usando date_diff () , questo è testato.

$date1 = date_create("2017-11-27");
$date2 = date_create("2018-12-29");
$diff=date_diff($date1,$date2);
$months = $diff->format("%m months");
$years = $diff->format("%y years");
$days = $diff->format("%d days");

echo $years .' '.$months.' '.$days;

l'output è:

1 years 1 months 2 days

2

Sto usando la seguente funzione che ho scritto, quando PHP 5.3 (rispettivamente date_diff ()) non è disponibile:

        function dateDifference($startDate, $endDate)
        {
            $startDate = strtotime($startDate);
            $endDate = strtotime($endDate);
            if ($startDate === false || $startDate < 0 || $endDate === false || $endDate < 0 || $startDate > $endDate)
                return false;

            $years = date('Y', $endDate) - date('Y', $startDate);

            $endMonth = date('m', $endDate);
            $startMonth = date('m', $startDate);

            // Calculate months
            $months = $endMonth - $startMonth;
            if ($months <= 0)  {
                $months += 12;
                $years--;
            }
            if ($years < 0)
                return false;

            // Calculate the days
            $measure = ($months == 1) ? 'month' : 'months';
            $days = $endDate - strtotime('+' . $months . ' ' . $measure, $startDate);
            $days = date('z', $days);   

            return array($years, $months, $days);
        }

2

DateInterval è fantastico ma ha un paio di avvertenze:

  1. solo per PHP 5.3+ ( ma non è più una buona scusa )
  2. supporta solo anni, mesi, giorni, ore, minuti e secondi (nessuna settimana)
  3. calcola la differenza con tutti i precedenti + giorni (non puoi ottenere la differenza solo in mesi)

Per ovviare a questo, ho codificato il seguente (migliorato dalla risposta @enobrev ):

function date_dif($since, $until, $keys = 'year|month|week|day|hour|minute|second')
{
    $date = array_map('strtotime', array($since, $until));

    if ((count($date = array_filter($date, 'is_int')) == 2) && (sort($date) === true))
    {
        $result = array_fill_keys(explode('|', $keys), 0);

        foreach (preg_grep('~^(?:year|month)~i', $result) as $key => $value)
        {
            while ($date[1] >= strtotime(sprintf('+%u %s', $value + 1, $key), $date[0]))
            {
                ++$value;
            }

            $date[0] = strtotime(sprintf('+%u %s', $result[$key] = $value, $key), $date[0]);
        }

        foreach (preg_grep('~^(?:year|month)~i', $result, PREG_GREP_INVERT) as $key => $value)
        {
            if (($value = intval(abs($date[0] - $date[1]) / strtotime(sprintf('%u %s', 1, $key), 0))) > 0)
            {
                $date[0] = strtotime(sprintf('+%u %s', $result[$key] = $value, $key), $date[0]);
            }
        }

        return $result;
    }

    return false;
}

Esegue due anelli; il primo si occupa degli intervalli relativi (anni e mesi) tramite forzatura bruta, e il secondo calcola gli intervalli assoluti aggiuntivi con una semplice aritmetica (quindi è più veloce):

echo humanize(date_dif('2007-03-24', '2009-07-31', 'second')); // 74300400 seconds
echo humanize(date_dif('2007-03-24', '2009-07-31', 'minute|second')); // 1238400 minutes, 0 seconds
echo humanize(date_dif('2007-03-24', '2009-07-31', 'hour|minute|second')); // 20640 hours, 0 minutes, 0 seconds
echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|day')); // 2 years, 129 days
echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|week')); // 2 years, 18 weeks
echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|week|day')); // 2 years, 18 weeks, 3 days
echo humanize(date_dif('2007-03-24', '2009-07-31')); // 2 years, 4 months, 1 week, 0 days, 0 hours, 0 minutes, 0 seconds

function humanize($array)
{
    $result = array();

    foreach ($array as $key => $value)
    {
        $result[$key] = $value . ' ' . $key;

        if ($value != 1)
        {
            $result[$key] .= 's';
        }
    }

    return implode(', ', $result);
}

@PeterMortensen: dovrebbe funzionare, ma non ho garanzie. Imposta il tuo fuso orario e provalo.
Alix Axel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.