Как проверить, находится ли дата в заданном диапазоне?

86

Если у вас есть $start_dateи $end_date, как вы можете проверить, попадает ли указанная пользователем дата в этот диапазон?

например

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28'; 

На данный момент даты представляют собой строки, поможет ли преобразовать их в целые числа с отметками времени?

мелея
источник
Это поможет, тогда у вас будет доступ к любым функциям манипулирования датами.
ChrisF
3
Просто будьте внимательны с ограничением временных меток, так как временные метки Unix начинаются с эпохи, то есть 1 января 1970 года (1970-01-01), так что у вас может быть забавное поведение для дат тестирования до 1970 года.
Шади Альмосри
1
@Shadi Ты ведь знаешь, что есть ОТРИЦАТЕЛЬНЫЕ числа, верно?
Джереми Логан,
@fiXedd, хотя существует та же основная проблема - даже с учетом отрицательных меток времени, 32-битные метки времени не могут представлять даты до 1902 года.
Фрэнк Фармер

Ответы:

122

Преобразование их в метки времени - это хороший способ, используя strtotime , например

$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
источник
Работает отлично. Спасибо.
GeneCode 07
47

Используйте класс DateTime, если у вас PHP 5.3+. Легче в использовании, лучше функциональность.

DateTime внутренне поддерживает часовые пояса, другие решения должны решать вам.

<?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
Я бы сказал, что функция должна возвращать истину, если 2012-02-01находится между ними 2012-02-01 ... 2014-04-30 23:59:59.
Салман А
2
Я всегда предпочитаю DateTimeотрывочные функции времени, которые PHP предлагает «из коробки». Чтобы включить дату начала и окончания в эту проверку, очень просто измените возвращаемое значение наreturn $date >= $startDate && $date <= $endDate;
zanderwar
@zanderway, вы говорите, что> по умолчанию используется "дневное" сравнение, а не сравнение секунд? В $ startDate указаны секунды, поэтому мне интересно, действительно ли нужен "> ="?
PJ Brunet
46

Для сравнения нет необходимости преобразовывать во временную метку, поскольку строки проверяются как даты в каноническом формате «ГГГГ-ММ-ДД».

Этот тест будет работать:

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

дано:

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

ПРИМЕЧАНИЕ. Сравнение строк, подобных этой, позволяет использовать «недействительные» даты, например (32 декабря) «2009-13-32» и для странно отформатированных строк «2009/3/3», так что сравнение строк НЕ будет эквивалентно сравнение даты или времени. Это работает ТОЛЬКО, если значения даты в строках находятся в СООТВЕТСТВИИ и КАНОНИЧЕСКОМ формате.

ИЗМЕНИТЬ, чтобы добавить сюда примечание, уточняя очевидное.

Под СОГЛАСОВАННЫМ я подразумеваю, например, что сравниваемые строки должны быть в одинаковом формате: месяц всегда должен состоять из двух символов, день всегда должен состоять из двух символов, а символ-разделитель всегда должен быть тире. Мы не можем надежно сравнить «строки», которые не являются четырехзначным годом, двухсимвольным месяцем и двухсимвольным днем. Если бы у нас было сочетание одного символа и двух символов месяца в строках, например, мы получили бы неожиданный результат при сравнении '2009-9-30'с '2009-10-11'. По-человечески мы видим, что «9» меньше «10», но при сравнении строк будет видно, '2009-9'что оно больше '2009-1'. Нам не обязательно иметь символы-разделители тире; мы могли так же надежно сравнивать строки в'YYYYMMDD'формат; если есть символ-разделитель, он должен быть всегда и всегда одинаков.

Под CANONICAL я имею в виду формат, в результате которого строки будут отсортированы по дате. То есть в строке сначала будет отображаться «год», затем «месяц», затем «день». Мы не можем надежно сравнивать строки в 'MM-DD-YYYY'формате, потому что это не канонично. При сравнении строк сравнивается MM(месяц) до сравнения YYYY(год), поскольку сравнение строк выполняется слева направо.) Большое преимущество строкового формата «ГГГГ-ММ-ДД» состоит в том, что он является каноническим; даты, представленные в этом формате, можно надежно сравнивать как строки.

[ДОБАВЛЕНИЕ]

Если вы все же перейдете на преобразование метки времени php, помните об ограничениях.

На некоторых платформах php не поддерживает значения отметок времени до 01.01.1970 и / или позже 19.01.2038. (Такова природа 32-битного целого числа временной метки unix.) Более поздние версии pf php (5.3?) Должны решить эту проблему.

Часовой пояс также может быть проблемой, если вы не используете один и тот же часовой пояс при преобразовании из строки в метку времени и из метки времени обратно в строку.

HTH

spencer7593
источник
1
Это интересно.
Ionuț G. Stan
1
Хотя без преобразования вы можете столкнуться с проблемами, если значения $ date_from_user, $ start_date или $ end_date не являются датами .. т.е. $ end_date = 'Balh Blah' .. определенно не будет работать правильно
Майк Динеску
@ spencer7593, у вас есть ссылки на такое поведение?
Ionuț G. Stan
2
Вы можете использовать checkdate () для проверки
meleyal
1
@Sergio: да, то же сравнение строк работает для значений времени, если строки находятся в стандартном каноническом формате (т.е. 24-часовой формат, полночь представлена ​​как '00: 00: 00 ', последняя секунда перед полуночью представлена ​​как' 23:59:59 '. Чтобы гарантировать, что сравнение строк будет «работать», вам необходимо гарантировать, что строковые представления значения времени находятся в гарантированном формате.
spencer7593
4
$startDatedt = strtotime($start_date)
$endDatedt = strtotime($end_date)
$usrDatedt = strtotime($date_from_user)

if( $usrDatedt >= $startDatedt && $usrDatedt <= $endDatedt)
{
   //..falls within range
}
Стэн Р.
источник
Это не будет включать никаких точных совпадений с датой начала или даты окончания
TheTXI
OP не запрашивал инклюзивные совпадения.
Джереми Логан,
3

Преобразуйте обе даты в метки времени, затем выполните

псевдокод:

if date_from_user > start_date && date_from_user < end_date
    return true
Glen
источник
Возможно, вы захотите отредактировать его, включив в диапазон также start_date и end_date. Прямо сейчас, если date_from_user равно ни одному, это не будет засчитано.
TheTXI
В OP не указаны включающие или эксклюзивные диапазоны, поэтому я оставлю им самим выбирать, какую стратегию использовать
Глен
3

В указанном вами формате при условии, что пользователь достаточно умен, чтобы дать вам действительные даты, вам не нужно сначала преобразовывать дату в дату, вы можете сравнить их как строки.

Ричардталлент
источник
1
К этому моменту в коде даты уже были подтверждены
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

Преобразуйте их в даты или целые числа отметок времени, а затем просто проверьте, что $ date_from_user равно <= $ end_date и> = $ start_date

TheTXI
источник
3
Не могли бы вы пояснить «преобразовать их в даты»? Как бы Вы это сделали? Я думал, что в PHP нет типа даты?
meleyal
2

Вы можете попробовать это:

//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
примечание к версии: iterator_to_array()доступно, начиная с PHP 5.1
Raptor
0

Я нашел этот способ самым простым:

$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

  }
}
Иниравпател
источник