¿Cómo comprobar si una fecha está en un rango determinado?

86

Si tiene un $start_datey $end_date, ¿cómo puede verificar si una fecha dada por el usuario se encuentra dentro de ese rango?

p.ej

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28'; 

En el momento en que las fechas son cadenas, ¿ayudaría convertirlas en números enteros de marca de tiempo?

leal
fuente
Sería útil, entonces tendrías acceso a cualquier función de manipulación de fechas que exista.
ChrisF
3
Solo tenga cuidado con la limitación de la marca de tiempo, ya que las marcas de tiempo de Unix comienzan en la época, que es el 1 de enero de 1970 (1970-01-01), por lo que podría tener un comportamiento
extraño
1
@Shadi Sabes que existen los números NEGATIVOS, ¿verdad?
Jeremy Logan
@fiXedd, sin embargo, existe el mismo problema básico: incluso si se permiten marcas de tiempo negativas, las marcas de tiempo de 32 bits no pueden representar fechas anteriores a 1902.
Frank Farmer

Respuestas:

122

Convertirlos en marcas de tiempo es el camino a seguir, usando strtotime , por ejemplo

$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
fuente
Funciona genial. Gracias.
GeneCode
47

Use la clase DateTime si tiene PHP 5.3+. Más fácil de usar, mejor funcionalidad.

DateTime admite internamente zonas horarias, con las otras soluciones depende de usted manejar eso.

<?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);
viejo mago
fuente
Es probable que transforme esto en una función que tome tres parámetros y devuelva un booleano. ¿Debería ser muy fácil de probar?
oldwizard
Yo diría que la función debería devolver verdadero porque 2012-02-01está entre 2012-02-01 ... 2014-04-30 23:59:59.
Salman A
2
Siempre prefiero DateTimelas funciones de tiempo incompletas que PHP ofrece listas para usar. Para incluir la fecha de inicio y finalización dentro de esta verificación, simplemente cambie el valor de retorno areturn $date >= $startDate && $date <= $endDate;
zanderwar
@zanderway, ¿estás diciendo que el> predeterminado es una comparación de "días" y no una comparación de segundos? $ startDate tiene segundos especificados, así que me pregunto si "> =" es realmente necesario.
PJ Brunet
46

No es necesario convertir a marca de tiempo para realizar la comparación, dado que las cadenas se validan como fechas en formato canónico 'AAAA-MM-DD'.

Esta prueba funcionará:

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

dado:

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

NOTA: La comparación de cadenas como esta permite fechas "no válidas", por ejemplo, (32 de diciembre) '2009-13-32' y cadenas con formato extraño '2009/3/3', de modo que una comparación de cadenas NO será equivalente a una comparación de fecha o marca de tiempo. Esto funciona SOLO si los valores de fecha en las cadenas están en formato CONSISTENTE y CANÓNICO .

EDITAR para agregar una nota aquí, elaborando lo obvio.

Por CONSISTENTE , quiero decir, por ejemplo, que las cadenas que se comparan deben tener un formato idéntico: el mes debe tener siempre dos caracteres, el día siempre debe tener dos caracteres y el carácter separador debe ser siempre un guión. No podemos comparar de forma fiable "cadenas" que no sean un año de cuatro caracteres, un mes de dos caracteres ni un día de dos caracteres. Si tuviéramos una mezcla de un carácter y dos meses de caracteres en las cadenas, por ejemplo, obtendríamos un resultado inesperado cuando comparamos '2009-9-30'con '2009-10-11'. Humanamente vemos "9" como menor que "10", pero una comparación de cadenas verá '2009-9'como mayor que '2009-1'. No es necesario que tengamos caracteres separadores de guiones; podríamos comparar cadenas de forma fiable en'YYYYMMDD'formato; si hay un carácter separador, debe estar siempre ahí y ser siempre el mismo.

Por CANÓNICO , me refiero a un formato que dará como resultado cadenas que se ordenarán por fecha. Es decir, la cadena tendrá una representación de "año" primero, luego "mes", luego "día". No podemos comparar cadenas en 'MM-DD-YYYY'formato de manera confiable , porque eso no es canónico. Una comparación de cadenas compararía el MM(mes) antes de compararlo YYYY(año), ya que la comparación de cadenas funciona de izquierda a derecha.) Un gran beneficio del formato de cadena 'AAAA-MM-DD' es que es canónico; las fechas representadas en este formato se pueden comparar de forma fiable como cadenas.

[APÉNDICE]

Si opta por la conversión de marca de tiempo php, tenga en cuenta las limitaciones.

En algunas plataformas, php no admite valores de marca de tiempo anteriores a 1970-01-01 y / o posteriores a 2038-01-19. (Esa es la naturaleza del entero de 32 bits de marca de tiempo de Unix.) Se supone que las versiones posteriores pf php (¿5.3?) Abordan eso.

La zona horaria también puede ser un problema, si no tiene cuidado de usar la misma zona horaria al convertir de cadena a marca de tiempo y de marca de tiempo a cadena.

HTH

spencer7593
fuente
1
Este es interesante.
Ionuț G. Stan
1
Aunque sin la conversión, podrías tener problemas si los valores de $ date_from_user, $ start_date o $ end_date no son fechas ... es decir, $ end_date = 'Balh Blah' ... definitivamente no funcionará correctamente
Mike Dinescu
@ spencer7593, ¿tiene algunas referencias para este comportamiento?
Ionuț G. Stan
2
Puede usar checkdate () para validar
meleyal
1
@Sergio: sí, la misma comparación de cadenas funciona para valores de tiempo, siempre que las cadenas estén en un formato canónico estándar (es decir, reloj de 24 horas, medianoche representado como '00: 00: 00 ', el último segundo antes de la medianoche representado como' 23:59:59 '. Para garantizar que la comparación de cadenas "funcione", debe garantizar que las representaciones de cadenas del valor de tiempo estén en un formato garantizado.
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.
fuente
Eso no incluirá coincidencias exactas con la fecha de inicio o la fecha de finalización
TheTXI
OP no pidió coincidencias inclusivas.
Jeremy Logan
3

Convierta ambas fechas en marcas de tiempo y luego haga

pseudocódigo:

if date_from_user > start_date && date_from_user < end_date
    return true
Cañada
fuente
Es posible que desee editarlo para que también incluya start_date y end_date en el rango. En este momento, si date_from_user es igual a cualquiera, no se contará.
TheTXI
El OP no especificó rangos inclusivos o exclusivos, así que dejaré que ellos elijan qué estrategia usar
Glen
3

En el formato que ha proporcionado, asumiendo que el usuario es lo suficientemente inteligente como para darle fechas válidas, no necesita convertir a una fecha primero, puede compararlas como cadenas.

richardtallent
fuente
1
En este punto del código, las fechas ya han sido validadas
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
fuente
2

Conviértelos en fechas o números enteros de marca de tiempo y luego simplemente verifique que $ date_from_user sea <= $ end_date y> = $ start_date

TheTXI
fuente
3
¿Podrías aclarar 'convertirlos en fechas'? ¿Cómo lo harías tú? Pensé que PHP no tiene tipo de fecha.
meleyal
2

Puedes probar esto:

//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
fuente
1
nota de la versión: iterator_to_array()está disponible desde PHP 5.1
Raptor
0

Encontré este método el más fácil:

$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
fuente