Bagaimana cara memeriksa apakah suatu tanggal dalam kisaran tertentu?

86

Jika Anda memiliki $start_datedan $end_date, bagaimana Anda dapat memeriksa apakah tanggal yang diberikan oleh pengguna termasuk dalam kisaran itu?

misalnya

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28'; 

Pada saat tanggalnya adalah string, apakah akan membantu jika mengubahnya menjadi bilangan bulat timestamp?

meleyal
sumber
Ini akan membantu, maka Anda akan memiliki akses ke fungsi manipulasi tanggal yang ada.
ChrisF
3
Berhati-hatilah dengan batasan stempel waktu karena stempel waktu Unix dimulai pada epoch, yaitu 1 Januari 1970 (1970-01-01), sehingga Anda dapat memiliki perilaku lucu saat menguji tanggal sebelum 1970.
Shadi Almosri
1
@Shadi Anda tahu ada yang namanya angka NEGATIF, kan?
Jeremy Logan
@fiXedd masalah dasar yang sama tetap ada - meskipun mengizinkan cap waktu negatif, cap waktu 32 bit tidak dapat mewakili tanggal sebelum 1902.
Frank Farmer

Jawaban:

123

Mengonversinya menjadi stempel waktu adalah cara yang baik, menggunakan strtotime , mis

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28';

check_in_range($start_date, $end_date, $date_from_user);


function check_in_range($start_date, $end_date, $date_from_user)
{
  // Convert to timestamp
  $start_ts = strtotime($start_date);
  $end_ts = strtotime($end_date);
  $user_ts = strtotime($date_from_user);

  // Check that user date is between start & end
  return (($user_ts >= $start_ts) && ($user_ts <= $end_ts));
}
ConroyP
sumber
1
Bekerja dengan baik. Terima kasih.
GeneCode
48

Gunakan kelas DateTime jika Anda memiliki PHP 5.3+. Lebih mudah digunakan, fungsionalitas lebih baik.

DateTime secara internal mendukung zona waktu, dengan solusi lain terserah Anda untuk menanganinya.

<?php    
/**
 * @param DateTime $date Date that is to be checked if it falls between $startDate and $endDate
 * @param DateTime $startDate Date should be after this date to return true
 * @param DateTime $endDate Date should be before this date to return true
 * return bool
 */
function isDateBetweenDates(DateTime $date, DateTime $startDate, DateTime $endDate) {
    return $date > $startDate && $date < $endDate;
}

$fromUser = new DateTime("2012-03-01");
$startDate = new DateTime("2012-02-01 00:00:00");
$endDate = new DateTime("2012-04-30 23:59:59");

echo isDateBetweenDates($fromUser, $startDate, $endDate);
penyihir tua
sumber
Anda mungkin akan mengubahnya menjadi fungsi yang mengambil tiga parameter, dan mengembalikan boolean. Haruskah sangat mudah untuk diuji?
oldwizard
Saya akan mengatakan bahwa fungsi harus mengembalikan nilai true for 2012-02-01is between 2012-02-01 ... 2014-04-30 23:59:59.
Salman A
2
Saya selalu menyukai DateTimefungsi waktu samar yang ditawarkan PHP out-of-the-box. Untuk memasukkan tanggal mulai dan berakhir dalam pemeriksaan ini, cukup ubah nilai pengembalian kereturn $date >= $startDate && $date <= $endDate;
zanderwar
@ zanderway, apakah Anda mengatakan> default untuk perbandingan "hari" dan bukan perbandingan detik? $ startDate memiliki detik yang ditentukan, jadi saya ingin tahu apakah "> =" benar-benar diperlukan?
PJ Brunet
46

Anda tidak perlu mengonversi ke stempel waktu untuk melakukan perbandingan, karena string divalidasi sebagai tanggal dalam format kanonis 'YYYY-MM-DD'.

Tes ini akan bekerja:

( ( $date_from_user >= $start_date ) && ( $date_from_user <= $end_date ) )

diberikan:

$start_date     = '2009-06-17';
$end_date       = '2009-09-05';
$date_from_user = '2009-08-28';

CATATAN: Membandingkan string seperti ini memungkinkan untuk tanggal "tidak valid" misalnya (32 Desember) '2009-13-32' dan untuk string yang diformat aneh '2009/3/3', sehingga perbandingan string TIDAK akan sama dengan perbandingan tanggal atau stempel waktu. Ini HANYA berfungsi jika nilai tanggal dalam string dalam format KONSISTEN dan CANONICAL .

EDIT untuk menambahkan catatan di sini, menguraikan yang sudah jelas.

Dengan CONSISTENT , maksud saya misalnya bahwa string yang dibandingkan harus dalam format yang identik: bulan harus selalu dua karakter, hari harus selalu dua karakter, dan karakter pemisah harus selalu berupa tanda hubung. Kami tidak dapat membandingkan "string" yang bukan empat tahun karakter, dua bulan karakter, dua hari karakter. Jika kami memiliki campuran satu karakter dan dua karakter bulan dalam string, misalnya, kami akan mendapatkan hasil yang tidak terduga saat kami membandingkan, '2009-9-30'dengan '2009-10-11'. Kita secara manusiawi melihat "9" sebagai kurang dari "10", tetapi perbandingan string akan melihat '2009-9'lebih besar dari '2009-1'. Kami tidak perlu memiliki karakter pemisah tanda hubung; kami juga bisa membandingkan string dengan andal'YYYYMMDD'format; jika ada karakter pemisah, itu harus selalu ada dan selalu sama.

Yang saya maksud dengan CANONICAL adalah format yang akan menghasilkan string yang akan diurutkan dalam urutan tanggal. Artinya, string akan memiliki representasi "tahun" terlebih dahulu, lalu "bulan", lalu "hari". Kami tidak dapat membandingkan string dalam 'MM-DD-YYYY'format dengan andal , karena itu tidak kanonik. Perbandingan string akan membandingkan MM(bulan) sebelum dibandingkan YYYY(tahun) karena perbandingan string bekerja dari kiri ke kanan.) Manfaat besar dari format string 'YYYY-MM-DD' adalah bahwa format itu kanonik; tanggal yang direpresentasikan dalam format ini dengan andal dapat dibandingkan sebagai string.

[TAMBAHAN]

Jika Anda melakukan konversi stempel waktu php, perhatikan batasannya.

Pada beberapa platform, php tidak mendukung nilai stempel waktu sebelum 01-01 1970 dan / atau lebih dari 2038-01-19. (Itulah sifat integer 32-bit timestamp unix.) Versi yang lebih baru pf php (5.3?) Seharusnya mengatasinya.

Zona waktu juga dapat menjadi masalah, jika Anda tidak berhati-hati menggunakan zona waktu yang sama saat mengonversi dari string ke stempel waktu dan dari stempel waktu kembali ke string.

HTH

spencer7593
sumber
1
Meskipun tanpa casting Anda bisa mengalami masalah jika nilai dari $ date_from_user, atau $ start_date, atau $ end_date bukan tanggal .. yaitu $ end_date = 'Balh Blah' .. pasti tidak akan berfungsi dengan benar
Mike Dinescu
@ spencer7593, apakah Anda memiliki beberapa referensi untuk perilaku ini?
Ionuț G. Stan
2
Anda dapat menggunakan checkdate () untuk memvalidasi
meleyal
Apakah ini sesuai dengan waktu? Maksud saya, saya punya dua kali dalam format HH: MM: SS dan saya ingin tahu apakah ada waktu di antara keduanya.
Andy Ibanez
1
@Sergio: ya, perbandingan string yang sama berfungsi untuk nilai waktu, selama string dalam format kanonik standar (yaitu jam 24 jam, tengah malam direpresentasikan sebagai '00: 00: 00 ', detik terakhir sebelum tengah malam direpresentasikan sebagai' 23:59:59 '. Untuk memastikan bahwa perbandingan string akan "berfungsi", Anda perlu menjamin bahwa representasi string dari nilai waktu dalam format yang dijamin.
spencer7593
4
$startDatedt = strtotime($start_date)
$endDatedt = strtotime($end_date)
$usrDatedt = strtotime($date_from_user)

if( $usrDatedt >= $startDatedt && $usrDatedt <= $endDatedt)
{
   //..falls within range
}
Stan R.
sumber
Itu tidak akan mencakup kecocokan persis dengan tanggal mulai atau tanggal akhir
TheTXI
OP tidak meminta pertandingan inklusif.
Jeremy Logan
3

Ubah kedua tanggal menjadi stempel waktu lalu lakukan

pseudocode:

if date_from_user > start_date && date_from_user < end_date
    return true
Lembah kecil
sumber
Anda mungkin ingin mengeditnya sehingga Anda juga menyertakan tanggal_mulai dan tanggal_akhir dalam rentang tersebut. Saat ini jika date_from_user sama dengan salah satunya, itu tidak akan dihitung.
TheTXI
OP tidak menentukan rentang inklusif atau eksklusif, jadi saya akan menyerahkan kepada mereka untuk memilih strategi mana yang akan digunakan
Glen
3

Dalam format yang Anda berikan, dengan asumsi pengguna cukup pintar untuk memberi Anda tanggal yang valid, Anda tidak perlu mengonversi ke tanggal terlebih dahulu, Anda dapat membandingkannya sebagai string.

richardtallent
sumber
1
Pada titik ini dalam kode tanggal telah divalidasi
meleyal
3
$start_date="17/02/2012";
$end_date="21/02/2012";
$date_from_user="19/02/2012";

function geraTimestamp($data)
{
    $partes = explode('/', $data); 
    return mktime(0, 0, 0, $partes[1], $partes[0], $partes[2]);
}


$startDatedt = geraTimestamp($start_date); 
$endDatedt = geraTimestamp($end_date);
$usrDatedt = geraTimestamp($date_from_user);

if (($usrDatedt >= $startDatedt) && ($usrDatedt <= $endDatedt))
{ 
    echo "Dentro";
}    
else
{
    echo "Fora";
}
Paulo Henrique
sumber
2

Ubah menjadi tanggal atau bilangan bulat stempel waktu dan kemudian periksa $ date_from_user adalah <= $ end_date dan> = $ start_date

TheTXI
sumber
3
Bisakah Anda menjelaskan 'ubah menjadi tanggal'? Bagaimana Anda melakukannya? Saya pikir PHP tidak memiliki tipe tanggal?
meleyal
2

Anda dapat mencoba ini:

//custom date for example
$d1 = new DateTime("2012-07-08");
$d2 = new DateTime("2012-07-11");
$d3 = new DateTime("2012-07-08");
$d4 = new DateTime("2012-07-15");

//create a date period object
$interval = new DateInterval('P1D');
$daterange = iterator_to_array(new DatePeriod($d1, $interval, $d2));
$daterange1 = iterator_to_array(new DatePeriod($d3, $interval, $d4));
array_map(function($v) use ($daterange1) { if(in_array($v, $daterange1)) print "Bingo!";}, $daterange);
Ilya
sumber
1
catatan versi: iterator_to_array()tersedia sejak PHP 5.1
Raptor
0

Saya menemukan metode ini yang paling mudah:

$start_date = '2009-06-17';
$end_date = '2009-09-05';
$date_from_user = '2009-08-28';

$start_date = date_create($start_date);
$date_from_user = date_create($date_from_user);
$end_date = date_create($end_date);

$interval1 = date_diff($start_date, $date_from_user);
$interval2 = date_diff($end_date, $date_from_user);

if($interval1->invert == 0){
  if($interval2->invert == 1){

     // if it lies between start date and end date execute this code

  }
}
iniravpatel.dll
sumber