PHP Carbon,如何获取日期范围内的所有日期?

104

如何在PHP中获取两个日期之间的所有日期?最好使用Carbon处理日期。

$from = Carbon::now();
$to = Carbon::createFromDate(2017, 5, 21);

我想要获取这两个日期之间的所有日期,但是怎么做呢?我只能找到使用strtotime函数的解决方案。

12个回答

210

截至Carbon 1.29,现在可以做到:

$period = CarbonPeriod::create('2018-06-14', '2018-06-20');

// Iterate over the period
foreach ($period as $date) {
    echo $date->format('Y-m-d');
}

// Convert the period to an array of dates
$dates = $period->toArray();

详见文档以获取更多细节:https://carbon.nesbot.com/docs/#api-period


3
友情提醒,您也可以使用 $date->toDateString()Y-m-d 格式获取日期。文档 - ibnɘꟻ
@ibnɘꟻ 我知道这一点,但 ->format() 方法可以让你在配置文件中全局存储字符串格式。因此,每当需要在所有地方更改格式时,你不需要到处修改代码。 - Dendi Handian

76

这是我如何使用Carbon完成的

private function generateDateRange(Carbon $start_date, Carbon $end_date)
{
    $dates = [];

    for($date = $start_date->copy(); $date->lte($end_date); $date->addDay()) {
        $dates[] = $date->format('Y-m-d');
    }

    return $dates;
}

2
最后,您不会遇到$start_date等于$end_date的问题吗? 如果您想在此函数调用后继续使用原始的$start_date,则应将原始的$start_date副本传递给此函数或在for循环的定义中设置$date = $start_date -> copy(),我更喜欢后者。 - molerat

22

由于Carbon是PHP内置DateTime的扩展,您应该能够像使用DateTime对象一样使用DatePeriod和DateInterval。

$interval = new DateInterval('P1D');
$to->add($interval);
$daterange = new DatePeriod($from, $interval ,$to);

foreach($daterange as $date){
    echo $date->format("Ymd"), PHP_EOL;
}

编辑

如果您需要包括周期的最后日期,则需要稍微修改它,并在生成DatePeriod之前调整$to

$interval = new DateInterval('P1D');
$daterange = new DatePeriod($from, $interval ,$to);

foreach($daterange as $date){
    echo $date->format("Ymd"), PHP_EOL;
}

如果$to时间不大于$from时间,那么该代码将不会打印出区间内的最后一个日期。我的意思是,至少要比起始时间晚一秒钟,或许是毫秒,我没有尝试过。 - Dariux
添加了相关的代码行,以包括$to日期在期间内。 - Mark Baker

11

基于 Mark Baker 的回答,我编写了这个函数:

/**
 * Compute a range between two dates, and generate
 * a plain array of Carbon objects of each day in it.
 *
 * @param  \Carbon\Carbon  $from
 * @param  \Carbon\Carbon  $to
 * @param  bool  $inclusive
 * @return array|null
 *
 * @author Tristan Jahier
 */
function date_range(Carbon\Carbon $from, Carbon\Carbon $to, $inclusive = true)
{
    if ($from->gt($to)) {
        return null;
    }

    // Clone the date objects to avoid issues, then reset their time
    $from = $from->copy()->startOfDay();
    $to = $to->copy()->startOfDay();

    // Include the end date in the range
    if ($inclusive) {
        $to->addDay();
    }

    $step = Carbon\CarbonInterval::day();
    $period = new DatePeriod($from, $step, $to);

    // Convert the DatePeriod into a plain array of Carbon objects
    $range = [];

    foreach ($period as $day) {
        $range[] = new Carbon\Carbon($day);
    }

    return ! empty($range) ? $range : null;
}

使用方法:

>>> date_range(Carbon::parse('2016-07-21'), Carbon::parse('2016-07-23'));
=> [
     Carbon\Carbon {#760
       +"date": "2016-07-21 00:00:00.000000",
       +"timezone_type": 3,
       +"timezone": "UTC",
     },
     Carbon\Carbon {#759
       +"date": "2016-07-22 00:00:00.000000",
       +"timezone_type": 3,
       +"timezone": "UTC",
     },
     Carbon\Carbon {#761
       +"date": "2016-07-23 00:00:00.000000",
       +"timezone_type": 3,
       +"timezone": "UTC",
     },
   ]

你还可以将一个布尔值(false)作为第三个参数传递,以排除结束日期。


6
这也可以这样做:
new DatePeriod($startDate, new DateInterval('P1D'), $endDate)

请记住,DatePeriod是一个迭代器,如果你想要一个实际的数组:

iterator_to_array(new DatePeriod($startDate, new DateInterval('P1D'), $endDate))

如果您正在使用Laravel,您可以创建一个Carbon宏:

Carbon::macro('range', function ($start, $end) {
    return new Collection(new DatePeriod($start, new DateInterval('P1D'), $end));
});

现在您可以这样做:
foreach (Carbon::range($start, $end) as $date) {
   // ...
}

5

这是我所拥有的:

private function getDatesFromRange($date_time_from, $date_time_to)
    {

        // cut hours, because not getting last day when hours of time to is less than hours of time_from
        // see while loop
        $start = Carbon::createFromFormat('Y-m-d', substr($date_time_from, 0, 10));
        $end = Carbon::createFromFormat('Y-m-d', substr($date_time_to, 0, 10));

        $dates = [];

        while ($start->lte($end)) {

            $dates[] = $start->copy()->format('Y-m-d');

            $start->addDay();
        }

        return $dates;
    }

例子:

$this->getDatesFromRange('2015-03-15 10:10:10', '2015-03-19 09:10:10');

2
您可以直接使用Carbon。
    $start = Carbon::createFromDate(2017, 5, 21);
    $end = Carbon::now();

    while($start < $end){
        echo $start->format("M");
        $start->addMonth();
    }

2
您不能直接使用循环控制变量,下一个应该能够正常运行。
$start = Carbon::today()->startOfWeek();
$end = Carbon::today()->endOfWeek();

$stack = [];

$date = $start;
while ($date <= $end) {

    if (! $date->isWeekend()) {
        $stack[] = $date->copy();
    }
    $date->addDays(1);
}

return $stack;

-1

如果您使用此函数,我认为会更好。

 public static function check_continuous_dates(array $dates): bool
    {
        $startDate = Carbon::create($dates[0]);
        $endDate = Carbon::create(end($dates));
        if ($endDate->diffInDays($startDate)+1 == count($dates)) {
            return true;
        }
        return false;
    } 

1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

-1

例子:

<?php 
        $from = "2023-05-02";
        $to = "2023-05-31";
        $betweenDate = CarbonPeriod::create($from, $to);
        
        $dates = [];
        foreach ($betweenDate as $date) {
            $dates[] =$date->format('Y-m-d');
        }
        dd($dates);
?>

输出:

0 => "2023-05-02" 1 => "2023-05-03" 2 => "2023-05-04" 3 => "2023-05-05" 4 => "2023-05-06" 5 => "2023-05-07" 6 => "2023-05-08" 7 => "2023-05-09" 8 => "2023-05-10" 9 => "2023-05-11" 10 => "2023-05-12" 11 => "2023-05-13" 12 => "2023-05-14" 13 => "2023-05-15" 14 => "2023-05-16" 15 => "2023-05-17" 16 => "2023-05-18" 17 => "2023-05-19" 18 => "2023-05-20" 19 => "2023-05-21" 20 => "2023-05-22" 21 => "2023-05-23" 22 => "2023-05-24" 23 => "2023-05-25" 24 => "2023-05-26" 25 => "2023-05-27" 26 => "2023-05-28" 27 => "2023-05-29" 28 => "2023-05-30" 29 => "2023-05-31"

这个例子中使用的方法与被接受的答案中的方法相同。如果您提供的是相同的方法,请不要添加新的答案。此外,您不应该创建一个带有格式化日期的数组,而是应该保留Carbon日期,并在使用之前进行格式化。 - Your Common Sense
这是一个有效的解决方案。 - Sejal Varu

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