PHP kullanarak iki tarih arasındaki fark nasıl hesaplanır?


722

Formun iki tarihi var:

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

Şimdi bu ikisi arasındaki farkı aşağıdaki biçimde bulmam gerekiyor:

2 years, 3 months and 2 days

Bunu PHP'de nasıl yapabilirim?


1
2 yıl 94 gün. Artık yılları hesaba katarak ayları hesaplamak sorunlu olurdu. Bunun ne kadar doğru olması gerekir?
dbasnett

Yanıtlar:


527

Eski kod için bunu kullanın (PHP <5.3). Güncel çözüm için jurka'nın cevabına bakınız.

İki tarihi unix zamanına dönüştürmek için strtotime () yöntemini kullanabilir ve aralarındaki saniye sayısını hesaplayabilirsiniz. Bundan farklı zaman aralıklarını hesaplamak oldukça kolaydır.

$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);

Düzenleme: Açıkçası bunu yapmanın tercih edilen yolu aşağıdaki jurka tarafından tarif gibi. Kodum genellikle yalnızca PHP 5.3 veya daha üst sürümünüz yoksa önerilir.

Yorumlarda yer alan birkaç kişi, yukarıdaki kodun sadece bir yaklaşım olduğuna dikkat çekti. Hala pek çok amaç için iyi olduğuna inanıyorum, çünkü bir aralığın kullanımı, hassasiyet sağlamaktan ziyade ne kadar zaman geçtiğini veya kaldığını anlamak için daha fazlasıdır - bunu yapmak istiyorsanız, sadece tarihi çıktılayın.

Tüm bunlara rağmen şikayetleri ele almaya karar verdim. Gerçekten tam bir aralığa ihtiyacınız varsa ancak PHP 5.3'e erişemiyorsanız, aşağıdaki kodu kullanın (PHP 4'te de çalışmalıdır). Bu, PHP'nin yaz saatlerini hesaplamak için dahili olarak kullandığı kodun doğrudan bağlantı noktasıdır, ancak gün ışığından yararlanma süresini dikkate almaz. Bu, en fazla bir saat kapalı olduğu anlamına gelir, ancak bunun dışında doğru olmalıdır.

<?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
DateTime sınıfını kullanıyorsanız, unix zaman damgasını almak için $ date-> formatına ('U') gidebilirsiniz.
Jon Cram

4
Yaz / kış saati ile uğraşmak zorundaysanız doğru değil. Bu özel durumda yaz / kış saatini ayarladığınızda, bir gün 23 veya 25 saate eşittir.
Arno

4
Aynı tartışma artık yıllar için de yapılabilir. Bunu da dikkate almıyor. Yine de, burada bir dizi tartıştığımız için bunu dikkate almak istediğinize ikna olmadım. Bir aralığın semantiği, mutlak bir tarihe göre biraz farklıdır.
Emil H

9
Bu işlev yanlış. Bir yaklaşım için iyidir, ancak kesin aralıklar için yanlıştır. Birincisi, ayda 30 gün olduğunu varsayar, yani 1 Şubat ile 1 Mart arasında 1 Temmuz ile 1 Ağustos arasında (artık yıl ne olursa olsun) aynı gün farkına sahip olacağı anlamına gelir.
enobrev

1
PHP'de, referans değişkenleri çağrıda değil fonksiyon imzasındadır. Tüm &imzalarınızı taşıyın .
Paul Tarjan

910

DateTime ve DateInterval nesnelerini kullanmanızı öneririm.

$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 ";

daha fazla bilgi php DateTime :: diff manuel

Kılavuzdan:

PHP 5.2.2'den itibaren, DateTime nesneleri karşılaştırma işleçleri kullanılarak karşılaştırılabilir.

$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 artık yılları ve zaman dilimlerini düzgün işliyor
hakre

3
İki DateTimes arasındaki toplam saniye sayısını veren bir yöntem var mı? (bileşenleri eklemeden, yani)
patates

1
@Panique $ aralığı-> günler ve $ aralığı-> d farklı ölçülerdir. yukarıdaki yorumunuz doğru "toplam gün sayısını gösterir (yukarıdaki gibi yıllara, aylara ve günlere
bölünmez

1
@potatoe Muhtemelen istiyorsun $date2->format('U') - $date1->format('U').
Paulo Freitas

3
DateInterval'ın bazı PHP sürümlerine sahip Windows'ta yanlış bir gün özelliğine ( her zaman 6015 ) sahip olduğu bir hata olduğunu unutmayın : bugs.php.net/bug.php?id=51184 (düzeltme / geçici çözüm için yorumlara bakın)
Pim Schaaf

73

En iyi eylem yolu PHP'nin DateTime(ve DateInterval) nesnelerini kullanmaktır. Her tarih bir DateTimenesnede kapsüllenir ve daha sonra ikisi arasında bir fark yapılabilir:

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

DateTimeNesne herhangi bir biçimde kabul eder strtotime()olur. Daha da özel bir tarih formatı gerekiyorsa, nesneyi DateTime::createFromFormat()oluşturmak için kullanılabilir DateTime.

Her iki nesne de somutlaştırıldıktan sonra, birini diğerinden soyutlayabilirsiniz DateTime::diff().

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

$differenceartık DateIntervalfark bilgisine sahip bir nesne tutuyor . A var_dump()şuna benzer:

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

DateIntervalNesneyi biçimlendirmek için , her bir değeri kontrol etmemiz ve 0 ise hariç tutmamız gerekir:

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

Şimdi geriye kalan tek şey $difference DateIntervalnesne üzerindeki fonksiyonumuzu çağırmaktır :

echo format_interval($difference);

Ve doğru sonucu alıyoruz:

20 gün 6 saat 56 dakika 30 saniye

Hedefe ulaşmak için kullanılan kodun tamamı:

/**
 * 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()bir işlev değil, bir nesne ve PHP 5.2'den beri orada. Sunucunuzun desteklediğinden emin olun.
Madara'nın Hayaleti

2
@SecondRikudo DateTime :: Diff PHP
5.3.0'a

Bir sorunumuz var, first_date öğesini second_date ile değiştirelim ve aynı sonucu alıyoruz? Neden 0 gün 0 saat 0 dakika 0 saniye veya sadece 0 demiyorsunuz. Örnek: 2012-11-30 17:03:30 - 2012-12-21 00:00:00 ve 2012-12-21 00:00:00 - 2012-11-30 17:03:30 aynı sonucu alır.
EgoistDeveloper

Çünkü diff size iki kez arasındaki farkı verir. Hangi tarihin daha sonra geleceğinden bağımsız olarak fark 0 değildir.
Madara'nın Hayaleti

1
Bu çok iyi bir cevaptır, çünkü kod tabanındaki herhangi bir yerden çok fazla zaman hesabı olmadan çağrılabilen net bir işlev sağlar. Diğer cevaplar, sorunu çözmek yerine belirtileri ele alan yankılanan kalsleri anında bırakmanıza izin verir ... Eklediğim tek öğe (ve hemen hemen tüm diğer yayınlar bunu kapsamaz) $ aralık elemanlarının çoğullaştırılmasıdır 1'den fazla ise
nickhar

33

Saat ve Dakika ve Saniye Göster ..

$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
Muhtemelen bu kesin sonuç vermeyecektir.
Dolphin

8
Ve çok eski bir PHP sürümü kullanmak zorunda değilseniz korkunç bir çözümdür ...
rdlowrey

2
O kadar KURU değil . Örneğin, 60 * 60 * 24 15 kez tekrarlanır. Yaşasın kopyala yapıştır kullanımı!
Peter Mortensen

Artık yıllar ne olacak? Bir yıl ortalama 365 gün değildir.
Peter Mortensen

Bu kod, bir ayın ortalama 30 gün olduğunu varsayar. Bir yıl için 365 gün olduğu varsayılsa bile, ortalama bir ay 365/12 = 30,42 gündür (yaklaşık).
Peter Mortensen

18

Aşağıdaki bağlantıya bir göz atın. Bu şimdiye kadar bulduğum en iyi cevap .. :)

function dateDiff ($d1, $d2) {

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

} // end function dateDiff

Tarih parametrelerini ilettiğinizde hangi tarihin daha erken veya daha sonra olduğu önemli değildir. İşlev, her iki tarih arasındaki gün sayısı olarak bir pozitif sayı döndürmek için PHP ABS () mutlak değerini kullanır.

İki tarih arasındaki gün sayısının her iki tarihi de içermediğini unutmayın. Dolayısıyla, girilen tarihler dahil olmak üzere tüm tarihlerle temsil edilen gün sayısını arıyorsanız, bu işlevin sonucuna bir (1) eklemeniz gerekir.

Örneğin, 2013-02-09 ve 2013-02-14 arasındaki fark (yukarıdaki işlevle döndürüldüğü gibi) 5'tir. Ancak 2013-02-09 - 2013-02- tarih aralığının temsil ettiği gün veya tarih sayısı 14, 6'dır.

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


Soru, toplam gün sayısı değil, yıl, ay ve gün sayısı olarak farkı istedi.
Peter Mortensen

14

Oy verdim Jurka 'ın cevabını bu benim favorim, ama önceden php.5.3 sürümüne sahip olarak ...

Kendimi benzer bir sorun üzerinde çalışırken buldum - bu soruya ilk başta böyle geldim - ama saatlerce bir farka ihtiyacım vardı. Ama benim fonksiyonum bunu oldukça güzel bir şekilde çözdü ve kaybolmayacağı ve unutulmayacağı yerde tutmak için kendi kütüphanemde hiçbir yerim yok, bu yüzden umarım bu birileri için yararlıdır.

/**
 *
 * @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;
}

Ve test:

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

Ve sonuç:

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

Kullanımları için değiştirdiğim orijinal fikri buradan aldım (ve umarım modifikasyonum da bu sayfada gösterilecek).

Diziden kaldırarak $aIntervalsveya belki bir $aExcludeparametre ekleyerek istemediğiniz aralıkları ("hafta" diyelim) kolayca kaldırabilir veya dizeyi çıkardığınızda filtreleyebilirsiniz.


Ne yazık ki bu yıl / ay taşması nedeniyle DateInterval ile aynı şeyi döndürmez.
Stephen Harris

2
@StephenHarris: Bunu test etmedim, ancak kodu okuyarak oldukça eminim - weekdizini silmeniz şartıyla $aIntervals( DateDiffasla kullanmaz).
Alix Axel

Bu, iki tarih arasındaki her aralıkta meydana gelen tarihleri ​​bulmak için mükemmel bir çözümdür.
betweenbrain

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);
?>

Soru yıl , ay ve gün sayısı olarak farkı istedi . Bu, farkı toplam gün sayısı olarak verir.
Peter Mortensen

11

Bir PHP çerçevesi kullanıp kullanmadığınızı bilmiyorum, ancak PHP çerçevelerinin birçoğu tekerleği yeniden keşfetmenize yardımcı olmak için tarih / saat kitaplıkları ve yardımcıları var.

Örneğin CodeIgniter bu timespan()işleve sahiptir. İki Unix zaman damgasını girmeniz yeterlidir ve otomatik olarak böyle bir sonuç oluşturur:

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

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


8

Örnek kullanın:

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

Çıktı :

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

İşlev:

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

farkın 30 dakikadan büyük olup olmadığını belirlemek istersem ne yapmalıyım?
Ofir Attia

@OfirAttia: SO'da böyle bir sürü sorunuz var, sadece aramayı kullanın. Basit demo
Glavić

7

Bunun için bazı basit mantık var:

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

Örnek kodun sonunda eksik bir şey var gibi görünüyor (bir bitiş ayracı ve " ?> "?).
Peter Mortensen

"basit" mantık. Bunlar en az 40 satırlık saf koddur.
Madjosz

6

Kullanabilirsiniz

getdate()

Sağlanan tarih / saatin tüm öğelerini içeren bir dizi döndüren işlev:

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

Başlangıç ​​ve bitiş tarihleriniz dize biçimindeyse şunu kullanın:

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

yukarıdaki koddan önce


çalışmıyor gibi görünüyor. Zaman damgası çağının başlangıcında bir randevu alıyorum.
Sirber

$my_t["year"] -= 1970Doğru sayıda yıl almak için bir yapmanız gerektiğini anlamanız önemlidir . Ayrıca çıkarmak gerekir senin sağ saat almak için GMT saat farkı. Ay ve tarihten 1 çıkartmanız gerekir.
Salman A

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 yıl', $ date1)" artık yılları hesaba katıyor mu?
Peter Mortensen

6

Bu benim fonksiyonum. Gerekli PHP> = 5.3.4. DateTime sınıfını kullanır. Çok hızlı, hızlı ve iki tarih arasındaki farkı veya hatta "o zamandan beri" denebilir.

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

Ben kullanımına tercih ediyorum date_createve date_diffnesneler.

Kod:

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

Çıktı:

2 years, 3 months and 2 days

Daha fazla bilgi için PHP kılavuzunu okuyundate_diff

El kitabına göre date_diffbir takma ) (DateTime :: fark


5

Bu, bir zaman damgasının verilip verilmediğini tespit etmeye çalışır ve gelecekteki tarihleri ​​/ saatleri negatif değerler olarak döndürür:

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

Örnek kullanım:

<?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

Veya:

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

5

"Eğer" tarih MySQL'de saklanırsa, fark hesaplamasını veritabanı düzeyinde yapmayı daha kolay buluyorum ... Daha sonra Gün, Saat, Min, Saniye çıktı, ayrıştırma ve sonuçları uygun şekilde görüntüleme ...

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

Makalenizi PHP tarih ve saat hesaplamaları için bir dizi referans içeren bir sonraki sayfada buldum .

PHP kullanarak iki Tarih (ve saat) arasındaki farkı hesaplayın. Aşağıdaki sayfa, iki tarih arasındaki zaman (saat, mühimmat), gün, ay veya yıl farkını belirlemek için PHP kullanarak tarih / saat hesaplamaları yapmak için bir dizi farklı yöntem (toplam 7) sunmaktadır.

Bkz. PHP Tarih Saati - 7 Tarih Arasındaki Farkı Hesaplamak için 7 Yöntem .


4

Ayrıca, $ date1 = $ duedate tarihine kadar yuvarlak kesirlere göre tarih farkı döndürmek için aşağıdaki kodu da kullanabilirsiniz; // bitiş tarihini ata echo $ date2 = tarih ("Ymd"); // geçerli tarih $ ts1 = strtotime ($ date1); $ ts2 = strtotime ($ date2); $ seconds_diff = $ ts1 - $ ts2; echo $ tarihliiff = tavan (($ seconds_diff / 3600) / 24); // gün içinde geri dönüş

Tavan yerine php'nin zemin yöntemini kullanırsanız, yuvarlak kesri geri döndürür. Lütfen buradaki farkı kontrol edin, bazı durumlarda hazırlama sunucularınızın saat dilimi canlı site saat diliminden farklıysa, bu durumda farklı sonuçlar alabilirsiniz, bu nedenle koşulları uygun şekilde değiştirin.


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

her zaman yaşı yıl ve ay cinsinden döndürebilen aşağıdaki işlevi kullanabilirsiniz (örn. 1 Yıl 4 Ay)

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

veya yaşın geçerli tarihte hesaplanmasını istiyorsanız,

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

Php sürümü için> = 5.3: İki tarih nesnesi oluşturun ve sonra date_diff()işlevini kullanın . Php DateInterval nesnesini döndürür . belgelere bakın

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

4

İşte çalıştırılabilir kod

$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

PHP 5.2 ile aynı sorunu yaşadım ve MySQL ile çözdüm. Tam olarak aradığınız şey olmayabilir, ancak bu hile yapacak ve gün sayısını döndürecektir:

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

Daha fazla bilgi için http://dev.mysql.com/doc/refman/5.5/tr/date-and-time-functions.html#function_datediff


3

Herkes kod örnekleri gönderdiğinden, burada başka bir sürüm var.

Bir fonksiyonun saniye ile yıl arasındaki farkları göstermesini istedim (sadece bir birim). 1 günden uzun süreler için gece yarısında rollover olmasını istedim (Çarşamba günleri saat 9'dan itibaren 10: 00'da 1 gün değil, 2 gün önce). Ve bir aydan uzun süreler için, rollover'ın ayın aynı gününde olmasını istedim (30/31 gün ayları ve artık yıllar dahil).

Ben geldi budur:

/**
 * 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

Bir süre önce , tarihinizi nasıl istediğinize dair birçok seçenekformat_date sunduğu için bir işlev yazdım :

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
Bu cevap, khaldonno'nun yanıtı kadar yanlıştır. Bir yıl 365 gün (her dördüncü yılda 366 gün (Gregoryen takvimi için 100 yıl / 400 yıl kuralları hariç)) ve bir ayın 30 gün olduğunu (yaklaşık 30.42 gün olduğunu) varsayar (durum 10). artık olmayan yıllarda). Daha iyi sabitlerle bile, sadece ortalama olarak doğrudur, iki belirli tarih için mutlaka doğru değildir.
Peter Mortensen

3

Çok basit:

    <?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>";
    ?>

Ayrıntılar için lütfen aşağıdaki bağlantıyı kontrol edin:

PHP: date_diff - El ile

PHP 5.3.0 veya üstü için olduğunu unutmayın.


3

Kolay fonksiyon

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

Gibi kullanın

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

Gibi dönecektir 2 years 8 months 2 days


3

Date_diff () kullanarak bu çok basit yanıtı deneyin , bu test edilmiştir.

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

çıktı:

1 years 1 months 2 days

2

PHP 5.3 (sırasıyla date_diff ()) mevcut olmadığında yazdığım aşağıdaki işlevi kullanıyorum:

        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 harika ama birkaç uyarı var:

  1. sadece PHP 5.3+ için ( ama bu artık iyi bir bahane değil )
  2. yalnızca yıl, ay, gün, saat, dakika ve saniyeyi destekler (hafta yok)
  3. farkı yukarıdaki + günlerin tümü ile hesaplar (farkı sadece aylar içinde elde edemezsiniz)

Bunun üstesinden gelmek için aşağıdakileri kodladım ( @enobrev yanıtından geliştirildi ):

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

İki döngü çalıştırır; birincisi kaba kuvvetleme yoluyla göreli aralıkları (yıl ve aylar) ele alır ve ikincisi ek mutlak aralıkları basit aritmetik ile hesaplar (böylece daha hızlıdır):

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: Çalışmalı ama hiçbir garanti vermiyorum. Saat diliminizi ayarlayın ve bir deneyin.
Alix Axel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.