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

基于Laravel与php-Carbon的日历逻辑:日期解析器开发问题

企业日程表日期解析器实现问题与解决方案思路

我正在为企业日程表开发一个日期解析器,需求是将指定日期对应到上月的同周同日;若遇特殊情况需适配合理日期。但因各月周结构存在差异,且处理31日时会出现月份错误,尝试了以下两段逻辑代码仍存在多日期解析错误的问题,希望获取正确实现思路。

尝试过的代码实现

第一段代码

public function parser($day = "2 feb 2023") {

    $date = Carbon::parse($day);
    $dayOfWeek = $date->copy()->dayOfWeek;
    $numberOfWeek = $date->copy()->weekNumberInMonth;
    $newDate = $date->copy()->subMonth()->startOfWeek(Carbon::SUNDAY)->next($dayOfWeek);
    $lastOfMonthNewDate = $date->copy()->subDay(1)->subMonth(1)->startOfWeek()->next($dayOfWeek);


    if (($date->day == 31) && ($lastOfMonthNewDate == $date->isSameMonth($lastOfMonthNewDate))) {

        return $lastOfMonthNewDate->copy()->subMonth(1)->startOfWeek()->next($dayOfWeek);

    } else if ($date->day == 31) {

        return $lastOfMonthNewDate;

    } else  if ($newDate == $date->isSameMonth($newDate)) {

        return $newDate->copy()->subMonth(1)->startOfWeek()->next($dayOfWeek);

    } else {
            
            return $newDate;
    }
}

更新后的第二段代码

public function parser2($day){
    $date = Carbon::parse($day);
    $dayOfWeek = $date->copy()->dayOfWeek;
    $date4Week = $date->copy()->subWeek(4);
    $date5Week = $date->copy()->subWeek(5);
    $currentWeek = $date->copy()->weekNumberInMonth;
    $prevWeek = $date->copy()->subWeek(4)->weekNumberInMonth;


    if ($date->isSameMonth($date4Week) == 1) {

        if ($currentWeek != $date5Week->copy()->weekNumberInMonth) {
           return $date->subMonth();
        }else{
            return $date4Week->copy()->subWeek();
        }
    }else {

        if ($prevWeek != $currentWeek) {
            return $date5Week;
        }else{
            return $date4Week;
        } 
    }
}

正确实现思路

核心逻辑定义

先明确「同周同日」的业务规则:指原日期是当月第N个星期X,目标是找到上月对应的第N个星期X;如果上月没有第N个星期X,则取当月最后一个星期X。

步骤拆解

  • 提取关键信息:获取原日期的星期几(dayOfWeek)和当月周序号(weekOfMonth),注意可根据业务调整周起始日,比如设置周日为一周开头:Carbon::setWeekStartsAt(Carbon::SUNDAY)。
  • 判断上月周数匹配度:计算上月的总周数,若原日期的周序号≤上月总周数,直接取上月对应周的星期X;若超过,则取上月最后一个星期X。
  • 自动适配特殊日期:像31日这类大日期无需单独判断,通过周序号逻辑就能自动适配到上月合理日期。

参考实现代码

public function parser($day = "2 feb 2023") {
    // 按需设置周起始日,示例为周日开头
    // Carbon::setWeekStartsAt(Carbon::SUNDAY);
    
    $date = Carbon::parse($day);
    $targetDayOfWeek = $date->dayOfWeek;
    $targetWeekNumber = $date->weekOfMonth;
    
    // 上月起始与结束日期
    $prevMonthStart = $date->copy()->subMonth()->startOfMonth();
    $prevMonthEnd = $prevMonthStart->copy()->endOfMonth();
    // 上月总周数
    $prevMonthTotalWeeks = $prevMonthEnd->weekOfMonth;
    
    if ($targetWeekNumber <= $prevMonthTotalWeeks) {
        // 取上月第N个星期X
        $result = $prevMonthStart->copy()->startOfWeek()->addWeeks($targetWeekNumber - 1)->next($targetDayOfWeek);
    } else {
        // 取上月最后一个星期X
        $result = $prevMonthEnd->copy()->startOfWeek()->previous($targetDayOfWeek);
        // 若上月最后一天正好是目标星期,直接取该日期
        if ($prevMonthEnd->dayOfWeek === $targetDayOfWeek) {
            $result = $prevMonthEnd;
        }
    }
    
    return $result;
}

测试验证案例

  • 2023年3月31日(周五,当月第5个周五)→ 2023年2月24日(2月仅4个周五,取最后一个)
  • 2023年2月2日(周四,当月第1个周四)→ 2023年1月5日(1月第1个周四)
  • 2023年1月31日(周二,当月第5个周二)→ 2022年12月27日(12月最后一个周二)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 11:03:14