You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP日历开发:如何标记数据库中所有日期区间内的日期?

嘿,我明白你现在卡在哪了——你的日历只能标记数据库里最后一条预订记录的日期范围,之前的所有预订都没显示出来对吧?这问题根源很简单:你在遍历数据库查询结果的时候,每次都用新的$date_from和$date_to覆盖了旧值,循环结束后这两个变量只保留了最后一行的数据,自然只能处理最后一条记录的日期。

咱们来一步步修复这个问题,顺便实现所有占用日期的标记(还能扩展成不同记录用不同颜色):

第一步:先把所有预订的日期都收集到一个集合里

首先,我们需要把数据库里每一条预订的日期范围都拆解成单个日期,统一存到一个数组(或映射)里,而不是只保留最后一条。

修改你数据库查询后的代码部分:

// 初始化数组,用来存所有已被占用的日期(或日期与颜色的映射)
$occupiedDates = [];

// 数据库查询保持不变
$sql = "SELECT date_from, date_to FROM booking_2";
$result = $this->connect()->query($sql);

if ($result->num_rows > 0) {
    while ($row = $result->fetch_assoc()) {
        // 把字符串日期转成DateTime对象,方便生成日期范围
        $startDate = new DateTime($row['date_from']);
        $endDate = new DateTime($row['date_to']);
        // DatePeriod默认不包含结束日期,所以给结束日期加一天
        $endDate->modify('+1 day');
        
        // 生成这个预订的所有日期
        $period = new DatePeriod($startDate, new DateInterval('P1D'), $endDate);
        foreach ($period as $date) {
            // 转成Y-m-d格式存入数组
            $occupiedDates[] = $date->format('Y-m-d');
        }
    }
    // 去重,避免同一日期被多次添加
    $occupiedDates = array_unique($occupiedDates);
}

第二步:渲染日历单元格时检查日期是否被占用

接下来,在循环生成日历每个日期单元格的时候,检查当前日期是否在$occupiedDates数组里,然后给对应的单元格加上样式:

找到你生成日期单元格的那段代码,替换成下面的逻辑:

<?php 
$dayCount = 1; 
for ($cb = 1; $cb <= $boxDisplay; $cb++) { 
    if (($cb >= $currentMonthFirstDay || $currentMonthFirstDay == 7) && $cb <= ($totalDaysOfMonthDisplay - 1)) { 
        $currentDate = $dateYear.'-'.$dateMonth.'-'.$dayCount;
        
        // 检查当前日期是否在已占用数组中
        $isBooked = in_array($currentDate, $occupiedDates);
        
        // 设置单元格样式:如果被占用就加背景色
        $cellStyle = $isBooked ? 'style="background-color:#FF3232 !important;"' : '';
        
        // 输出单元格
        echo '<li date="'.$currentDate.'" class="date_cell" '.$cellStyle.'>';
        echo '<span>'.$dayCount.'</span>';
        echo '</li>';
        
        $dayCount++; 
    } else { 
?>
<li><span>&nbsp;</span></li>
<?php } } ?>

扩展:给不同的预订记录用不同颜色

如果想让每条预订的日期显示不同的颜色,我们可以把日期和对应颜色做个映射:

// 定义一组颜色,循环使用
$availableColors = ['#FF3232', '#32FF66', '#3266FF', '#FFCC32', '#CC32FF'];
$colorIndex = 0;
// 用关联数组存日期对应的颜色
$dateColorMap = [];

$sql = "SELECT date_from, date_to FROM booking_2";
$result = $this->connect()->query($sql);

if ($result->num_rows > 0) {
    while ($row = $result->fetch_assoc()) {
        $startDate = new DateTime($row['date_from']);
        $endDate = new DateTime($row['date_to']);
        $endDate->modify('+1 day');
        
        // 给当前预订分配一个颜色
        $currentColor = $availableColors[$colorIndex % count($availableColors)];
        
        $period = new DatePeriod($startDate, new DateInterval('P1D'), $endDate);
        foreach ($period as $date) {
            $dateStr = $date->format('Y-m-d');
            // 如果日期还没被分配颜色,就用当前预订的颜色(避免后预订的覆盖先预订的)
            if (!isset($dateColorMap[$dateStr])) {
                $dateColorMap[$dateStr] = $currentColor;
            }
        }
        $colorIndex++;
    }
}

然后渲染单元格时改成:

$currentDate = $dateYear.'-'.$dateMonth.'-'.$dayCount;
$cellStyle = '';
if (isset($dateColorMap[$currentDate])) {
    $cellStyle = 'style="background-color:'.$dateColorMap[$currentDate].' !important;"';
}

echo '<li date="'.$currentDate.'" class="date_cell" '.$cellStyle.'>';
echo '<span>'.$dayCount.'</span>';
echo '</li>';

为什么原来的代码不行?

你之前的while循环里,每次都会把$date_from和$date_to替换成当前行的数据,循环结束后这两个变量只剩下最后一条记录的值,所以后面的DatePeriod只处理了最后一个预订的日期范围,前面的所有预订数据都被覆盖丢失了。

现在这样修改后,所有预订的日期都会被收集起来,渲染时逐个检查就能全部标记出来啦!

内容的提问来源于stack exchange,提问作者kaspianso

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:52:14