Tanggapan awal saya adalah, mengubah kedua nilai menjadi stempel waktu menggunakan strftime()dan membagi perbedaan dengan 3600, tetapi apakah itu akan selalu berhasil? Sialan, Waktu Musim Panas!
Pekka
@Pekka: tidak, itu tidak akan selalu berhasil, saya kira ... Lihat jawaban saya. Di sana saya telah memposting solusi mempertimbangkan, zona waktu, tahun kabisat, detik kabisat, dan dst :)
Fidi
@Pekka, jika Anda menggunakannya strtotime()AKAN selalu berfungsi, selama Anda menggunakan zona waktu default ATAU secara eksplisit menentukan offset zona waktu. Tidak ada alasan untuk mengutuk DST.
Walter Tross
Jawaban:
205
Yang lebih baru PHP-Versi menyediakan beberapa kelas baru yang disebut DateTime, DateInterval, DateTimeZonedan DatePeriod. Hal yang keren tentang kelas ini adalah, kelas ini mempertimbangkan zona waktu yang berbeda, tahun kabisat, detik kabisat, musim panas, dll. Dan di atas itu, sangat mudah digunakan. Inilah yang Anda inginkan dengan bantuan objek ini:
// Create two new DateTime-objects...
$date1 =newDateTime('2006-04-12T12:30:00');
$date2 =newDateTime('2006-04-14T11:30:00');// The diff-methods returns a new DateInterval-object...
$diff = $date2->diff($date1);// Call the format method on the DateInterval-object
echo $diff->format('%a Day and %h hours');
Objek DateInterval, yang dikembalikan juga menyediakan metode selain format. Jika Anda menginginkan hasil dalam hitungan jam saja, Anda bisa melakukan sesuatu seperti ini:
Semua kelas ini juga menawarkan cara prosedural / fungsional untuk beroperasi dengan tanggal. Oleh karena itu, lihat ikhtisar: http://php.net/manual/book.datetime.php
+1 Kerja bagus! Ini terlihat kokoh dan merupakan gambaran yang bagus. Penting untuk diperhatikan bahwa penghitungan dapat bervariasi menurut zona waktu karena aturan DST yang berbeda, jadi sebaiknya selalu tentukan zona dan tidak bergantung pada pengaturan server.
Pekka
Ya. Dengan objek ini Anda bahkan dapat menghitung antara tanggal dalam zona waktu yang berbeda. $date1 = new DateTime('2006-04-12T12:30:00 Europe/Berlin');dan$date2 = new DateTime('2006-04-14T11:30:00 America/New_York');
Fidi
3
Jika seseorang mengalami masalah yang sama seperti yang baru saja saya lakukan di mana $diff->dsama dengan 0 (karena saya mencoba menghitung jam antara dua tanggal yang persis berjarak 2 bulan): Berlari var_dump($diff)menunjukkan kepada saya parameter lain:, ["days"]=>int(61)jadi saya akhirnya menggunakan $hours = $diff->days * 24;, dan itu datang mendekati "rata-rata" dari 1440 jam yang diberikan 2 30 hari bulan, jadi itu terlihat jauh lebih baik daripada hasil 0. (Menebak versi PHP saya agak tua ...)
semmelbroesel
2
Maksud saya, di banyak bagian dunia, setahun memiliki satu hari 23 jam dan satu hari 25 jam.
Walter Tross
4
@Amal Murali, jadi Anda memutuskan untuk memberikan bonus untuk jawaban ini, mana SALAH? Sudahkah Anda mencoba menghitung dengan jawaban ini jumlah jam antara siang hari pertama Januari dan siang hari pertama Juni, di zona waktu mana pun yang memiliki DST (waktu musim panas)? Anda akan mendapatkan hasil genap, sedangkan hasil sebenarnya adalah ganjil.
$start =new \DateTime('2006-04-12T12:30:00');
$end =new \DateTime('2006-04-14T11:30:00');//determine what interval should be used - can change to weeks, months, etc
$interval =new \DateInterval('PT1H');//create periods every hour between the two dates
$periods =new \DatePeriod($start, $interval, $end);//count the number of objects within the periods
$hours = iterator_count($periods);
echo $hours .' hours';//difference between Unix Epoch
$diff = $end->getTimestamp()- $start->getTimestamp();
$hours = $diff /(60*60);
echo $hours .' hours (60 * 60)';//difference between days
$diff = $end->diff($start);
$hours = $diff->h +($diff->days *24);
echo $hours .' hours (days * 24)';
Harap diperhatikan bahwa DatePeriodtidak termasuk satu jam untuk DST tetapi tidak menambahkan satu jam lagi saat DST berakhir. Jadi penggunaannya bergantung pada hasil dan rentang tanggal yang Anda inginkan.
Bagi siapa pun yang bingung seperti saya saat melihat parameter konstruktor DateInterval, formatnya adalah Durasi ISO 8601
TheKarateKid
Catatan lain adalah bahwa DateIntervaltidak menerima nilai pecahan seperti pada spesifikasi ISO 8601. Jadi P1.2Ybukan durasi yang valid di PHP.
fyrye
CATATAN: iterator_count hanya akan mengembalikan hasil positif. Jika tanggal pertama lebih besar dari yang kedua, hasil perbedaannya adalah 0.
SubjectDelta
1
@SubjectDelta masalah tidak terkait iterator_count, ini karena DatePeriodtidak dapat menghasilkan tanggal ketika tanggal mulai di masa depan dari tanggal akhir. Lihat: 3v4l.org/Ypsp1 untuk menggunakan tanggal negatif, Anda perlu menentukan interval negatif, DateInterval::createFromDateString('-1 hour');dengan tanggal mulai di masa lalu dari tanggal akhir.
fyrye
1
@SubjectDelta ini adalah nuansa lain dari DatePeriod, karena secara default akan menyertakan tanggal mulai antara periode yang ditentukan kecuali jika kurang dari atau sama dengan tanggal mulai. Akibatnya Anda memberi tahu php untuk membuat periode 1 jam antara dua tanggal, dalam waktu 1 detik. Anda perlu menghapus menit dan detik dari objek tanggal Anda, karena tidak relevan dalam penghitungan, menggunakan DateTime::setTime(date->format('H'), 0). 3v4l.org/K7uss Dengan cara ini jika Anda melebihi rentang 1 detik, tanggal lain tidak dibuat.
Bagaimana jika ada 2 jam 30 menit antara? Jawaban Anda akan menghasilkan 3 jam. Saya pikir akan lebih baik menggunakan lantai sehingga akan menghasilkan 2 jam. Sangat tergantung pada situasinya.
Kapitein Witbaard
14
Cara termudah untuk mendapatkan jumlah jam yang benar antara dua tanggal (waktu), bahkan di seluruh perubahan waktu musim panas, adalah dengan menggunakan perbedaan di stempel waktu Unix. Stempel waktu Unix adalah detik berlalu sejak 1970-01-01T00: 00: 00 UTC, mengabaikan detik kabisat (ini tidak masalah karena Anda mungkin tidak memerlukan ketepatan ini, dan karena cukup sulit untuk memperhitungkan detik kabisat).
Cara paling fleksibel untuk mengonversi string datetime dengan informasi zona waktu opsional menjadi stempel waktu Unix adalah dengan membuat objek DateTime (opsional dengan DateTimeZone sebagai argumen kedua dalam konstruktor), lalu memanggil metode getTimestamp -nya .
Dari komentar di manual , tampaknya, untuk kesesuaian dengan tanggal pra-zaman, format("U")lebih disukai daripadagetTimestamp()
Arth
1
@Arth, saya tidak tahu kapan ini masalahnya, tetapi di PHP 5.5.9 saya, itu tidak benar lagi. getTimestamp()sekarang mengembalikan nilai yang sama persis dengan format("U"). Yang pertama adalah integer, sedangkan yang terakhir adalah string (kurang efisien di sini).
Walter Tross
Keren, mungkin itu benar di versi sebelumnya .. Ya, integer akan lebih bersih, jadi saya lebih suka getTimestamp()jika saya bisa yakin.
Arth
4
//Calculate number of hours between pass and now
$dayinpass ="2013-06-23 05:09:12";
$today = time();
$dayinpass= strtotime($dayinpass);
echo round(abs($today-$dayinpass)/60/60);
Ini juga merupakan salinan dari formulir jawaban 2010.
Daniel W.
2
Sayangnya solusi yang diberikan oleh FaileN tidak berfungsi seperti yang dinyatakan oleh Walter Tross .. hari mungkin bukan 24 jam!
Saya suka menggunakan Objek PHP jika memungkinkan dan untuk sedikit lebih fleksibel, saya telah membuat fungsi berikut:
/**
* @param DateTimeInterface $a
* @param DateTimeInterface $b
* @param bool $absolute Should the interval be forced to be positive?
* @param string $cap The greatest time unit to allow
*
* @return DateInterval The difference as a time only interval
*/function time_diff(DateTimeInterface $a,DateTimeInterface $b, $absolute=false, $cap='H'){// Get unix timestamps, note getTimeStamp() is limited
$b_raw = intval($b->format("U"));
$a_raw = intval($a->format("U"));// Initial Interval properties
$h =0;
$m =0;
$invert =0;// Is interval negative?if(!$absolute && $b_raw<$a_raw){
$invert =1;}// Working diff, reduced as larger time units are calculated
$working = abs($b_raw-$a_raw);// If capped at hours, calc and remove hours, cap at minutesif($cap =='H'){
$h = intval($working/3600);
$working -= $h *3600;
$cap ='M';}// If capped at minutes, calc and remove minutesif($cap =='M'){
$m = intval($working/60);
$working -= $m *60;}// Seconds remain
$s = $working;// Build interval and invert if necessary
$interval =newDateInterval('PT'.$h.'H'.$m.'M'.$s.'S');
$interval->invert=$invert;return $interval;}
Ini seperti date_diff()membuat DateTimeInterval, tetapi dengan unit tertinggi sebagai jam bukan tahun .. dapat diformat seperti biasa.
$interval = time_diff($date_a, $date_b);
echo $interval->format('%r%H');// For hours (with sign)
NB saya gunakan format('U')sebagai ganti getTimestamp()karena komentar di manual . Perhatikan juga bahwa 64-bit diperlukan untuk tanggal pasca-zaman dan pra-zaman-negatif!
Fungsi ini membantu Anda menghitung tahun dan bulan yang tepat antara dua tanggal tertentu, $doj1dan $doj. Ini mengembalikan contoh 4.3 berarti 4 tahun dan 3 bulan.
<?php
function cal_exp($doj1){
$doj1=strtotime($doj1);
$doj=date("m/d/Y",$doj1);//till date or any given date
$now=date("m/d/Y");//$b=strtotime($b1);//echo $c=$b1-$a2;//echo date("Y-m-d H:i:s",$c);
$year=date("Y");//$chk_leap=is_leapyear($year);//$year_diff=365.25;
$x=explode("/",$doj);
$y1=explode("/",$now);
$yy=$x[2];
$mm=$x[0];
$dd=$x[1];
$yy1=$y1[2];
$mm1=$y1[0];
$dd1=$y1[1];
$mn=0;
$mn1=0;
$ye=0;if($mm1>$mm){
$mn=$mm1-$mm;if($dd1<$dd){
$mn=$mn-1;}
$ye=$yy1-$yy;}elseif($mm1<$mm){
$mn=12-$mm;//$mn=$mn;if($mm!=1){
$mn1=$mm1-1;}
$mn+=$mn1;if($dd1>$dd){
$mn+=1;}
$yy=$yy+1;
$ye=$yy1-$yy;}else{
$ye=$yy1-$yy;
$ye=$ye-1;
$mn=12-1;if($dd1>$dd){
$ye+=1;
$mn=0;}}
$to=$ye." year and ".$mn." months";return $ye.".".$mn;/*return daysDiff($x[2],$x[0],$x[1]);
$days=dateDiff("/",$now,$doj)/$year_diff;
$days_exp=explode(".",$days);
return $years_exp=$days; //number of years exp*/}?>
Pengeditan yang disarankan terlalu kecil, tetapi <phpperlu diubah menjadi <?phpAtau setujui pengeditan yang disarankan, yang menghapus bug secara bersamaan.
anishsane
0
Ini bekerja dalam proyek saya. Saya pikir, ini akan membantu Anda.
Jika Tanggal sudah lewat maka pembalikan akan 1.
Jika Tanggal di masa depan maka pembalikan akan 0.
Catatan Zona waktu akan diteruskan dan keluaran seperti +0:00saat menggunakan @pada konstruktor DateTime. Saat menggunakan DateTime::modify()metode ini akan meneruskan stempel waktu sebagai +0:00dan menampilkan zona waktu saat ini. Atau gunakan $date = new DateTime(); $date->setTimestamp($unix_timestamp);lihat: 3v4l.org/BoAWI
fyrye
0
Karbon juga bisa menjadi cara yang bagus untuk digunakan.
Carbon memperluas kelas DateTime untuk mewarisi metode termasuk diff(). Ia menambahkan gula yang bagus seperti diffInHours, diffInMintutes, diffInSecondsdll
Pertama, Anda harus membuat objek interval dari rentang tanggal. Dengan kata-kata yang digunakan dalam kalimat ini saja, seseorang dapat dengan mudah mengidentifikasi abstraksi dasar yang dibutuhkan. Ada interval sebagai sebuah konsep, dan beberapa cara lagi untuk menerapkannya, termasuk yang sudah disebutkan - dari rentang tanggal. Jadi, interval terlihat seperti itu:
Selain jawaban @ fyrye yang sangat membantu, ini adalah solusi yang oke untuk bug yang disebutkan (yang ini ), DatePeriod mengurangi satu jam ketika memasuki musim panas, tetapi tidak menambahkan satu jam ketika meninggalkan musim panas (dan dengan demikian Maret Eropa / Berlin memiliki mengoreksi 743 jam tetapi Oktober memiliki 744, bukan 745 jam):
Menghitung jam dalam sebulan (atau rentang waktu apa pun), dengan mempertimbangkan transisi DST di kedua arah
function getMonthHours(string $year,string $month, \DateTimeZone $timezone):int{// or whatever start and end \DateTimeInterface objects you like
$start =new \DateTimeImmutable($year .'-'. $month .'-01 00:00:00', $timezone);
$end =new \DateTimeImmutable((new \DateTimeImmutable($year .'-'. $month .'-01 23:59:59', $timezone))->format('Y-m-t H:i:s'), $timezone);// count the hours just utilizing \DatePeriod, \DateInterval and iterator_count, hell yeah!
$hours = iterator_count(new \DatePeriod($start,new \DateInterval('PT1H'), $end));// find transitions and check, if there is one that leads to a positive offset// that isn't added by \DatePeriod// this is the workaround for https://bugs.php.net/bug.php?id=75685
$transitions = $timezone->getTransitions((int)$start->format('U'),(int)$end->format('U'));if(2=== count($transitions)&& $transitions[0]['offset']- $transitions[1]['offset']>0){
$hours +=(round(($transitions[0]['offset']- $transitions[1]['offset'])/3600));}return $hours;}
$myTimezoneWithDST =new \DateTimeZone('Europe/Berlin');
var_dump(getMonthHours('2020','01', $myTimezoneWithDST));// 744
var_dump(getMonthHours('2020','03', $myTimezoneWithDST));// 743
var_dump(getMonthHours('2020','10', $myTimezoneWithDST));// 745, finally!
$myTimezoneWithoutDST =new \DateTimeZone('UTC');
var_dump(getMonthHours('2020','01', $myTimezoneWithoutDST));// 744
var_dump(getMonthHours('2020','03', $myTimezoneWithoutDST));// 744
var_dump(getMonthHours('2020','10', $myTimezoneWithoutDST));// 744
NB Jika Anda memeriksa rentang waktu (lebih lama), yang mengarah ke lebih dari dua transisi tersebut, solusi saya tidak akan menyentuh jam yang dihitung untuk mengurangi potensi efek samping yang lucu. Dalam kasus seperti itu, solusi yang lebih rumit harus diterapkan. Seseorang dapat mengulang semua transisi yang ditemukan dan membandingkan arus dengan yang terakhir dan memeriksa apakah itu satu dengan DST true-> false.
strftime()
dan membagi perbedaan dengan 3600, tetapi apakah itu akan selalu berhasil? Sialan, Waktu Musim Panas!strtotime()
AKAN selalu berfungsi, selama Anda menggunakan zona waktu default ATAU secara eksplisit menentukan offset zona waktu. Tidak ada alasan untuk mengutuk DST.Jawaban:
Yang lebih baru PHP-Versi menyediakan beberapa kelas baru yang disebut
DateTime
,DateInterval
,DateTimeZone
danDatePeriod
. Hal yang keren tentang kelas ini adalah, kelas ini mempertimbangkan zona waktu yang berbeda, tahun kabisat, detik kabisat, musim panas, dll. Dan di atas itu, sangat mudah digunakan. Inilah yang Anda inginkan dengan bantuan objek ini:Objek DateInterval, yang dikembalikan juga menyediakan metode selain
format
. Jika Anda menginginkan hasil dalam hitungan jam saja, Anda bisa melakukan sesuatu seperti ini:Dan berikut ini tautan untuk dokumentasi:
Semua kelas ini juga menawarkan cara prosedural / fungsional untuk beroperasi dengan tanggal. Oleh karena itu, lihat ikhtisar: http://php.net/manual/book.datetime.php
sumber
$date1 = new DateTime('2006-04-12T12:30:00 Europe/Berlin');
dan$date2 = new DateTime('2006-04-14T11:30:00 America/New_York');
$diff->d
sama dengan 0 (karena saya mencoba menghitung jam antara dua tanggal yang persis berjarak 2 bulan): Berlarivar_dump($diff)
menunjukkan kepada saya parameter lain:,["days"]=>int(61)
jadi saya akhirnya menggunakan$hours = $diff->days * 24;
, dan itu datang mendekati "rata-rata" dari 1440 jam yang diberikan 2 30 hari bulan, jadi itu terlihat jauh lebih baik daripada hasil 0. (Menebak versi PHP saya agak tua ...)sumber
$diff / 3600
?Untuk menyediakan metode lain
DatePeriod
saat menggunakan zona waktu UTC atau GMT .Hitung Jam https://3v4l.org/Mu3HD
Hasil
Hitung Jam dengan Daylight Savings https://3v4l.org/QBQUB
Harap diperhatikan bahwa
DatePeriod
tidak termasuk satu jam untuk DST tetapi tidak menambahkan satu jam lagi saat DST berakhir. Jadi penggunaannya bergantung pada hasil dan rentang tanggal yang Anda inginkan.Lihat laporan bug saat ini
Hasil
sumber
DateInterval
tidak menerima nilai pecahan seperti pada spesifikasi ISO 8601. JadiP1.2Y
bukan durasi yang valid di PHP.iterator_count
, ini karenaDatePeriod
tidak dapat menghasilkan tanggal ketika tanggal mulai di masa depan dari tanggal akhir. Lihat: 3v4l.org/Ypsp1 untuk menggunakan tanggal negatif, Anda perlu menentukan interval negatif,DateInterval::createFromDateString('-1 hour');
dengan tanggal mulai di masa lalu dari tanggal akhir.DatePeriod
, karena secara default akan menyertakan tanggal mulai antara periode yang ditentukan kecuali jika kurang dari atau sama dengan tanggal mulai. Akibatnya Anda memberi tahu php untuk membuat periode 1 jam antara dua tanggal, dalam waktu 1 detik. Anda perlu menghapus menit dan detik dari objek tanggal Anda, karena tidak relevan dalam penghitungan, menggunakanDateTime::setTime(date->format('H'), 0)
. 3v4l.org/K7uss Dengan cara ini jika Anda melebihi rentang 1 detik, tanggal lain tidak dibuat.jawabanmu adalah:
round((strtotime($day2) - strtotime($day1))/(60*60))
sumber
Cara termudah untuk mendapatkan jumlah jam yang benar antara dua tanggal (waktu), bahkan di seluruh perubahan waktu musim panas, adalah dengan menggunakan perbedaan di stempel waktu Unix. Stempel waktu Unix adalah detik berlalu sejak 1970-01-01T00: 00: 00 UTC, mengabaikan detik kabisat (ini tidak masalah karena Anda mungkin tidak memerlukan ketepatan ini, dan karena cukup sulit untuk memperhitungkan detik kabisat).
Cara paling fleksibel untuk mengonversi string datetime dengan informasi zona waktu opsional menjadi stempel waktu Unix adalah dengan membuat objek DateTime (opsional dengan DateTimeZone sebagai argumen kedua dalam konstruktor), lalu memanggil metode getTimestamp -nya .
sumber
format("U")
lebih disukai daripadagetTimestamp()
getTimestamp()
sekarang mengembalikan nilai yang sama persis denganformat("U")
. Yang pertama adalah integer, sedangkan yang terakhir adalah string (kurang efisien di sini).getTimestamp()
jika saya bisa yakin.sumber
Saya kira fungsi strtotime () menerima format tanggal ini.
sumber
sumber
Sayangnya solusi yang diberikan oleh FaileN tidak berfungsi seperti yang dinyatakan oleh Walter Tross .. hari mungkin bukan 24 jam!
Saya suka menggunakan Objek PHP jika memungkinkan dan untuk sedikit lebih fleksibel, saya telah membuat fungsi berikut:
Ini seperti
date_diff()
membuatDateTimeInterval
, tetapi dengan unit tertinggi sebagai jam bukan tahun .. dapat diformat seperti biasa.NB saya gunakan
format('U')
sebagai gantigetTimestamp()
karena komentar di manual . Perhatikan juga bahwa 64-bit diperlukan untuk tanggal pasca-zaman dan pra-zaman-negatif!sumber
Fungsi ini membantu Anda menghitung tahun dan bulan yang tepat antara dua tanggal tertentu,
$doj1
dan$doj
. Ini mengembalikan contoh 4.3 berarti 4 tahun dan 3 bulan.sumber
<php
perlu diubah menjadi<?php
Atau setujui pengeditan yang disarankan, yang menghapus bug secara bersamaan.Ini bekerja dalam proyek saya. Saya pikir, ini akan membantu Anda.
Jika Tanggal sudah lewat maka pembalikan akan 1.
Jika Tanggal di masa depan maka pembalikan akan 0.
sumber
Untuk meneruskan stempel waktu unix gunakan notasi ini
sumber
+0:00
saat menggunakan@
pada konstruktor DateTime. Saat menggunakanDateTime::modify()
metode ini akan meneruskan stempel waktu sebagai+0:00
dan menampilkan zona waktu saat ini. Atau gunakan$date = new DateTime(); $date->setTimestamp($unix_timestamp);
lihat: 3v4l.org/BoAWIKarbon juga bisa menjadi cara yang bagus untuk digunakan.
Dari situs web mereka:
Contoh:
Carbon memperluas kelas DateTime untuk mewarisi metode termasuk
diff()
. Ia menambahkan gula yang bagus sepertidiffInHours
,diffInMintutes
,diffInSeconds
dllsumber
Pertama, Anda harus membuat objek interval dari rentang tanggal. Dengan kata-kata yang digunakan dalam kalimat ini saja, seseorang dapat dengan mudah mengidentifikasi abstraksi dasar yang dibutuhkan. Ada interval sebagai sebuah konsep, dan beberapa cara lagi untuk menerapkannya, termasuk yang sudah disebutkan - dari rentang tanggal. Jadi, interval terlihat seperti itu:
FromISO8601
memiliki semantik yang sama: itu adalah objek datetime yang dibuatfrom iso8601-formatted string
, oleh karena itu namanya.Saat Anda memiliki jeda, Anda dapat memformatnya sesuka Anda. Jika Anda membutuhkan sejumlah jam penuh, Anda bisa memilikinya
Jika Anda ingin total jam yang ditentukan, ini dia:
Untuk informasi lebih lanjut tentang pendekatan ini dan beberapa contoh, lihat entri ini .
sumber
Selain jawaban @ fyrye yang sangat membantu, ini adalah solusi yang oke untuk bug yang disebutkan (yang ini ), DatePeriod mengurangi satu jam ketika memasuki musim panas, tetapi tidak menambahkan satu jam ketika meninggalkan musim panas (dan dengan demikian Maret Eropa / Berlin memiliki mengoreksi 743 jam tetapi Oktober memiliki 744, bukan 745 jam):
Menghitung jam dalam sebulan (atau rentang waktu apa pun), dengan mempertimbangkan transisi DST di kedua arah
NB Jika Anda memeriksa rentang waktu (lebih lama), yang mengarah ke lebih dari dua transisi tersebut, solusi saya tidak akan menyentuh jam yang dihitung untuk mengurangi potensi efek samping yang lucu. Dalam kasus seperti itu, solusi yang lebih rumit harus diterapkan. Seseorang dapat mengulang semua transisi yang ditemukan dan membandingkan arus dengan yang terakhir dan memeriksa apakah itu satu dengan DST true-> false.
sumber
Anda bisa mencoba yang ini.
sumber