Hướng dẫn how can i get the number of days between two given dates in php? - làm cách nào tôi có thể nhận được số ngày giữa hai ngày đã cho trong php?

TL; DR không sử dụng dấu thời gian UNIX. Không sử dụng time(). Nếu bạn làm như vậy, hãy chuẩn bị nếu độ tin cậy 98.0825% của nó không thành công. Sử dụng datetime (hoặc carbon). do not use UNIX timestamps. Do not use time(). If you do, be prepared should its 98.0825% reliability fail you. Use DateTime (or Carbon).

Câu trả lời đúng là câu trả lời được đưa ra bởi Saksham Gupta (các câu trả lời khác cũng đúng):correct answer is the one given by Saksham Gupta (other answers are also correct):

$date1 = new DateTime('2010-07-06');
$date2 = new DateTime('2010-07-09');
$days  = $date2->diff($date1)->format('%a');

Hoặc theo thủ tục là một lớp lót:

/**
 * Number of days between two dates.
 *
 * @param date $dt1    First date
 * @param date $dt2    Second date
 * @return int
 */
function daysBetween($dt1, $dt2) {
    return date_diff(
        date_create($dt2),  
        date_create($dt1)
    )->format('%a');
}

Với một cảnh báo: '%A' dường như chỉ ra số ngày tuyệt đối. Nếu bạn muốn nó là một số nguyên đã ký, tức là âm khi ngày thứ hai là trước lần thứ nhất, thì bạn cần sử dụng tiền tố '%r' (tức là format('%r%a')).absolute number of days. If you want it as a signed integer, i.e. negative when the second date is before the first, then you need to use the '%r' prefix (i.e. format('%r%a')).


Nếu bạn thực sự phải sử dụng dấu thời gian UNIX, hãy đặt múi giờ thành GMT để tránh hầu hết các cạm bẫy chi tiết dưới đây.set the time zone to GMT to avoid most of the pitfalls detailed below.


Câu trả lời dài: Tại sao chia cho 24*60*60 (còn gọi là 86400) không an toàn

Hầu hết các câu trả lời sử dụng dấu thời gian UNIX (và 86400 để chuyển đổi điều đó thành ngày) đưa ra hai giả định, kết hợp với nhau, có thể dẫn đến các kịch bản với kết quả sai và các lỗi tinh tế có thể khó theo dõi và phát sinh ngay cả ngày, vài tuần sau một triển khai thành công. Không phải là giải pháp không hoạt động - nó hoạt động. Hôm nay. Nhưng nó có thể ngừng hoạt động vào ngày mai.wrong results and subtle bugs that may be difficult to track, and arise even days, weeks or months after a successful deployment. It's not that the solution doesn't work - it works. Today. But it might stop working tomorrow.

Sai lầm đầu tiên là không xem xét rằng khi được hỏi, "Bao nhiêu ngày trôi qua kể từ ngày hôm qua?"zero if between the present and the instant indicated by "yesterday" less than one whole day has passed.

Thông thường khi chuyển đổi một "ngày" thành dấu thời gian unix, những gì thu được là dấu thời gian cho nửa đêm của ngày cụ thể đó.midnight of that particular day.

Vì vậy, giữa nửa đêm ngày 1 tháng 10 đến ngày 15 tháng 10, mười lăm ngày đã trôi qua. Nhưng từ 13:00 ngày 1 đến 14:55 ngày 15 tháng 10, mười lăm ngày trừ 5 phút đã trôi qua và hầu hết các giải pháp sử dụng floor() hoặc thực hiện chuyển đổi số nguyên ngầm sẽ báo cáo ít hơn một ngày so với dự kiến.will report one day less than expected.

Vì vậy, "bao nhiêu ngày trước là y-m-d h: i: s"? sẽ mang lại câu trả lời sai.wrong answer.

Sai lầm thứ hai là tương đương một ngày đến 86400 giây. Điều này hầu như luôn luôn đúng - nó thường xảy ra đủ để bỏ qua những lần nó không. Nhưng khoảng cách tính bằng giây giữa hai nửa đêm liên tiếp chắc chắn không phải là 86400 ít nhất hai lần một năm khi thời gian tiết kiệm ánh sáng ban ngày diễn ra. So sánh hai ngày qua một ranh giới DST sẽ mang lại câu trả lời sai.almost always true - it happens often enough to overlook the times it doesn't. But the distance in seconds between two consecutive midnights is surely not 86400 at least twice a year when daylight saving time comes into play. Comparing two dates across a DST boundary will yield the wrong answer.

Vì vậy, ngay cả khi bạn sử dụng "hack" buộc tất cả các dấu thời gian ngày vào một giờ cố định, giả sử Midnight (điều này cũng được thực hiện ngầm bằng nhiều ngôn ngữ và khung khác nhau khi bạn chỉ chỉ định ngày hàng ngày và cũng không phải là một giờ chiều; Tương tự xảy ra với loại ngày trong cơ sở dữ liệu như MySQL), công thức được sử dụng rộng rãi

 FLOOR((unix_timestamp(DATE2) - unix_timestamp(DATE1)) / 86400)

hoặc

 floor((time() - strtotime($somedate)) / 86400)

sẽ trở lại, giả sử, 17 khi ngày 1 và ngày 2 nằm trong cùng một phân đoạn DST của năm; Nhưng ngay cả khi giờ: Phút: Phần thứ hai giống hệt nhau, đối số có thể là 17.042, và tệ hơn nữa, 16.958 khi chúng ở các phân đoạn DST khác nhau và múi giờ là DST nhận thức. Việc sử dụng sàn () hoặc bất kỳ cắt ngắn nào đối với số nguyên sau đó sẽ chuyển đổi những gì đáng lẽ phải là 17 thành 16. Trong các trường hợp khác, các biểu thức như "$ ngày> 17" sẽ trở lại ____99 cho 17.042, ngay cả khi điều này sẽ trông như thể Số lượng ngày trôi qua là 18.

Và mọi thứ phát triển thậm chí còn xấu hơn vì mã như vậy không thể di động trên các nền tảng, bởi vì một số trong số chúng có thể áp dụng các giây nhảy và một số có thể không. Trên các nền tảng đó, sự khác biệt giữa hai ngày sẽ không phải là 86400 mà là 86401 hoặc có thể 86399. Vì vậy, mã hoạt động trong tháng 5 và thực sự đã vượt qua tất cả các bài kiểm tra sẽ bị phá vỡ vào tháng 6 tới khi 12.99999 ngày được coi là 12 ngày thay vì 13. Hai ngày Điều đó đã hoạt động trong năm 2015 sẽ không hoạt động trong năm 2017 - cùng ngày và cả năm không phải là một năm bước nhảy vọt. Và giữa năm 2018-03-01 và 2017-03-01, trên những nền tảng chăm sóc, 366 ngày sẽ trôi qua thay vì 365, biến năm 2018 trở thành một năm bước nhảy vọt (không phải vậy).is not portable across platforms, because some of them may apply leap seconds and some might not. On those platforms that do, the difference between two dates will not be 86400 but 86401, or maybe 86399. So code that worked in May and actually passed all tests will break next June when 12.99999 days are considered 12 days instead of 13. Two dates that worked in 2015 will not work in 2017 -- the same dates, and neither year is a leap year. And between 2018-03-01 and 2017-03-01, on those platforms that care, 366 days will have passed instead of 365, making 2018 a leap year (which it is not).

Vì vậy, nếu bạn thực sự muốn sử dụng dấu thời gian Unix:

  • Sử dụng hàm

    /**
     * Number of days between two dates.
     *
     * @param date $dt1    First date
     * @param date $dt2    Second date
     * @return int
     */
    function daysBetween($dt1, $dt2) {
        return date_diff(
            date_create($dt2),  
            date_create($dt1)
        )->format('%a');
    }
    
    0 một cách khôn ngoan, không phải floor().

  • Thay vào đó, không tính toán sự khác biệt giữa D1-M1-YYY1 và D2-M2-YYY2. Những ngày đó sẽ thực sự được coi là D1-M1-YYY1 00:00:00 và D2-M2-YYY2 00:00:00. Thay vào đó, chuyển đổi giữa D1-M1-YYY1 22:30:00 và D2-M2-YYY2 04:30:00. Bạn sẽ luôn nhận được một phần còn lại khoảng hai mươi giờ. Điều này có thể trở thành hai mươi mốt giờ hoặc mười chín, và có thể mười tám giờ, năm mươi chín phút ba mươi sáu giây. Không vấn đề. Đó là một biên độ lớn sẽ ở lại đó và sống tích cực cho tương lai gần. Bây giờ bạn có thể cắt ngắn nó với floor() về an toàn.

Mặc dù vậy, giải pháp chính xác, để tránh các hằng số ma thuật, làm tròn Kludges và một khoản nợ bảo trì, làcorrect solution though, to avoid magic constants, rounding kludges and a maintenance debt, is to

  • sử dụng thư viện thời gian (DateTime, carbon, bất cứ điều gì); Đừng tự lăn

  • Viết các trường hợp thử nghiệm toàn diện bằng cách sử dụng các lựa chọn ngày thực sự xấu xa - qua các ranh giới DST, qua những năm bước nhảy, trên những giây bước nhảy, v.v., cũng như ngày phổ biến. Lý tưởng nhất (các cuộc gọi đến DateTime là nhanh chóng!) Tạo ra bốn năm (và một ngày) có giá trị ngày bằng cách lắp ráp chúng từ các chuỗi, tuần tự và đảm bảo rằng sự khác biệt giữa ngày đầu tiên được kiểm tra tăng đều đặn. Điều này sẽ đảm bảo rằng nếu bất cứ điều gì thay đổi trong các thói quen cấp thấp và sửa chữa Seconds, hãy cố gắng tàn phá, ít nhất bạn sẽ biết.comprehensive test cases using really evil date choices - across DST boundaries, across leap years, across leap seconds, and so on, as well as commonplace dates. Ideally (calls to datetime are fast!) generate four whole years' (and one day) worth of dates by assembling them from strings, sequentially, and ensure that the difference between the first day and the day being tested increases steadily by one. This will ensure that if anything changes in the low-level routines and leap seconds fixes try to wreak havoc, at least you will know.

  • Chạy các bài kiểm tra thường xuyên cùng với phần còn lại của bộ thử nghiệm. Chúng là một vấn đề của mili giây và có thể giúp bạn tiết kiệm hàng giờ đầu.


Dù giải pháp của bạn là gì, hãy kiểm tra nó!

Hàm

/**
 * Number of days between two dates.
 *
 * @param date $dt1    First date
 * @param date $dt2    Second date
 * @return int
 */
function daysBetween($dt1, $dt2) {
    return date_diff(
        date_create($dt2),  
        date_create($dt1)
    )->format('%a');
}
3 bên dưới thực hiện một trong các giải pháp (như nó xảy ra, một giải pháp được chấp nhận) trong một kịch bản thế giới thực.

<?php
$tz         = 'Europe/Rome';
$yearFrom   = 1980;
$yearTo     = 2020;
$verbose    = false;

function funcdiff($date2, $date1) {
    $now        = strtotime($date2);
    $your_date  = strtotime($date1);
    $datediff   = $now - $your_date;
    return floor($datediff / (60 * 60 * 24));
}
########################################

date_default_timezone_set($tz);
$failures   = 0;
$tests      = 0;

$dom = array ( 0, 31, 28, 31, 30,
                  31, 30, 31, 31,
                  30, 31, 30, 31 );
(array_sum($dom) === 365) || die("Thirty days hath September...");
$last   = array();
for ($year = $yearFrom; $year < $yearTo; $year++) {
    $dom[2] = 28;
    // Apply leap year rules.
    if ($year % 4 === 0)   { $dom[2] = 29; }
    if ($year % 100 === 0) { $dom[2] = 28; }
    if ($year % 400 === 0) { $dom[2] = 29; }
    for ($month = 1; $month <= 12; $month ++) {
        for ($day = 1; $day <= $dom[$month]; $day++) {
            $date = sprintf("%04d-%02d-%02d", $year, $month, $day);
            if (count($last) === 7) {
                $tests ++;
                $diff = funcdiff($date, $test = array_shift($last));
                if ((double)$diff !== (double)7) {
                    $failures ++;
                    if ($verbose) {
                        print "There seem to be {$diff} days between {$date} and {$test}\n";
                    }
                }
            }
            $last[] = $date;
        }
    }
}

print "This function failed {$failures} of its {$tests} tests";
print " between {$yearFrom} and {$yearTo}.\n";

Kết quả là,

This function failed 280 of its 14603 tests

Câu chuyện kinh dị: Chi phí của "Tiết kiệm thời gian"

Tất cả bắt đầu vào cuối năm 2014. Một lập trình viên khéo léo đã quyết định tiết kiệm nhiều micro giây khỏi một tính toán mất nhiều nhất khoảng ba mươi giây, bằng cách cắm vào mã khét tiếng "(Midnightofdateb-midnightofdatea)/86400" mã ở một số nơi. Rõ ràng là một tối ưu hóa đến nỗi anh ta thậm chí không ghi lại nó, và việc tối ưu hóa đã vượt qua các bài kiểm tra tích hợp và bằng cách nào đó ẩn giấu trong mã trong vài tháng, tất cả đều không được chú ý.

Điều này đã xảy ra trong một chương trình tính toán tiền lương cho một số nhân viên bán hàng bán chạy nhất, trong số đó ít nhất có nhiều người đáng sợ hơn cả một nhóm lập trình viên năm người khiêm tốn được thực hiện. Vào ngày 28 tháng 3 năm 2015, múi giờ mùa hè đã tham gia, lỗi đã xảy ra - và một số kẻ đó đã thay đổi cả ngày hoa hồng béo. Để làm cho mọi thứ tồi tệ hơn, hầu hết trong số họ đã không làm việc vào Chủ nhật và, gần cuối tháng, đã sử dụng ngày hôm đó để bắt kịp với việc lập hóa đơn của họ. Họ chắc chắn không thích thú.

Tệ hơn vô cùng, họ đã mất niềm tin (đã rất ít) mà họ có trong chương trình không được thiết kế để lén lút trục họ, và giả vờ - và có được - một đánh giá mã đầy đủ, chi tiết với các trường hợp kiểm tra đã chạy và nhận xét theo các điều khoản của Layman (cộng với rất nhiều điều trị thảm đỏ trong những tuần tiếp theo).obtained - a complete, detailed code review with test cases ran and commented in layman's terms (plus a lot of red-carpet treatment in the following weeks).

Tôi có thể nói gì: Về mặt tích cực, chúng tôi đã thoát khỏi rất nhiều khoản nợ kỹ thuật, và có thể viết lại và tái cấu trúc một số mớ hỗn độn Spaghetti đã nghe lại sự xâm nhập của Cobol trong những năm 90. Chương trình chắc chắn chạy tốt hơn bây giờ, và có rất nhiều thông tin gỡ lỗi để nhanh chóng thực hiện khi bất cứ thứ gì trông tanh. Tôi ước tính rằng chỉ trong một điều cuối cùng này sẽ tiết kiệm được một hoặc hai người đàn ông mỗi tháng trong tương lai gần, vì vậy thảm họa sẽ có một chiếc lót bạc, hoặc thậm chí là vàng.

Về phía trừ, toàn bộ Brouhaha đã tiêu tốn của công ty khoảng 200.000 euro lên phía trước - cộng với khuôn mặt, cộng với chắc chắn một số sức mạnh thương lượng (và do đó, nhưng nhiều tiền hơn).

Anh chàng chịu trách nhiệm cho "tối ưu hóa" đã thay đổi công việc vào tháng 12 năm 2014, trước thảm họa, nhưng vẫn có cuộc nói chuyện với Sue anh ta vì thiệt hại. Và nó đã không phù hợp với các tiếng vang trên rằng đó là "lỗi của anh chàng cuối cùng" - nó trông giống như một thiết lập để chúng ta trở nên sạch sẽ của vấn đề, và cuối cùng, chúng ta vẫn ở trong nhà ổ chuột cho Phần còn lại của năm, và một trong những đội đã từ chức vào cuối mùa hè đó.

Chín mươi chín lần trong số một trăm, "86400 hack" sẽ hoạt động hoàn hảo. . .. và hai sai sẽ vui vẻ làm một quyền).

Điều này, thưa quý vị và quý ông, là một trường hợp khi nó không. Cũng như túi khí và dây an toàn, có lẽ bạn sẽ không bao giờ thực sự cần sự phức tạp (và dễ sử dụng) của

/**
 * Number of days between two dates.
 *
 * @param date $dt1    First date
 * @param date $dt2    Second date
 * @return int
 */
function daysBetween($dt1, $dt2) {
    return date_diff(
        date_create($dt2),  
        date_create($dt1)
    )->format('%a');
}
5 hoặc
/**
 * Number of days between two dates.
 *
 * @param date $dt1    First date
 * @param date $dt2    Second date
 * @return int
 */
function daysBetween($dt1, $dt2) {
    return date_diff(
        date_create($dt2),  
        date_create($dt1)
    )->format('%a');
}
6. Nhưng ngày mà bạn có thể (hoặc ngày mà bạn phải chứng minh rằng bạn đã nghĩ về điều này) sẽ đến như một tên trộm trong đêm (có thể lúc 02:00 một số Chủ nhật trong tháng 10). Được chuẩn bị.

Công thức cho ngày giữa hai ngày là gì?

Sử dụng hàm Datedif khi bạn muốn tính toán chênh lệch giữa hai ngày.Đầu tiên đặt ngày bắt đầu vào một ô và ngày kết thúc ở một ngày khác.Sau đó nhập một công thức như một trong những điều sau đây.

Làm thế nào có thể đếm ngày trong PHP?

Php $ to_date = Time ();// Nhập ngày của bạn vào đây, ví dụ:Strtotime ("2014-01-02") $ from_date = strtotime ("2012-01-31");$ day_diff = $ to_date - $ from_date;Tầng Echo ($ day_diff/(60*60*24)).