91

If you have a $start_date and $end_date, how can you check if a date given by the user falls within that range?

e.g.

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28'; 

At the moment the dates are strings, would it help to convert them to timestamp integers?

meleyal
  • 32,252
  • 24
  • 73
  • 79
  • It would help, then you'd have access to any date manipulation functions there are. – ChrisF Jun 10 '09 at 16:22
  • 3
    Just becarefull with the timestamp limitation as Unix timestamps start at the epoch, which is January 1, 1970 (1970-01-01), so you could have funny behaviour for testing dates before 1970. – Shadi Almosri Jun 10 '09 at 16:26
  • 1
    @Shadi You know there's such thing as NEGATIVE numbers, right? – Jeremy Logan Jun 11 '09 at 06:33
  • @fiXedd the same basic problem exists though -- even allowing negative timestamps, 32 bit timestamps cannot represent dates before 1902. – Frank Farmer Dec 12 '12 at 19:08

10 Answers10

132

Converting them to timestamps is the way to go alright, using strtotime, e.g.

$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
  • 40,958
  • 16
  • 80
  • 86
55

Use the DateTime class if you have PHP 5.3+. Easier to use, better functionality.

DateTime internally supports timezones, with the other solutions is up to you to handle that.

<?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);
oldwizard
  • 5,012
  • 2
  • 31
  • 32
  • You would likely transform this into a function that takes three parameters, and return a boolean. Should be very easy to test? – oldwizard Apr 28 '15 at 05:28
  • I would say that the function should return true for `2012-02-01` is between `2012-02-01 ... 2014-04-30 23:59:59`. – Salman A May 15 '15 at 10:07
  • 4
    I always favor `DateTime` over the sketchy time functions that PHP offers out-of-the-box. To include start and end date within this check very simply change the return value to `return $date >= $startDate && $date <= $endDate;` – zanderwar Sep 27 '16 at 02:46
  • @zanderway are you saying the > defaults to a "day" comparison and not a seconds comparison? $startDate has seconds specified, so I'm wondering if the ">=" is really necessary? – PJ Brunet Nov 25 '19 at 22:12
47

It's not necessary to convert to timestamp to do the comparison, given that the strings are validated as dates in 'YYYY-MM-DD' canonical format.

This test will work:

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

given:

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

NOTE: Comparing strings like this does allow for "non-valid" dates e.g. (December 32nd ) '2009-13-32' and for weirdly formatted strings '2009/3/3', such that a string comparison will NOT be equivalent to a date or timestamp comparison. This works ONLY if the date values in the strings are in a CONSISTENT and CANONICAL format.

EDIT to add a note here, elaborating on the obvious.

By CONSISTENT, I mean for example that the strings being compared must be in identical format: the month must always be two characters, the day must always be two characters, and the separator character must always be a dash. We can't reliably compare "strings" that aren't four character year, two character month, two character day. If we had a mix of one character and two character months in the strings, for example, we'd get unexpected result when we compared, '2009-9-30' to '2009-10-11'. We humanly see "9" as being less than "10", but a string comparison will see '2009-9' as greater than '2009-1'. We don't necessarily need to have a dash separator characters; we could just as reliably compare strings in 'YYYYMMDD' format; if there is a separator character, it has to always be there and always be the same.

By CANONICAL, I mean that a format that will result in strings that will be sorted in date order. That is, the string will have a representation of "year" first, then "month", then "day". We can't reliably compare strings in 'MM-DD-YYYY' format, because that's not canonical. A string comparison would compare the MM (month) before it compared YYYY (year) since the string comparison works from left to right.) A big benefit of the 'YYYY-MM-DD' string format is that it is canonical; dates represented in this format can reliably be compared as strings.

[ADDENDUM]

If you do go for the php timestamp conversion, be aware of the limitations.

On some platforms, php does not support timestamp values earlier than 1970-01-01 and/or later than 2038-01-19. (That's the nature of the unix timestamp 32-bit integer.) Later versions pf php (5.3?) are supposed to address that.

The timezone can also be an issue, if you aren't careful to use the same timezone when converting from string to timestamp and from timestamp back to string.

HTH

spencer7593
  • 106,611
  • 15
  • 112
  • 140
  • 1
    Although without casting you could run into problems if the values of the $date_from_user, or $start_date, or $end_date are not dates.. i.e. $end_date = 'Balh Blah'.. will definitely not work correctly – Mike Dinescu Jun 10 '09 at 16:29
  • @spencer7593, do you have some references for this behavior? – Ionuț G. Stan Jun 10 '09 at 16:35
  • 2
    You could use checkdate() to validate – meleyal Jun 10 '09 at 17:08
  • Does this work with time? I mean, I have two times in HH:MM:SS format and I want to know if any given time is between these two. – Andy Ibanez Jun 11 '12 at 05:03
  • 1
    @Sergio: yes, the same string comparison works for time values, as long as the strings are in a standard canonical format (i.e. 24 hour clock, midnight represented as '00:00:00', the last second before midnight represented as '23:59:59'. To be guaranteed that the string comparison will "work", you need to guarantee that the string representations of the time value are in a guaranteed format. – spencer7593 Jun 12 '12 at 14:04
4
$startDatedt = strtotime($start_date)
$endDatedt = strtotime($end_date)
$usrDatedt = strtotime($date_from_user)

if( $usrDatedt >= $startDatedt && $usrDatedt <= $endDatedt)
{
   //..falls within range
}
Stan R.
  • 15,757
  • 4
  • 50
  • 58
3

Convert both dates to timestamps then do

pseudocode:

if date_from_user > start_date && date_from_user < end_date
    return true
Glen
  • 21,816
  • 3
  • 61
  • 76
  • You might want to edit it so that you also include start_date and end_date in the range. Right now if date_from_user equals either, it will not be counted. – TheTXI Jun 10 '09 at 16:24
  • The OP didn't specify inclusive or exclusive ranges, so I'll leave it up to them to pick which strategy to use – Glen Jun 10 '09 at 16:27
3

In the format you've provided, assuming the user is smart enough to give you valid dates, you don't need to convert to a date first, you can compare them as strings.

richardtallent
  • 34,724
  • 14
  • 83
  • 123
2

You can try this:

//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
  • 68
  • 9
2
$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";
}
hakre
  • 193,403
  • 52
  • 435
  • 836
2

Convert them into dates or timestamp integers and then just check of $date_from_user is <= $end_date and >= $start_date

TheTXI
  • 37,429
  • 10
  • 86
  • 110
  • 3
    Could you clarify 'convert them into dates'? How would you do that? I thought PHP has no date type? – meleyal Jun 10 '09 at 16:25
0

I found this method the easiest:

$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
  • 1,553
  • 16
  • 24