如何检查日期是否在给定范围内?

91

如果你有一个 $start_date$end_date,那么如何检查用户提供的日期是否在该范围内?

例如:

$start_date = '2009-06-17';

$end_date = '2009-09-05';

$date_from_user = '2009-08-28'; 

目前日期是字符串,将它们转换为时间戳整数有帮助吗?


这会很有帮助,因为你将能够使用任何日期操作函数。 - ChrisF
3
请注意时间戳的限制,因为Unix时间戳从纪元开始,即1970年1月1日(1970-01-01),所以在测试1970年之前的日期时可能会出现奇怪的行为。请小心处理。 - Shadi Almosri
1
@Shadi 你知道有负数这个概念吗? - Jeremy Logan
@fiXedd,同样的基本问题仍然存在——即使允许负时间戳,32位时间戳也无法表示1902年之前的日期。 - Frank Farmer
10个回答

133

将它们转换为时间戳是正确的方法,使用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));
}

55

如果你使用的是PHP 5.3+,建议使用DateTime类,它更易用、功能更强大。

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-012012-02-01 ... 2014-04-30 23:59:59之间。 - Salman A
4
我通常更喜欢使用 DateTime,而不是 PHP 提供的不够可靠的时间函数。如果要在检查中包含开始和结束日期,只需简单地更改返回值为 return $date >= $startDate && $date <= $endDate; - zanderwar
@zanderway 你是说 ">" 默认是按照 "天" 而不是 "秒" 进行比较吗?$startDate 指定了秒数,所以我想知道 ">=" 是否真的有必要? - PJ Brunet

47
不必将其转换为时间戳进行比较,因为字符串已验证为以'YYYY-MM-DD'规范格式表示的日期。
以下测试将起作用:
( ( $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';
注意:像这样比较字符串确实允许“非有效”的日期,例如(12月32日)“2009-13-32”和格式奇怪的字符串“2009/3/3”,因此字符串比较将不等同于日期或时间戳比较。这仅在字符串中的日期值以一致的规范的格式表示时才有效。
编辑添加一个注释,详细说明明显的内容。
通过一致性,我的意思是例如被比较的字符串必须具有相同的格式:月份必须始终为两个字符,日期必须始终为两个字符,并且分隔符字符必须始终为短划线。我们无法可靠地比较不是四个字符年份,两个字符月份,两个字符日期的“字符串”。例如,如果字符串中混合了一个字符和两个字符的月份,则在比较'2009-9-30''2009-10-11'时将得到意外结果。我们人为看到“9”小于“10”,但字符串比较会将'2009-9'视为大于'2009-1'。我们不一定需要短划线分隔符字符;我们可以使用'YYYYMMDD'格式可靠地比较字符串;如果存在分隔符字符,则必须始终存在并且始终相同。
通过规范性,我的意思是格式将导致日期顺序排序的字符串。也就是说,该字符串将先表示“年”,然后表示“月”,然后表示“日”。我们无法可靠地比较'MM-DD-YYYY'格式的字符串,因为这不是规范的。由于字符串比较从左到右工作,因此字符串比较会在比较MM(月份)之前比较YYYY(年份)。 “YYYY-MM-DD”字符串格式的一个很大的好处是它是规范的;以此格式表示的日期可以可靠地作为字符串进行比较。
[补充]
如果你选择php时间戳转换,请注意它的限制。
在某些平台上,php不支持早于1970-01-01和/或晚于2038-01-19的时间戳值。(这是unix时间戳32位整数的本质。)更高版本的php(5.3?)应该解决了这个问题。
时区也可能是一个问题,如果在从字符串转换为时间戳和从时间戳返回字符串时不小心使用不同的时区。

1
尽管没有进行强制转换,但如果$date_from_user、$start_date或$end_date的值不是日期,就可能会遇到问题。例如,$end_date = 'Balh Blah',肯定无法正常工作。 - Mike Dinescu
@spencer7593,你有这种行为的参考资料吗? - Ionuț G. Stan
2
你可以使用checkdate()来进行验证。 - meleyal
这个适用于时间吗?我的意思是,我有两个以HH:MM:SS格式表示的时间,我想知道任何给定的时间是否在这两个时间之间。 - Andy Ibanez
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 没有要求包含匹配。 - Jeremy Logan

3
将两个日期都转换为时间戳,然后按照以下伪代码进行操作:
if date_from_user > start_date && date_from_user < end_date
    return true

你可能想要编辑它,以便在范围内也包括start_date和end_date。现在,如果date_from_user等于其中任何一个,它将不会被计算。 - TheTXI
该OP没有指定包含或不包含范围,因此我将让他们选择使用哪种策略。 - Glen

3

在您提供的格式中,假设用户足够聪明以提供有效日期,您无需先将其转换为日期,可以将它们作为字符串进行比较。


1
到了代码的这一点,日期已经被验证过了。 - 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

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

2
将它们转换为日期或时间戳整数,然后只需检查 $date_from_user 是否小于等于 $end_date 并且大于等于 $start_date。请保留 HTML 标签。

3
你能解释一下“将它们转换成日期”的意思吗?你会如何做到这一点?我以为 PHP 没有日期类型? - meleyal

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

  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接