PHP:返回两个日期之间的所有日期数组

295

期望输入:

getDatesFromRange( '2010-10-01', '2010-10-05' );

期望输出:

Array( '2010-10-01', '2010-10-02', '2010-10-03', '2010-10-04', '2010-10-05' )
26个回答

1

我喜欢简洁的一行代码!

我今天发现的 PHP 技巧是,array_push() 函数会返回数组中新元素的数量。

我成功地在一个空的 while 循环的两个条件语句中检查了结束日期匹配、增加了 $x 的值,并且添加了新的元素。

function getDatesFromRange($a,$b,$x=0,$dates=[]){
    while(end($dates)!=$b && $x=array_push($dates,date("Y-m-d",strtotime("$a +$x day"))));
    return $dates;
}
var_export(getDatesFromRange('2010-10-01','2010-10-05'));

这个页面上最类似于我的函数的是drolex的(如果你相信我,直到我写完自己的代码后才发现)。我对大大小小的日期范围进行了一些速度测试,它们似乎同样表现出色,所以我认为它们的表现相当。以下是一些其他比较:
- 我们都使用date()、strtotime()和两个数组函数。 - Drolex只使用三个变量,而我使用相同的三个加上$x。 - 因为将开始日期加载到$date数组中对于我的函数来说并不是必要的,所以我可以在函数参数中声明它,并省去这行代码(同样适用于$x)。
**只有几个重要的注意事项:
1- 在将日期字符串输入函数之前,必须验证它们是否有效。
2- 上述函数只能处理向前移动的日期范围。如果您想处理向后移动的日期范围,请在函数调用中反转日期顺序并在$x=后添加一个负号。 (相当聪明,对吧?)
function getDatesFromRange($a,$b,$x=0,$dates=[]){
    while(end($dates)!=$b && $x=-array_push($dates,date("Y-m-d",strtotime("$a +$x day"))));
    return $dates;
}
var_export(getDatesFromRange('2010-10-05','2010-10-01'));

再增加一个扩展/考虑...

假设你有一个多元文化(或者松散的)用户群体,并且你的函数必须能够接收不同有效格式的开始和结束日期,并且你需要能够以任何有效格式输出数组?通过小的调整,我提供了一个解决方案。

所谓“有效”,指的是 YYYY-MM-DDMM/DD/YYYDD-MM-YYYY,这些是全球广泛使用的标准。如果需要另一种格式,则可用性将取决于 strtotime 的理解。

这里是演示

代码:

function getDatesFromRange($a,$b,$format='Y-m-d',$dates=[],$x=0){
    while(date($format,strtotime(end($dates)))!=date($format,strtotime($b)) && $x=array_push($dates,date($format,strtotime("$a +$x day"))));
    return $dates;
}

$formats=array("Computer"=>'Y-m-d',"American"=>'m/d/Y','Non-American'=>'d-m-Y');
$start='15-02-2017';    // Non-American formatted start date
$end='2017-02-27';  // Computer formatted start date
foreach($formats as $label=>$format){
    echo "<br>$label<br>";
    var_export(getDatesFromRange($start,$end,$format));
    echo "<br>";
}

输出

Computer
array ( 0 => '2017-02-15', 1 => '2017-02-16', 2 => '2017-02-17', 3 => '2017-02-18',
        4 => '2017-02-19', 5 => '2017-02-20', 6 => '2017-02-21', 7 => '2017-02-22',
        8 => '2017-02-23', 9 => '2017-02-24', 10 => '2017-02-25', 11 => '2017-02-26',
        12 => '2017-02-27', )

American
array ( 0 => '02/15/2017', 1 => '02/16/2017', 2 => '02/17/2017', 3 => '02/18/2017',
        4 => '02/19/2017', 5 => '02/20/2017', 6 => '02/21/2017', 7 => '02/22/2017',
        8 => '02/23/2017', 9 => '02/24/2017', 10 => '02/25/2017', 11 => '02/26/2017',
        12 => '02/27/2017', )

Non-American
array ( 0 => '15-02-2017', 1 => '16-02-2017', 2 => '17-02-2017', 3 => '18-02-2017',
        4 => '19-02-2017', 5 => '20-02-2017', 6 => '21-02-2017', 7 => '22-02-2017',
        8 => '23-02-2017', 9 => '24-02-2017', 10 => '25-02-2017', 11 => '26-02-2017',
        12 => '27-02-2017', )

现在有些人不完全信任strtotime()函数,因为它存在一些错误的行为。我曾经读过它会在尝试从闰日跳过一个月时出错。然而,除非有人能够重现这个问题来证明我是错的,否则只要你每次递增一天,strtotime()函数就永远不会让你失望。


上帝保佑文档清晰的答案。+1 - Sergio A.
这对我来说更像是一个学术挑战。我无法想象在生产代码中使用这种技术。如果你认真对待项目,我建议使用datetime对象。 - mickmackusa
好的,我确实很感激你的努力。为你鼓掌。@mickmackusa - Sergio A.

0
function datesbetween ($date1,$date2)
{
    $dates= array();
    for ($i = $date1
       ; $i<= $date1
       ; $i=date_add($i, date_interval_create_from_date_string('1 days')) ) 
    {            
       $dates[] = clone $i;
    }
    return $dates;
}

我认为这是最简单的方法。 - figuitiko
1
请解释一下你的答案是如何解决问题的,这将有助于每个人更清楚地理解你的解决方案并为将来的参考留下记录。 - Aziz

0
public static function countDays($date1,$date2)
{
    $date1 = strtotime($date1); // or your date as well
    $date2 = strtotime($date2);
    $datediff = $date1 - $date2;
    return floor($datediff/(60*60*24));
}

public static function dateRange($date1,$date2)
{
    $count = static::countDays($date1,$date2) + 1;
    $dates = array();
    for($i=0;$i<$count;$i++)
    {
        $dates[] = date("Y-m-d",strtotime($date2.'+'.$i.' days'));
    }
    return $dates;
}

-2
为了让Mostafa的回答更完整,这绝对是最简单和最有效的方法:
function getDatesFromRange($start_date, $end_date, $date_format = 'Y-m-d')
   {
      $dates_array = array();
      for ($x = strtotime($start_date); $x <= strtotime($end_date); $x += 86400) {
         array_push($dates_array, date($date_format, $x));
      }

      return $dates_array;
   }

   // see the dates in the array
   print_r( getDatesFromRange('2017-02-09', '2017-02-19') );

如果您在调用函数时添加第三个参数,甚至可以更改默认的输出日期格式,否则它将使用已设置为“Y-m-d”的默认格式。

希望能对您有所帮助 :)


当时区设置为('Europe/Berlin'),日期范围为2016-10-30到2016-11-01时,这个答案会出现错误。http://sandbox.onlinephpfunctions.com/code/b57a6fdf07cce1cea791db1db14ed38f369d2299 - mickmackusa

-3
$arr = range(strtotime("2013-12-01"),strtotime("2013-12-31"), "86400");
array_walk_recursive($arr, function(&$element) { $element = date("Y-m-d", $element); });
print_r ($arr);

4
好的,我会尽力进行翻译。以下是需要翻译的内容:请添加一些英语以阐明您的回答。 - hgwhittle
当时区设置为('Europe/Berlin'),日期范围为2016-10-30至2016-11-01时,此答案会出现错误。http://sandbox.onlinephpfunctions.com/code/db3881a8ecab7dc9a6bcf63bf87f404cefdb2bcc - mickmackusa

-3
function getWeekdayDatesFrom($format, $start_date_epoch, $end_date_epoch, $range) {

    $dates_arr = array();

    if( ! $range) {
        $range = round(abs($start_date_epoch-$end_date_epoch)/86400) + 1;
    } else {
        $range = $range + 1; //end date inclusive
    }

    $current_date_epoch = $start_date_epoch;

    for($i = 1; $i <= $range; $i+1) {

        $d = date('N',  $current_date_epoch);

        if($d <= 5) { // not sat or sun
            $dates_arr[] = "'".date($format, $current_date_epoch)."'";
        }

        $next_day_epoch = strtotime('+'.$i.'day', $start_date_epoch);
        $i++;
        $current_date_epoch = $next_day_epoch;

    }

    return $dates_arr;
} 

这应该可以回答你的问题,不止如此。使用这个函数,你可以声明返回格式(例如Y-m-d),声明开始日期和结束日期或者开始日期和范围。我目前将其设置为包括结束日期并且默认仅返回工作日(这很容易撤消)。 - coddiwomplefrog
如果给出错误答案的原因,那么错误的答案在很多情况下和正确的一样有帮助。如果你要点踩,应该给一个理由。然而,我的答案并不是错误的。它也是一个公正的回答。 - coddiwomplefrog
当时区设置为Europe/Berlin,日期范围为2016-10-30至2016-11-01时,此答案注定会失败。此外,没有函数调用指定要提供给$format$start_date_epoch$end_date_epoch$range的值。请编辑或删除此答案。 - mickmackusa

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