2010-11-20 82 views
45

Giả sử tôi có hai ngày trong các biến, giống nhưCách thanh lịch để nhận số tháng giữa hai ngày?

$date1 = "2009-09-01"; 
$date2 = "2010-05-01"; 

tôi cần phải lấy số liệu của tháng giữa $date2$date1 ($date2 >= $date1). I E. tôi cần lấy 8.

Có cách nào để lấy nó bằng cách sử dụng chức năng date hoặc tôi phải phát nổ chuỗi và thực hiện một số phép tính?

Cảm ơn nhiều

Trả lời

93

Đối với PHP> = 5,3

$d1 = new DateTime("2009-09-01"); 
$d2 = new DateTime("2010-05-01"); 

var_dump($d1->diff($d2)->m); // int(4) 
var_dump($d1->diff($d2)->m + ($d1->diff($d2)->y*12)); // int(8) 

DateTime :: diff trả về một đối tượng DateInterval

Nếu bạn không chạy với PHP 5.3 hoặc cao hơn, tôi đoán bạn' sẽ phải sử dụng dấu thời gian unix:

$d1 = "2009-09-01"; 
$d2 = "2010-05-01"; 

echo (int)abs((strtotime($d1) - strtotime($d2))/(60*60*24*30)); // 8 

Nhưng không chính xác lắm (không có luôn 30 ngày mỗi tháng).

Điều cuối cùng: nếu những ngày đó đến từ cơ sở dữ liệu của bạn, thì hãy sử dụng DBMS của bạn để thực hiện công việc này, chứ không phải PHP.

Edit: Mã này nên chính xác hơn nếu bạn không thể sử dụng DateTime :: diff hoặc RDBMS của bạn:

$d1 = strtotime("2009-09-01"); 
$d2 = strtotime("2010-05-01"); 
$min_date = min($d1, $d2); 
$max_date = max($d1, $d2); 
$i = 0; 

while (($min_date = strtotime("+1 MONTH", $min_date)) <= $max_date) { 
    $i++; 
} 
echo $i; // 8 
+0

Giải pháp tuyệt vời trong vòng lặp while! Rất ngắn gọn và chính xác. Làm tốt! +1 –

+5

Nếu bạn có hai ngày cách nhau hơn một năm, bạn sẽ thấy 'var_dump ($ d1-> diff ($ d2) -> m)' sẽ thất bại trong phương thức DateTime (phương thức trên cùng của câu trả lời này) vì nó sẽ chỉ hiển thị những tháng không thêm đến nhiều năm. Hãy thử điều này và xem điều gì xảy ra: '$ d1 = Ngày giờ mới (" 2011-05-14 "); ' ' $ d2 = new DateTime ("2013-02-02"); ' ' $ d3 = $ d1 -> diff ($ d2); ' ' echo '

'.print_r($d3,true).'
'; ' – pathfinder

+0

Không quá nhanh ... dựa vào strtotime có thể làm bạn đau đầu. Có bao nhiêu tháng từ ngày 31 tháng 1 năm 2011 đến ngày 28 tháng 2 năm 2011? –

23

Hoặc, nếu bạn muốn phong cách thủ tục:

$date1 = new DateTime("2009-09-01"); 
$date2 = new DateTime("2010-05-01"); 
$interval = date_diff($date1, $date2); 
echo $interval->m + ($interval->y * 12) . ' months'; 

CẬP NHẬT: Đã thêm bit mã vào tài khoản trong nhiều năm.

+1

Nếu ngày của bạn cách nhau hơn một năm thì điều này sẽ không thành công. Bạn sẽ cần phải thêm năm * 12 vào câu trả lời của bạn để nhận được các tháng. – pathfinder

+1

Đúng là bạn. Cập nhật tài khoản cho các năm có thể kéo dài. –

1

Sử dụng DateTime, điều này sẽ cung cấp cho bạn một giải pháp chính xác hơn đối với bất kỳ số lượng tháng:

$d1 = new DateTime("2011-05-14"); 
$d2 = new DateTime(); 
$d3 = $d1->diff($d2); 
$d4 = ($d3->y*12)+$d3->m; 
echo $d4; 

Bạn vẫn sẽ cần phải xử lý những ngày còn sót lại $d3->d nếu vấn đề của thế giới thực sự của bạn không phải là đơn giản và cắt và khô như câu hỏi ban đầu, cả hai ngày đều là ngày đầu tiên của tháng.

13

Hoặc một phép tính đơn giản sẽ cung cấp cho:

$numberOfMonths = abs((date('Y', $endDate) - date('Y', $startDate))*12 + (date('m', $endDate) - date('m', $startDate)))+1; 

chính xác và làm việc tại tất cả các trường hợp.

+0

Điều này thật tuyệt vời, ngoại trừ việc nó luôn tắt bằng cách xóa bỏ "+1" ở cuối! : D – supercoolville

11

Sau khi kiểm tra tấn các giải pháp, đặt tất cả trong một thử nghiệm đơn vị, đây là những gì tôi đi ra với:

/** 
* Calculate the difference in months between two dates (v1/18.11.2013) 
* 
* @param \DateTime $date1 
* @param \DateTime $date2 
* @return int 
*/ 
public static function diffInMonths(\DateTime $date1, \DateTime $date2) 
{ 
    $diff = $date1->diff($date2); 

    $months = $diff->y * 12 + $diff->m + $diff->d/30; 

    return (int) round($months); 
} 

Ví dụ nó sẽ trở lại (trường hợp kiểm tra từ các đơn vị kiểm tra):

  • 01.11.2013 - 30.11.2013 - 1 tháng
  • 01.01.2013 - 31.12.2013 - 12 tháng
  • 31.01.2011 - 28.02.2011-1 tháng
  • 2009/09/01 - 2010/05/01 - 8 tháng
  • 2013/01/01 - 2013/03/31 - 3 tháng
  • 2013/02/15 - 2013/04/15 - 2 tháng
  • 1985/02/01 - 31.12.2013 - 347 tháng

Lưu ý: Do làm tròn với ngày, thậm chí một nửa tháng sẽ được làm tròn, có thể dẫn đến vấn đề nếu bạn sử dụng nó với một số trường hợp. Vì vậy, KHÔNG SỬ DỤNG nó cho các trường hợp như vậy, nó sẽ gây ra vấn đề cho bạn.

Ví dụ:

  • 02.11.2013 - 2013/12/31 sẽ trở lại 2, chứ không phải 1 (như mong đợi).
+1

Giải pháp này là tốt cho một số "con người có thể đọc được" của tháng: Nó trả về những gì một con người mong đợi để xem. Trong trường hợp này, làm tròn được đề cập ở trên thực sự hữu ích và bạn nhận được 'vấn đề' với người dùng nếu bạn không làm điều đó! – Steve

+0

31.01.2011 - 01.03.2011 - 1 tháng ==> phải là 2 tháng – manish1706

1

Đây là một phương pháp đơn giản tôi đã viết trong lớp học của tôi để đếm số tháng tham gia vào hai thời điểm đưa ra:

public function nb_mois($date1, $date2) 
{ 
    $begin = new DateTime($date1); 
    $end = new DateTime($date2); 
    $end = $end->modify('+1 month'); 

    $interval = DateInterval::createFromDateString('1 month'); 

    $period = new DatePeriod($begin, $interval, $end); 
    $counter = 0; 
    foreach($period as $dt) { 
     $counter++; 
    } 

    return $counter; 
} 
+0

Trong khi tôi cung cấp cho nó một +1 vì đây là gần nhất để cung cấp cho bất kỳ kết quả thực sự. Tuy nhiên nó vẫn chưa hoàn chỉnh, vì nó sẽ thất bại trong những ngày trong cùng một tháng. –

3

tôi sử dụng này:

$d1 = new DateTime("2009-09-01"); 
$d2 = new DateTime("2010-09-01"); 
$months = 0; 

$d1->add(new \DateInterval('P1M')); 
while ($d1 <= $d2){ 
    $months ++; 
    $d1->add(new \DateInterval('P1M')); 
} 

print_r($months); 
3

Đây là một cách khác để nhận số tháng giữa hai ngày:

// Set dates 
$dateIni = '2014-07-01'; 
$dateFin = '2016-07-01'; 

// Get year and month of initial date (From) 
$yearIni = date("Y", strtotime($dateIni)); 
$monthIni = date("m", strtotime($dateIni)); 

// Get year an month of finish date (To) 
$yearFin = date("Y", strtotime($dateFin)); 
$monthFin = date("m", strtotime($dateFin)); 

// Checking if both dates are some year 

if ($yearIni == $yearFin) { 
    $numberOfMonths = ($monthFin-$monthIni) + 1; 
} else { 
    $numberOfMonths = ((($yearFin - $yearIni) * 12) - $monthIni) + 1 + $monthFin; 
} 
+0

Đây phải là câu trả lời chính xác :) –

0

Tôi đã sử dụng tính năng này và hoạt động trong mọi điều kiện

$fiscal_year = mysql_fetch_row(mysql_query("SELECT begin,end,closed FROM fiscal_year WHERE id = '2'")); 


      $date1 = $fiscal_year['begin']; 
      $date2 = $fiscal_year['end']; 

      $ts1 = strtotime($date1); 
      $ts2 = strtotime($date2); 


      $te=date('m',$ts2-$ts1); 

      echo $te; 
Các vấn đề liên quan