Saya pikir mengembalikan sejumlah hari negatif memberikan informasi yang relevan. Dan Anda harus menggunakan $your_date-$now, jika Anda ingin masa depan mengembalikan integer positif.
Tim
23
Bagaimana dengan detik kabisat? Tidak semua hari memiliki tepat 24 * 60 * 60 detik. Kode ini mungkin cukup untuk tujuan praktis tetapi tidak tepat dalam kasus tepi yang sangat langka.
Benjamin Brizzi
49
Lupa detik kabisat (tidak, sebenarnya pertimbangkan itu juga) tetapi ini TIDAK memperhitungkan perubahan Waktu Musim Panas! Itu bisa dimatikan sepanjang hari atas batas-batas itu setiap tahun. Anda perlu menggunakan kelas DateTime.
Lewi
6
@ billynoah Maaf, saya tidak pernah kembali untuk memperbarui komentar saya. Anda harus berhati-hati dengan zona waktu musim panas. Jika Anda membandingkan tanggal dengan daylight saving dengan tanggal tanpa itu, sebagai gantinya misalnya mengembalikan 7 hari itu mengembalikan 6,9 hari. Mengambil kembali lantai 6 bukannya 7.
Alex Angelico
4
Tidak hanya strtotime () gagal dalam 20 tahun, itu tidak dapat digunakan sekarang. OP menentukan Tanggal, bukan Waktu. Tanggal bisa sangat tua. Inilah jawaban yang lebih sederhana: $ NumberDays = gregoriantojd ($ EndM, $ EndD, $ EndY) - gregoriantojd ($ StartM, $ StartD, $ StartY); (untuk rentang inklusif). Berbeda dengan Kelas Datetime, Gregorian ke Julian tersedia di v4 ke atas. Kisaran yang valid adalah 4714 SM hingga 9999 M. Waspadai urutan parameter yang funky (seperti Anda memerlukan peringatan untuk php).
Guy Gordon
524
Jika Anda menggunakan PHP 5.3 >, ini adalah cara paling akurat untuk menghitung perbedaan:
Perhatikan bahwa karena kita berbicara tentang interval waktu bukan titik waktu tertentu, sintaks format berbeda dari sintaks tanggal () dan strftime (). Sintaks interval waktu dapat ditemukan di sini: php.net/manual/en/dateinterval.format.php
Andrew
1
atau dalam kasus saya jumlah hari antara adalah $ date2-> diff ($ date1) -> format ("% a") - 1
xeo
13
Perlu diingat bahwa jika Anda memiliki waktu dalam kencan Anda, ini tidak akan berfungsi seperti yang Anda harapkan. Misalnya, jika Anda memiliki interval 23:30 jam ... dan mereka ada di hari yang berbeda, perbedaannya adalah 0.
Layke
20
Jika Anda membutuhkan jumlah hari relatif (negatif bila $date1anterior $date2), gunakan $diff = $date2->diff($date1)->format("%r%a");sebagai gantinya.
Socce
1
Apa format tanggal dalam DateTime("2010-07-06")?, apakah itu Y-m-datau Y-d-m?, apa format DateTimeparameter. yang mana hari?
151291
165
Dari PHP Versi 5.3 dan lebih tinggi, fungsi tanggal / waktu baru telah ditambahkan untuk mendapatkan perbedaan:
Ya, ini tampaknya lebih baik daripada jawaban yang diterima, yang tidak berfungsi dalam beberapa kasus. Suka: $ from = '2014-03-01'; $ to = '2014-03-31';
MBozic
1
Saya setuju, sangat mudah diikuti dan bekerja dengan luar biasa !!! Hanya saja, jangan lupa untuk menggunakan fungsi date_default_timezone_set () atau itu akan memberi Anda hasil aneh berdasarkan waktu UTC.
zeckdude
2
Fungsi ini gagal 0 dari 14603 tes antara 1980 dan 2020.
LSerni
128
Ubah tanggal Anda menjadi unix cap waktu, lalu kurangi satu dari yang lainnya. Itu akan memberi Anda perbedaan dalam hitungan detik, yang Anda bagi dengan 86400 (jumlah detik dalam sehari) untuk memberi Anda perkiraan jumlah hari dalam rentang itu.
Jika tanggal Anda dalam format 25.1.2010, 01/25/2010atau 2010-01-25, Anda dapat menggunakan strtotimefungsi:
Menggunakan ceilputaran jumlah hari hingga hari penuh berikutnya. Gunakan floorsebaliknya jika Anda ingin mendapatkan jumlah hari penuh antara dua tanggal tersebut.
Jika tanggal Anda sudah dalam format cap waktu unix, Anda dapat melewati konversi dan cukup lakukan $days_betweenbagian. Untuk format tanggal yang lebih eksotis, Anda mungkin harus melakukan parsing khusus untuk memperbaikinya.
@ toon81 - kami menggunakan cap waktu Unix untuk menghindari kekacauan seperti itu! ;)
Alastair
6
Biarkan saya menguraikan: katakanlah pagi ini jam 3 pagi, hampir seluruh Eropa mengembalikan jam satu jam. Itu berarti bahwa hari ini memiliki 3600 detik ekstra, dan itu harus tercermin dalam cap waktu UNIX. Jika ya, berarti hari ini akan dihitung selama dua hari dengan cara menghitung jumlah hari di atas. Dan saya bahkan tidak memulai sekitar detik kabisat karena baik PHP maupun UNIX tampaknya tidak memperhitungkan itu (yang sebenarnya IMO dapat dimengerti). TL; DR: tidak semua hari panjangnya 86.400 detik .
toon81
2
@ toon81 TIDAK 3600 detik lagi untuk tanggal itu. Tidak ada yang terjadi pada cap waktu UNIX saat pergi ke atau dari DST.
nickdnk
1
Jika tidak ada yang terjadi pada stempel waktu UNIX, maka Anda setuju dengan saya: perbedaan antara stempel waktu UNIX pada jam 1 siang $daydan stempel waktu UNIX jam 1 siang $day+1tidak selalu 86400 detik dalam zona waktu yang mengamati DST. Mungkin bernilai 23 atau 25 jam dalam hitungan detik alih-alih 24 jam.
toon81
112
TL; DR jangan tidak menggunakan UNIX cap waktu. Jangan gunakantime() . Jika Anda melakukannya, bersiaplah jika keandalan 98,0825% gagal Anda. Gunakan DateTime (atau Karbon).
The jawaban yang benar adalah salah satu yang diberikan oleh Saksham Gupta (jawaban lain juga benar):
/**
* 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');}
Dengan peringatan: '% a' tampaknya menunjukkan jumlah hari absolut . Jika Anda menginginkannya sebagai bilangan bulat yang ditandatangani, yaitu negatif ketika tanggal kedua adalah sebelum tanggal pertama, maka Anda perlu menggunakan awalan '% r' (yaitu format('%r%a')).
Jika Anda benar-benar harus menggunakan cap waktu UNIX, atur zona waktu ke GMT untuk menghindari sebagian besar jebakan yang dirinci di bawah ini.
Jawaban panjang: mengapa membaginya dengan 24 * 60 * 60 (alias 86400) tidak aman
Sebagian besar jawaban menggunakan cap waktu UNIX (dan 86400 untuk mengonversikannya menjadi beberapa hari) membuat dua asumsi yang, jika disatukan, dapat menghasilkan skenario dengan hasil yang salah dan bug halus yang mungkin sulit dilacak, dan timbul beberapa hari, minggu atau bulan setelahnya. penyebaran yang sukses. Bukannya solusinya tidak bekerja - itu berhasil. Hari ini. Tetapi mungkin berhenti bekerja besok.
Kesalahan pertama adalah tidak mempertimbangkan bahwa ketika ditanya, "Berapa hari telah berlalu sejak kemarin?", Komputer mungkin akan menjawab nol jika antara saat ini dan saat yang ditunjukkan oleh "kemarin" kurang dari satu hari penuh telah berlalu.
Biasanya ketika mengonversi "hari" ke cap waktu UNIX, yang diperoleh adalah cap waktu untuk tengah malam hari itu.
Jadi antara tengah malam 1 Oktober dan 15 Oktober, lima belas hari telah berlalu. Tetapi antara 13:00 tanggal 1 Oktober dan 14:55 tanggal 15 Oktober, lima belas hari dikurangi 5 menit telah berlalu, dan sebagian besar solusi menggunakan floor()atau melakukan konversi bilangan bulat implisit akan melaporkan satu hari kurang dari yang diharapkan .
Jadi, "berapa hari yang lalu Ymd H: i: s"? akan menghasilkan jawaban yang salah .
Kesalahan kedua adalah menyamakan satu hari menjadi 86400 detik. Ini hampir selalu benar - itu terjadi cukup sering untuk mengabaikan kali tidak. Tetapi jarak dalam detik antara dua tengah malam berturut-turut tentu tidak 86400 setidaknya dua kali setahun ketika waktu musim panas ikut bermain. Membandingkan dua tanggal melintasi batas DST akan menghasilkan jawaban yang salah.
Jadi, bahkan jika Anda menggunakan "peretasan" untuk memaksa semua cap waktu tanggal menjadi jam tetap, katakan tengah malam (ini juga dilakukan secara implisit oleh berbagai bahasa dan kerangka kerja ketika Anda hanya menentukan hari-bulan-tahun dan bukan juga menit-menit-detik; happpens yang sama dengan tipe DATE dalam database seperti MySQL), rumus yang banyak digunakan
akan kembali, misalnya, 17 ketika DATE1 dan DATE2 berada di segmen DST yang sama tahun ini; tetapi mungkin mengembalikan 17.042, dan lebih buruk lagi, 16.958. Penggunaan floor () atau pemotongan implisit ke bilangan bulat kemudian akan mengonversi apa yang seharusnya menjadi 17 menjadi 16. Dalam keadaan lain, ekspresi seperti "$ hari> 17" akan kembali trueuntuk 17.042 bahkan jika ini menunjukkan bahwa jumlah hari yang telah berlalu adalah 18.
Dan hal-hal tumbuh lebih buruk karena kode tersebut tidak portabel di seluruh platform, karena beberapa dari mereka mungkin berlaku detik kabisat dan beberapa mungkin tidak . Pada platform yang melakukannya , perbedaan antara dua tanggal tidak akan menjadi 86400 tetapi 86401, atau mungkin 86399. Jadi kode yang bekerja pada bulan Mei dan benar-benar lulus semua tes akan berakhir pada Juni mendatang ketika 12,99999 hari dianggap 12 hari, bukan 13. Dua tanggal yang bekerja pada tahun 2015 tidak akan berfungsi pada tahun 2017 - tanggal yang sama , dan tahun tidak merupakan tahun kabisat. Tetapi antara 2018-03-01 dan 2017-03-01, pada platform yang peduli, 366 hari akan berlalu sebagai ganti 365, menjadikan 2018 sebagai tahun kabisat (yang bukan).
Jadi, jika Anda benar-benar ingin menggunakan cap waktu UNIX:
gunakan round()fungsi dengan bijak, bukan floor().
sebagai alternatif, jangan menghitung perbedaan antara D1-M1-YYY1 dan D2-M2-YYY2. Tanggal-tanggal tersebut akan benar-benar dianggap sebagai D1-M1-YYY1 00:00:00 dan D2-M2-YYY2 00:00:00. Sebaliknya, konversi antara D1-M1-YYY1 22:30:00 dan D2-M2-YYY2 04:30:00. Anda akan selalu mendapatkan sisa sekitar dua puluh jam. Ini bisa menjadi dua puluh satu jam atau sembilan belas, dan mungkin delapan belas jam, lima puluh sembilan menit tiga puluh enam detik. Tidak penting. Ini adalah margin besar yang akan tinggal di sana dan tetap positif untuk masa mendatang. Sekarang Anda dapat memotongnya dengan floor()aman.
The benar solusi meskipun, untuk menghindari konstanta ajaib, pembulatan kludges dan utang pemeliharaan, adalah untuk
gunakan perpustakaan waktu (Datetime, Carbon, apa pun); jangan roll Anda sendiri
tulis kasus uji komprehensif menggunakan pilihan tanggal yang benar-benar jahat - melintasi batas DST, melintasi tahun kabisat, melintasi detik kabisat, dan seterusnya, serta tanggal yang biasa. Idealnya (panggilan ke datetime cepat !) Menghasilkan empat tahun penuh (dan satu hari) senilai tanggal dengan mengumpulkan mereka dari string, secara berurutan, dan memastikan bahwa perbedaan antara hari pertama dan hari yang diuji meningkat dengan mantap satu. Ini akan memastikan bahwa jika ada perubahan dalam rutinitas tingkat rendah dan lompatan detik perbaikan mencoba untuk mendatangkan malapetaka, setidaknya Anda akan tahu .
jalankan tes-tes tersebut secara teratur bersama-sama dengan sisa test suite lainnya. Mereka hanya dalam hitungan milidetik, dan dapat menghemat waktu Anda menggaruk kepala selama beberapa jam .
Apa pun solusi Anda, ujilah!
Fungsi di funcdiffbawah ini mengimplementasikan salah satu solusi (seperti yang terjadi, yang diterima) dalam skenario dunia nyata.
<?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 between {$yearFrom} and {$yearTo}.\n";
Hasilnya adalah,
Thisfunction failed 280of its 14603 tests
Kisah Horor: biaya "menghemat waktu"
Ini sebenarnya terjadi beberapa bulan lalu. Seorang programmer yang cerdik memutuskan untuk menghemat beberapa mikrodetik dari perhitungan yang paling banyak memakan waktu sekitar tiga puluh detik, dengan memasukkan kode "(MidnightOfDateB-MidnightOfDateA) / 86400" yang terkenal di beberapa tempat. Itu sangat jelas optimasi sehingga dia bahkan tidak mendokumentasikannya, dan optimasi melewati tes integrasi dan mengintai dalam kode selama beberapa bulan, semua tanpa disadari.
Ini terjadi dalam sebuah program yang menghitung upah untuk beberapa penjual terlaris, yang paling sedikit memiliki pengaruh yang jauh lebih menakutkan daripada tim programmer beranggotakan lima orang yang dibuat bersama. Suatu hari beberapa bulan yang lalu, dengan alasan yang tidak terlalu penting, serangga itu menyerang - dan beberapa dari mereka kehilangan satu hari penuh komisi lemak. Mereka jelas tidak senang.
Yang jauh lebih buruk, mereka kehilangan kepercayaan (yang sudah sangat sedikit) yang mereka miliki dalam program yang tidak dirancang untuk secara diam-diam menghabisi mereka, dan berpura-pura - dan memperoleh - tinjauan kode lengkap dan terperinci dengan kasus uji yang dijalankan dan berkomentar dalam istilah awam (ditambah banyak) perawatan karpet merah pada minggu-minggu berikutnya).
Apa yang bisa saya katakan: di sisi positifnya, kami menyingkirkan banyak hutang teknis, dan mampu menulis ulang dan merevisi beberapa bagian dari kekacauan spageti yang menyimak kembali ke serangan COBOL di tahun 90-an yang berayun. Program ini tidak diragukan lagi berjalan lebih baik sekarang, dan ada banyak lagi informasi debug untuk segera dihapus ketika ada sesuatu yang mencurigakan. Saya memperkirakan bahwa hanya satu hal terakhir ini akan menghemat mungkin satu atau dua hari kerja per bulan untuk masa yang akan datang.
Di sisi minusnya, seluruh brouhaha membuat perusahaan harus membayar sekitar € 200.000 di muka - plus muka, ditambah tidak diragukan lagi daya tawar (dan, karenanya, lebih banyak uang).
Orang yang bertanggung jawab untuk "optimasi" telah berganti pekerjaan setahun yang lalu, sebelum bencana, tetapi masih ada pembicaraan untuk menuntutnya atas kerusakan. Dan itu tidak sesuai dengan eselon atas bahwa itu adalah "kesalahan orang terakhir" - itu tampak seperti pengaturan bagi kita untuk menyelesaikan masalah ini, dan pada akhirnya, kita masih berada di rumah anjing dan salah satu tim berencana untuk berhenti.
Sembilan puluh sembilan dari seratus, "86400 hack" akan bekerja dengan sempurna. (Misalnya dalam PHP, strtotime()akan mengabaikan DST dan melaporkan bahwa antara tengah malam Sabtu terakhir Oktober dan Senin berikutnya, tepatnya 2 * 24 * 60 * 60 detik telah berlalu, bahkan jika itu jelas tidak benar ... dan dua kesalahan dengan senang hati akan memperbaikinya).
Saudara-saudara, ini adalah satu contoh ketika tidak. Seperti kantung udara dan sabuk pengaman, Anda mungkin tidak akan pernah benar - benar membutuhkan kompleksitas (dan kemudahan penggunaan) dari DateTimeatau Carbon. Tetapi hari ketika Anda mungkin (atau hari ketika Anda harus membuktikan bahwa Anda memikirkan hal ini) akan datang sebagai pencuri di malam hari. Dipersiapkan.
Ketika saya melihat jawaban ini, saya pikir saya bodoh dan gila karena saya selalu menggunakan DateTime, tetapi Anda membuat saya mengerti bahwa menggunakan DateTime adalah cara yang benar. Terima kasih
Syncro
Hai, semuanya di sini, di SO, dapatkan di sini dengan mencari di google days between two days in phpatau serupa, hanya karena hidup ini terlalu singkat untuk menulis semuanya sendiri.
Denis Matafonov
1
penjelasan terperinci. +1
Anant Singh --- Alive to Die
1
Kadang-kadang saya berharap kita bisa lebih menyukai jawaban daripada pertanyaan.
Ini adalah cara prosedural yang baik untuk melakukannya menggunakan kelas DateTime. Itu hanya kurang jelas menggunakan objek interval ( $diffvariabel dalam hal ini). Sesuatu seperti if ($diff->days > 30) { [doyourstuff]; }
Komentar yang sangat lama di atas, tetapi itu tidak benar. StackOverflow tidak memungkinkan Anda untuk menjawab pertanyaan Anda sendiri (bahkan ketika Anda bertanya pertanyaan Anda). Namun, menjawab pertanyaan sendiri setelah seseorang memposting solusi yang sama dianggap tidak sopan.
Maarten Bodewes
Fungsi ini gagal 560 dari 14603 tesnya antara 1980 dan 2020.
LSerni
10
Yah, jawaban yang dipilih bukan yang paling benar karena akan gagal di luar UTC. Bergantung pada zona waktu ( daftar ), mungkin ada penyesuaian waktu yang membuat hari "tanpa" 24 jam, dan ini akan membuat perhitungan (60 * 60 * 24) gagal.
Ini dia contohnya:
date_default_timezone_set('europe/lisbon');
$time1 = strtotime('2016-03-27');
$time2 = strtotime('2016-03-29');
echo floor(($time2-$time1)/(60*60*24));^-- the output will be **1**
Jadi solusi yang benar akan menggunakan DateTime
date_default_timezone_set('europe/lisbon');
$date1 =newDateTime("2016-03-27");
$date2 =newDateTime("2016-03-29");
echo $date2->diff($date1)->format("%a");^-- the output will be **2**
function dateDiff($date1, $date2)//days find function{
$diff = strtotime($date2)- strtotime($date1);return abs(round($diff /86400));}//start day
$date1 ="11-10-2018";// end day
$date2 ="31-10-2018";// call the days find fun store to variable
$dateDiff = dateDiff($date1, $date2);
echo "Difference between two dates: ". $dateDiff ." Days ";
Dengan pertanyaan lama yang memiliki jawaban yang ada, berguna untuk menjelaskan aspek baru apa yang dibawa oleh jawaban Anda ke pertanyaan. Jika relevan, berguna juga untuk mengakui segala perubahan yang mungkin terjadi sejak pertanyaan diajukan.
// Change this to the day in the future
$day =15;// Change this to the month in the future
$month =11;// Change this to the year in the future
$year =2012;// $days is the number of days between now and the date in the future
$days =(int)((mktime (0,0,0,$month,$day,$year)- time(void))/86400);
echo "There are $days days until $day/$month/$year";
Selamat datang di SO! Ketika Anda membalas posting dengan kode yang adil, tolong jelaskan sedikit. Kode yang Anda bawa dihitung antara 2019-11-10 dan 2019-11-25. Jadi itu tidak menjawab pertanyaan. Itu sebabnya bagus untuk menjelaskan POV Anda lebih baik daripada downvoted.
David García Bodego
0
Jika Anda menggunakan MySql
function daysSince($date, $date2){
$q ="SELECT DATEDIFF('$date','$date2') AS days;";
$result = execQ($q);
$row = mysql_fetch_array($result,MYSQL_BOTH);return($row[0]);
Secara umum, saya menggunakan 'DateTime' untuk menemukan hari antara 2 tanggal. Tetapi jika dalam beberapa alasan, beberapa pengaturan server tidak mengaktifkan 'DateTime', itu akan menggunakan perhitungan sederhana (tetapi tidak aman) dengan 'strtotime ()'.
(new DateTime("2010-01-11"))->diff(new DateTime("2019-08-19"))->days;
Jawaban:
sumber
$your_date-$now
, jika Anda ingin masa depan mengembalikan integer positif.Jika Anda menggunakan
PHP 5.3 >
, ini adalah cara paling akurat untuk menghitung perbedaan:sumber
$date1
anterior$date2
), gunakan$diff = $date2->diff($date1)->format("%r%a");
sebagai gantinya.DateTime("2010-07-06")
?, apakah ituY-m-d
atauY-d-m
?, apa formatDateTime
parameter. yang mana hari?Dari PHP Versi 5.3 dan lebih tinggi, fungsi tanggal / waktu baru telah ditambahkan untuk mendapatkan perbedaan:
Hasil seperti di bawah ini:
Semoga ini bisa membantu!
sumber
Ubah tanggal Anda menjadi unix cap waktu, lalu kurangi satu dari yang lainnya. Itu akan memberi Anda perbedaan dalam hitungan detik, yang Anda bagi dengan 86400 (jumlah detik dalam sehari) untuk memberi Anda perkiraan jumlah hari dalam rentang itu.
Jika tanggal Anda dalam format
25.1.2010
,01/25/2010
atau2010-01-25
, Anda dapat menggunakanstrtotime
fungsi:Menggunakan
ceil
putaran jumlah hari hingga hari penuh berikutnya. Gunakanfloor
sebaliknya jika Anda ingin mendapatkan jumlah hari penuh antara dua tanggal tersebut.Jika tanggal Anda sudah dalam format cap waktu unix, Anda dapat melewati konversi dan cukup lakukan
$days_between
bagian. Untuk format tanggal yang lebih eksotis, Anda mungkin harus melakukan parsing khusus untuk memperbaikinya.sumber
$day
dan stempel waktu UNIX jam 1 siang$day+1
tidak selalu 86400 detik dalam zona waktu yang mengamati DST. Mungkin bernilai 23 atau 25 jam dalam hitungan detik alih-alih 24 jam.TL; DR jangan tidak menggunakan UNIX cap waktu. Jangan gunakan
time()
. Jika Anda melakukannya, bersiaplah jika keandalan 98,0825% gagal Anda. Gunakan DateTime (atau Karbon).The jawaban yang benar adalah salah satu yang diberikan oleh Saksham Gupta (jawaban lain juga benar):
Atau secara prosedural sebagai one-liner:
Dengan peringatan: '% a' tampaknya menunjukkan jumlah hari absolut . Jika Anda menginginkannya sebagai bilangan bulat yang ditandatangani, yaitu negatif ketika tanggal kedua adalah sebelum tanggal pertama, maka Anda perlu menggunakan awalan '% r' (yaitu
format('%r%a')
).Jika Anda benar-benar harus menggunakan cap waktu UNIX, atur zona waktu ke GMT untuk menghindari sebagian besar jebakan yang dirinci di bawah ini.
Jawaban panjang: mengapa membaginya dengan 24 * 60 * 60 (alias 86400) tidak aman
Sebagian besar jawaban menggunakan cap waktu UNIX (dan 86400 untuk mengonversikannya menjadi beberapa hari) membuat dua asumsi yang, jika disatukan, dapat menghasilkan skenario dengan hasil yang salah dan bug halus yang mungkin sulit dilacak, dan timbul beberapa hari, minggu atau bulan setelahnya. penyebaran yang sukses. Bukannya solusinya tidak bekerja - itu berhasil. Hari ini. Tetapi mungkin berhenti bekerja besok.
Kesalahan pertama adalah tidak mempertimbangkan bahwa ketika ditanya, "Berapa hari telah berlalu sejak kemarin?", Komputer mungkin akan menjawab nol jika antara saat ini dan saat yang ditunjukkan oleh "kemarin" kurang dari satu hari penuh telah berlalu.
Biasanya ketika mengonversi "hari" ke cap waktu UNIX, yang diperoleh adalah cap waktu untuk tengah malam hari itu.
Jadi antara tengah malam 1 Oktober dan 15 Oktober, lima belas hari telah berlalu. Tetapi antara 13:00 tanggal 1 Oktober dan 14:55 tanggal 15 Oktober, lima belas hari dikurangi 5 menit telah berlalu, dan sebagian besar solusi menggunakan
floor()
atau melakukan konversi bilangan bulat implisit akan melaporkan satu hari kurang dari yang diharapkan .Jadi, "berapa hari yang lalu Ymd H: i: s"? akan menghasilkan jawaban yang salah .
Kesalahan kedua adalah menyamakan satu hari menjadi 86400 detik. Ini hampir selalu benar - itu terjadi cukup sering untuk mengabaikan kali tidak. Tetapi jarak dalam detik antara dua tengah malam berturut-turut tentu tidak 86400 setidaknya dua kali setahun ketika waktu musim panas ikut bermain. Membandingkan dua tanggal melintasi batas DST akan menghasilkan jawaban yang salah.
Jadi, bahkan jika Anda menggunakan "peretasan" untuk memaksa semua cap waktu tanggal menjadi jam tetap, katakan tengah malam (ini juga dilakukan secara implisit oleh berbagai bahasa dan kerangka kerja ketika Anda hanya menentukan hari-bulan-tahun dan bukan juga menit-menit-detik; happpens yang sama dengan tipe DATE dalam database seperti MySQL), rumus yang banyak digunakan
atau
akan kembali, misalnya, 17 ketika DATE1 dan DATE2 berada di segmen DST yang sama tahun ini; tetapi mungkin mengembalikan 17.042, dan lebih buruk lagi, 16.958. Penggunaan floor () atau pemotongan implisit ke bilangan bulat kemudian akan mengonversi apa yang seharusnya menjadi 17 menjadi 16. Dalam keadaan lain, ekspresi seperti "$ hari> 17" akan kembali
true
untuk 17.042 bahkan jika ini menunjukkan bahwa jumlah hari yang telah berlalu adalah 18.Dan hal-hal tumbuh lebih buruk karena kode tersebut tidak portabel di seluruh platform, karena beberapa dari mereka mungkin berlaku detik kabisat dan beberapa mungkin tidak . Pada platform yang melakukannya , perbedaan antara dua tanggal tidak akan menjadi 86400 tetapi 86401, atau mungkin 86399. Jadi kode yang bekerja pada bulan Mei dan benar-benar lulus semua tes akan berakhir pada Juni mendatang ketika 12,99999 hari dianggap 12 hari, bukan 13. Dua tanggal yang bekerja pada tahun 2015 tidak akan berfungsi pada tahun 2017 - tanggal yang sama , dan tahun tidak merupakan tahun kabisat. Tetapi antara 2018-03-01 dan 2017-03-01, pada platform yang peduli, 366 hari akan berlalu sebagai ganti 365, menjadikan 2018 sebagai tahun kabisat (yang bukan).
Jadi, jika Anda benar-benar ingin menggunakan cap waktu UNIX:
gunakan
round()
fungsi dengan bijak, bukanfloor()
.sebagai alternatif, jangan menghitung perbedaan antara D1-M1-YYY1 dan D2-M2-YYY2. Tanggal-tanggal tersebut akan benar-benar dianggap sebagai D1-M1-YYY1 00:00:00 dan D2-M2-YYY2 00:00:00. Sebaliknya, konversi antara D1-M1-YYY1 22:30:00 dan D2-M2-YYY2 04:30:00. Anda akan selalu mendapatkan sisa sekitar dua puluh jam. Ini bisa menjadi dua puluh satu jam atau sembilan belas, dan mungkin delapan belas jam, lima puluh sembilan menit tiga puluh enam detik. Tidak penting. Ini adalah margin besar yang akan tinggal di sana dan tetap positif untuk masa mendatang. Sekarang Anda dapat memotongnya dengan
floor()
aman.The benar solusi meskipun, untuk menghindari konstanta ajaib, pembulatan kludges dan utang pemeliharaan, adalah untuk
gunakan perpustakaan waktu (Datetime, Carbon, apa pun); jangan roll Anda sendiri
tulis kasus uji komprehensif menggunakan pilihan tanggal yang benar-benar jahat - melintasi batas DST, melintasi tahun kabisat, melintasi detik kabisat, dan seterusnya, serta tanggal yang biasa. Idealnya (panggilan ke datetime cepat !) Menghasilkan empat tahun penuh (dan satu hari) senilai tanggal dengan mengumpulkan mereka dari string, secara berurutan, dan memastikan bahwa perbedaan antara hari pertama dan hari yang diuji meningkat dengan mantap satu. Ini akan memastikan bahwa jika ada perubahan dalam rutinitas tingkat rendah dan lompatan detik perbaikan mencoba untuk mendatangkan malapetaka, setidaknya Anda akan tahu .
jalankan tes-tes tersebut secara teratur bersama-sama dengan sisa test suite lainnya. Mereka hanya dalam hitungan milidetik, dan dapat menghemat waktu Anda menggaruk kepala selama beberapa jam .
Apa pun solusi Anda, ujilah!
Fungsi di
funcdiff
bawah ini mengimplementasikan salah satu solusi (seperti yang terjadi, yang diterima) dalam skenario dunia nyata.Hasilnya adalah,
Kisah Horor: biaya "menghemat waktu"
Ini sebenarnya terjadi beberapa bulan lalu. Seorang programmer yang cerdik memutuskan untuk menghemat beberapa mikrodetik dari perhitungan yang paling banyak memakan waktu sekitar tiga puluh detik, dengan memasukkan kode "(MidnightOfDateB-MidnightOfDateA) / 86400" yang terkenal di beberapa tempat. Itu sangat jelas optimasi sehingga dia bahkan tidak mendokumentasikannya, dan optimasi melewati tes integrasi dan mengintai dalam kode selama beberapa bulan, semua tanpa disadari.
Ini terjadi dalam sebuah program yang menghitung upah untuk beberapa penjual terlaris, yang paling sedikit memiliki pengaruh yang jauh lebih menakutkan daripada tim programmer beranggotakan lima orang yang dibuat bersama. Suatu hari beberapa bulan yang lalu, dengan alasan yang tidak terlalu penting, serangga itu menyerang - dan beberapa dari mereka kehilangan satu hari penuh komisi lemak. Mereka jelas tidak senang.
Yang jauh lebih buruk, mereka kehilangan kepercayaan (yang sudah sangat sedikit) yang mereka miliki dalam program yang tidak dirancang untuk secara diam-diam menghabisi mereka, dan berpura-pura - dan memperoleh - tinjauan kode lengkap dan terperinci dengan kasus uji yang dijalankan dan berkomentar dalam istilah awam (ditambah banyak) perawatan karpet merah pada minggu-minggu berikutnya).
Apa yang bisa saya katakan: di sisi positifnya, kami menyingkirkan banyak hutang teknis, dan mampu menulis ulang dan merevisi beberapa bagian dari kekacauan spageti yang menyimak kembali ke serangan COBOL di tahun 90-an yang berayun. Program ini tidak diragukan lagi berjalan lebih baik sekarang, dan ada banyak lagi informasi debug untuk segera dihapus ketika ada sesuatu yang mencurigakan. Saya memperkirakan bahwa hanya satu hal terakhir ini akan menghemat mungkin satu atau dua hari kerja per bulan untuk masa yang akan datang.
Di sisi minusnya, seluruh brouhaha membuat perusahaan harus membayar sekitar € 200.000 di muka - plus muka, ditambah tidak diragukan lagi daya tawar (dan, karenanya, lebih banyak uang).
Orang yang bertanggung jawab untuk "optimasi" telah berganti pekerjaan setahun yang lalu, sebelum bencana, tetapi masih ada pembicaraan untuk menuntutnya atas kerusakan. Dan itu tidak sesuai dengan eselon atas bahwa itu adalah "kesalahan orang terakhir" - itu tampak seperti pengaturan bagi kita untuk menyelesaikan masalah ini, dan pada akhirnya, kita masih berada di rumah anjing dan salah satu tim berencana untuk berhenti.
Sembilan puluh sembilan dari seratus, "86400 hack" akan bekerja dengan sempurna. (Misalnya dalam PHP,
strtotime()
akan mengabaikan DST dan melaporkan bahwa antara tengah malam Sabtu terakhir Oktober dan Senin berikutnya, tepatnya 2 * 24 * 60 * 60 detik telah berlalu, bahkan jika itu jelas tidak benar ... dan dua kesalahan dengan senang hati akan memperbaikinya).Saudara-saudara, ini adalah satu contoh ketika tidak. Seperti kantung udara dan sabuk pengaman, Anda mungkin tidak akan pernah benar - benar membutuhkan kompleksitas (dan kemudahan penggunaan) dari
DateTime
atauCarbon
. Tetapi hari ketika Anda mungkin (atau hari ketika Anda harus membuktikan bahwa Anda memikirkan hal ini) akan datang sebagai pencuri di malam hari. Dipersiapkan.sumber
days between two days in php
atau serupa, hanya karena hidup ini terlalu singkat untuk menulis semuanya sendiri.Mudah digunakan date_diff
sumber
$diff
variabel dalam hal ini). Sesuatu sepertiif ($diff->days > 30) { [doyourstuff]; }
Gaya berorientasi objek:
Gaya prosedural:
sumber
Digunakan ini :)
Sekarang berhasil
sumber
Yah, jawaban yang dipilih bukan yang paling benar karena akan gagal di luar UTC. Bergantung pada zona waktu ( daftar ), mungkin ada penyesuaian waktu yang membuat hari "tanpa" 24 jam, dan ini akan membuat perhitungan (60 * 60 * 24) gagal.
Ini dia contohnya:
Jadi solusi yang benar akan menggunakan DateTime
sumber
Hitung perbedaan antara dua tanggal:
Output: +272 hari
Fungsi date_diff () mengembalikan perbedaan antara dua objek DateTime.
sumber
sumber
Saya menggunakan Karbon dalam proyek komposer saya untuk ini dan tujuan serupa.
Ini akan semudah ini:
sumber
Anda dapat menemukan tanggal hanya dengan
sumber
dan, jika perlu:
sumber
Jika Anda memiliki waktu dalam detik (cap waktu IE unix), maka Anda cukup mengurangi waktu dan membaginya dengan 86400 (detik per hari)
sumber
sumber
Anda dapat mencoba kode di bawah ini:
sumber
sumber
Jika Anda ingin mengulangi semua hari antara tanggal mulai dan berakhir, saya membuat ini:
sumber
Cara termudah untuk menemukan perbedaan hari antara dua tanggal
sumber
sumber
Ini adalah versi saya yang ditingkatkan yang menunjukkan 1 Tahun 2 Bulan 25 hari jika parameter ke-2 dilewati.
sumber
sumber
menggunakan kode di atas sangat sederhana. Terima kasih.
sumber
sumber
Menggunakan fungsi sederhana ini. Deklarasikan fungsi
dan panggil fungsi ini seperti ini di tempat yang Anda inginkan
sumber
sumber
Jika Anda menggunakan MySql
}
}
sumber
Coba gunakan Karbon
Anda juga bisa menggunakannya
untuk membuat objek tanggal Karbon menggunakan string cap waktu yang diberikan.
sumber
Mencari semua jawaban, saya menulis fungsi universal yang berfungsi pada semua versi PHP.
Secara umum, saya menggunakan 'DateTime' untuk menemukan hari antara 2 tanggal. Tetapi jika dalam beberapa alasan, beberapa pengaturan server tidak mengaktifkan 'DateTime', itu akan menggunakan perhitungan sederhana (tetapi tidak aman) dengan 'strtotime ()'.
sumber