Come verificare se una data è in un determinato intervallo?


86

Se hai una $start_datee $end_date, come puoi verificare se una data fornita dall'utente rientra in tale intervallo?

per esempio

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28'; 

Al momento le date sono stringhe, sarebbe utile convertirle in interi di timestamp?


Sarebbe utile, quindi avresti accesso a tutte le funzioni di manipolazione della data disponibili.
ChrisF

3
Basta essere attenti alla limitazione del timestamp poiché i timestamp di Unix iniziano all'epoca, che è il 1 gennaio 1970 (1970-01-01), quindi potresti avere un comportamento divertente per le date di test prima del 1970.
Shadi Almosri

1
@ Shadi Sai che esistono numeri NEGATIVI, giusto?
Jeremy Logan,

@fiXedd esiste lo stesso problema di base - anche consentendo timestamp negativi, timestamp a 32 bit non possono rappresentare date prima del 1902.
Frank Farmer

Risposte:


123

Convertirli in timestamp è la strada giusta, usando strtotime , ad es

$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));
}

1
Funziona alla grande. Grazie.
GeneCode

48

Usa la classe DateTime se hai PHP 5.3+. Più facile da usare, migliore funzionalità.

DateTime supporta internamente i fusi orari, con le altre soluzioni sta a te gestirlo.

<?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);

Probabilmente lo trasformeresti in una funzione che accetta tre parametri e restituirà un valore booleano. Dovrebbe essere molto facile da testare?
oldwizard

Direi che la funzione dovrebbe restituire true per 2012-02-01is between 2012-02-01 ... 2014-04-30 23:59:59.
Salman A

2
Prediligo sempre DateTimele funzioni temporali imprecise che PHP offre immediatamente. Per includere la data di inizio e di fine in questo controllo, è sufficiente modificare il valore restituito inreturn $date >= $startDate && $date <= $endDate;
zanderwar,

@zanderway stai dicendo che il> valore predefinito è un confronto "giornaliero" e non un confronto dei secondi? $ startDate ha dei secondi specificati, quindi mi chiedo se "> =" sia davvero necessario?
PJ Brunet

46

Non è necessario convertire in timestamp per fare il confronto, dato che le stringhe sono convalidate come date nel formato canonico "AAAA-MM-GG".

Questo test funzionerà:

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

dato:

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

NOTA: il confronto di stringhe come questo consente date "non valide" ad es. (32 dicembre) '2009-13-32' e stringhe stranamente formattate '2009/3/3', in modo tale che un confronto di stringhe NON sarà equivalente a una data o un confronto timestamp. Funziona SOLO se i valori di data nelle stringhe sono in un formato COSTANTE e CANONICO .

MODIFICA per aggiungere una nota qui, elaborando l'ovvio.

Per COERENTE intendo ad esempio che le stringhe da confrontare devono essere in formato identico: il mese deve essere sempre di due caratteri, il giorno deve essere sempre di due caratteri e il carattere separatore deve essere sempre un trattino. Non possiamo confrontare in modo affidabile "stringhe" che non sono quattro caratteri anno, due caratteri mese, due caratteri giorno. Se avessimo un mix di un carattere e due mesi di carattere nelle stringhe, ad esempio, otterremmo risultati inaspettati rispetto '2009-9-30'a '2009-10-11'. Umanamente vediamo "9" come minore di "10", ma un confronto tra stringhe vedrà '2009-9'come maggiore di '2009-1'. Non abbiamo necessariamente bisogno di avere un carattere separatore di trattini; potremmo confrontare in modo altrettanto affidabile le stringhe in'YYYYMMDD'formato; se c'è un carattere separatore, deve essere sempre lì ed essere sempre lo stesso.

Per CANONICO , intendo un formato che si tradurrà in stringhe che verranno ordinate in ordine di data. Cioè, la stringa avrà prima una rappresentazione di "anno", poi "mese", quindi "giorno". Non possiamo confrontare in modo affidabile le stringhe nel 'MM-DD-YYYY'formato, perché non è canonico. Un confronto di stringhe confronta il MM(mese) prima di confrontare YYYY(anno) poiché il confronto di stringhe funziona da sinistra a destra.) Un grande vantaggio del formato di stringa "AAAA-MM-GG" è che è canonico; le date rappresentate in questo formato possono essere confrontate in modo affidabile come stringhe.

[ADDENDUM]

Se scegli la conversione del timestamp php, sii consapevole dei limiti.

Su alcune piattaforme, php non supporta i valori di timestamp precedenti a 1970-01-01 e / o successivi a 2038-01-19. (Questa è la natura dell'intero unix timestamp a 32 bit.) Le versioni successive pf php (5.3?) Dovrebbero affrontare questo problema.

Anche il fuso orario può essere un problema, se non stai attento a utilizzare lo stesso fuso orario durante la conversione da stringa a timestamp e da timestamp a stringa.

HTH


1
Anche se senza casting potresti incorrere in problemi se i valori di $ date_from_user, o $ start_date o $ end_date non sono date .. cioè $ end_date = 'Balh Blah' .. sicuramente non funzionerà correttamente
Mike Dinescu

@ spencer7593, hai qualche riferimento per questo comportamento?
Ionuț G. Stan il

2
È possibile utilizzare checkdate () per convalidare
meleyal

Funziona con il tempo? Voglio dire, ho due volte in formato HH: MM: SS e voglio sapere se un dato tempo è tra questi due.
Andy Ibanez,

1
@Sergio: sì, lo stesso confronto di stringhe funziona per i valori di tempo, purché le stringhe siano in un formato canonico standard (ad es. Orologio a 24 ore, mezzanotte rappresentata come '00: 00: 00 ', l'ultimo secondo prima di mezzanotte rappresentato come' 23:59:59 '. Per garantire che il confronto tra stringhe "funzioni", è necessario garantire che le rappresentazioni di stringa del valore temporale siano in un formato garantito.
spencer7593

4
$startDatedt = strtotime($start_date)
$endDatedt = strtotime($end_date)
$usrDatedt = strtotime($date_from_user)

if( $usrDatedt >= $startDatedt && $usrDatedt <= $endDatedt)
{
   //..falls within range
}

Ciò non includerà alcuna corrispondenza esatta con la data di inizio o di fine
TheTXI

OP non ha chiesto corrispondenze inclusive.
Jeremy Logan,

3

Converti entrambe le date in timestamp, quindi fallo

pseudocodice:

if date_from_user > start_date && date_from_user < end_date
    return true

Potresti volerlo modificare in modo da includere anche start_date e end_date nell'intervallo. In questo momento, se date_from_user è uguale a entrambi, non verrà conteggiato.
TheTXI

L'OP non ha specificato intervalli inclusivi o esclusivi, quindi lascio a loro la scelta della strategia da utilizzare
Glen

3

Nel formato che hai fornito, supponendo che l'utente sia abbastanza intelligente da darti date valide, non devi prima convertirle in una data, puoi confrontarle come stringhe.


1
A questo punto nel codice le date sono già state convalidate
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";
}

2

Convertirli in date o numeri interi di timestamp e quindi controllare che $ date_from_user sia <= $ end_date e> = $ start_date


3
Potresti chiarire "convertirli in date"? Come lo faresti? Pensavo che PHP non avesse un tipo di data?
corpo a corpo il

2

Puoi provare questo:

//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);

1
nota sulla versione: iterator_to_array()è disponibile da PHP 5.1
Raptor

0

Ho trovato questo metodo il più semplice:

$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

  }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.