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

求助:含英国公共假日的奇数周周五收集日期检查器开发

解决你的下一次收集日期检查器问题

看起来你已经有了一个不错的开头!让我们一步步完善这个逻辑,满足你设定的核心规则:仅在每年奇数周的周五收集,若该周包含英国银行假日则调整为周六。

第一步:明确核心逻辑细节

首先要确认几个关键点:

  • 这里的「奇数周」采用ISO周数(date("W")返回的就是ISO标准的周数,范围1-53,每周从周一开始)
  • 「该周包含英国银行假日」指的是周五所在的ISO周(周一至周日)内存在银行假日

第二步:完善「下一个奇数周周五」的查找逻辑

你的现有代码已经开始获取周五,但还需要循环找到下一个属于奇数周的周五。这里要注意:如果当前周是奇数,但周五已经过去了,我们需要直接找下一个奇数周的周五。

// 获取当前日期
$currentDate = new DateTime();

// 初始化下一个候选周五
$nextCollectionFriday = clone $currentDate;
$nextCollectionFriday->modify('this friday');

// 如果当前周五已经过了,直接切换到下一周的周五
if ($nextCollectionFriday < $currentDate) {
    $nextCollectionFriday->modify('+1 week');
}

// 循环筛选,找到下一个奇数周的周五
while (intval($nextCollectionFriday->format("W")) % 2 === 0) {
    $nextCollectionFriday->modify('+1 week');
}

第三步:添加英国银行假日检查逻辑

接下来需要判断这个周五所在的周是否包含英国银行假日。我们可以写一个辅助函数来判断某一天是否是英国银行假日,然后检查该周的所有日期是否存在假日。

辅助函数:判断日期是否为英国银行假日

function isUKBankHoliday(DateTime $date): bool {
    $year = $date->format('Y');
    $dateStr = $date->format('Y-m-d');

    // 固定假日(含周末调休规则)
    $fixedHolidays = [
        // 新年:1月1日,周末则调至周一
        (new DateTime("$year-01-01"))->modify('next monday if Saturday or Sunday')->format('Y-m-d'),
        // 圣诞节:12月25日,周末则调至周一
        (new DateTime("$year-12-25"))->modify('next monday if Saturday or Sunday')->format('Y-m-d'),
        // 节礼日:12月26日,周末则调休(圣诞周六则节礼日周一,圣诞周日则节礼日周二)
        (new DateTime("$year-12-26"))->modify('next monday if Saturday')->modify('next tuesday if Sunday')->format('Y-m-d'),
    ];

    // 移动假日(动态计算)
    // 复活节周一:复活节后的第一个周一(复活节为春分月圆后的第一个周日)
    $easterSunday = new DateTime();
    $easterSunday->setTimestamp(easter_date($year));
    $easterMonday = clone $easterSunday;
    $easterMonday->modify('+1 day');
    $fixedHolidays[] = $easterMonday->format('Y-m-d');

    // 五月初银行假日:5月第一个周一
    $mayEarly = new DateTime("$year-05-01");
    if ($mayEarly->format('w') !== '1') {
        $mayEarly->modify('next monday');
    }
    $fixedHolidays[] = $mayEarly->format('Y-m-d');

    // 五月末银行假日:5月最后一个周一
    $mayLate = new DateTime("$year-05-31");
    if ($mayLate->format('w') !== '1') {
        $mayLate->modify('previous monday');
    }
    $fixedHolidays[] = $mayLate->format('Y-m-d');

    // 八月银行假日:8月最后一个周一
    $august = new DateTime("$year-08-31");
    if ($august->format('w') !== '1') {
        $august->modify('previous monday');
    }
    $fixedHolidays[] = $august->format('Y-m-d');

    // 检查当前日期是否在假日列表中
    return in_array($dateStr, $fixedHolidays);
}

检查目标周是否包含银行假日

现在我们需要遍历$nextCollectionFriday所在周的所有日期,确认是否存在银行假日:

// 获取目标周五所在周的周一和周日
$weekMonday = clone $nextCollectionFriday;
$weekMonday->modify('Monday this week');

$weekSunday = clone $nextCollectionFriday;
$weekSunday->modify('Sunday this week');

// 遍历该周每一天,检查是否有银行假日
$hasBankHolidayInWeek = false;
$currentCheckDate = clone $weekMonday;
while ($currentCheckDate <= $weekSunday) {
    if (isUKBankHoliday($currentCheckDate)) {
        $hasBankHolidayInWeek = true;
        break;
    }
    $currentCheckDate->modify('+1 day');
}

// 根据检查结果调整最终收集日期
$nextCollectionDate = clone $nextCollectionFriday;
if ($hasBankHolidayInWeek) {
    $nextCollectionDate->modify('+1 day'); // 调整为周六
}

// 输出最终结果
echo "下一次收集日期:" . $nextCollectionDate->format('Y-m-d (l)');

第四步:整合测试与优化

把上面的代码整合到一起,就可以得到完整的检查器了。如果需要处理特殊年份的额外假日(比如2023年的加冕礼假日),直接在fixedHolidays数组中添加对应日期即可。

小提示

  • ISO周数的计算基于周一,和我们的需求完全匹配
  • 银行假日的调休规则已经按照英国实际规定处理
  • 动态计算的移动假日(复活节、五月假日等)可以适配任意年份

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:29:55