Як перевірити, чи є дата в заданому діапазоні?


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 року (01.01.1970), щоб ви могли мати смішну поведінку для тестування дат до 1970 року.
Шаді Альмосрі,

1
@Shadi Ви знаєте, що існує таке поняття, як НЕГАТИВНІ цифри, так?
Джеремі Логан,

@fiXedd та ж сама основна проблема існує , хоча - навіть з урахуванням негативних оцінок часу, 32 - бітні тимчасові мітки не можуть представляти дати до 1902.
Frank Farmer

Відповіді:


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

Чудово працює. Дякую.
GeneCode

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

Я б сказав, що функція повинна повертати true для 2012-02-01is between 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', так що порівняння рядків НЕ буде еквівалентно порівняння дати або позначки часу. Це працює ТІЛЬКИ, якщо значення дат у рядках мають формат CONSISTENT та CANONICAL .

РЕДАКТУЙ, щоб додати тут примітку, деталізуючи очевидне.

Під CONSISTENT я маю на увазі, наприклад, що рядки, що порівнюються, мають бути в однаковому форматі: місяць завжди повинен мати два символи, день завжди повинен бути двома символами, а символ розділювача - завжди тире. Ми не можемо достовірно порівняти "рядки", які не складаються з чотирьох символів року, двох символів місяця, дня двох символів. Наприклад, якби ми мали в поєднанні один символ і два символьні місяці в рядках, ми б отримали несподіваний результат, порівнявши, '2009-9-30'з '2009-10-11'. Ми по-людськи бачимо, що "9" менше, ніж "10", але порівняння рядків буде бачити '2009-9'більше '2009-1'. Нам не обов’язково мати символи розділювача тире; ми могли б так само надійно порівнювати рядки в'YYYYMMDD'формат; якщо є символ-роздільник, він завжди повинен бути там і завжди бути однаковим.

Під CANONICAL я маю на увазі, що формат, який призведе до рядків, які будуть відсортовані в порядку дати. Тобто, рядок буде мати представлення спочатку "рік", потім "місяць", потім "день". Ми не можемо надійно порівняти рядки у 'MM-DD-YYYY'форматі, оскільки це не канонічно. Порівняння рядків може порівняти MM(місяць) до порівняння YYYY(рік), оскільки порівняння рядків працює зліва направо.) Великою перевагою формату рядка 'РРРР-ММ-ДД' є те, що він є канонічним; дати, представлені в цьому форматі, можна надійно порівняти як рядки.

[ДОДАТОК]

Якщо ви все ж підете на конвертацію мітки часу php, пам’ятайте про обмеження.

На деяких платформах php не підтримує значення міток часу раніше 1970-01-01 та / або пізніше 2038-01-19. (Це характер 32-розрядного цілого числа unix мітки часу.) Пізніші версії pf php (5.3?) Мають вирішити цю проблему.

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

HTH


1
Цей цікавий.
Ionuț G. Stan

1
Хоча без кастингу ви можете зіткнутися з проблемами, якщо значення $ date_from_user, або $ start_date, або $ end_date не є датами .. тобто $ end_date = 'Balh Blah' .. точно не буде працювати належним чином
Mike Dinescu

@ 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

Можливо, ви захочете відредагувати його, щоб ви також включили в діапазон дату_початку і дату_закінчення. Зараз, якщо date_from_user дорівнює будь-якому, це не буде враховано.
TheTXI

В ОП не вказано інклюзивного чи ексклюзивного діапазонів, тому я залишаю за ними вибір, яку стратегію використовувати
Глен

3

У форматі, який ви надали, припускаючи, що користувач достатньо розумний, щоб дати вам дійсні дати, вам не потрібно спочатку перетворювати на дату, ви можете порівняти їх як рядки.


1
На цей момент у коді дати вже підтверджені
мелеял

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


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

  }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.