如何用PHP DateTime更优实现指定格式的日期范围展示?
优化日期范围格式化的PHP实现
需求说明
需要将两个日期按照以下格式展示:
29th and 30th November 2024
or
28th to 30th November 2024
or
28th October to 30th November 2024
or
30th November and 1st December 2024
现有实现代码
$date1 = new DateTime('2024-09-29'); $month1 = $date1->format('m'); $date2 = new DateTime('2024-09-30'); $month2 = $date2->format('m'); $interval = $date1->diff($date2); if($month1 == $month2){ if($interval->days == 1){ $result_date = getDayWithSuffix($date1); $result_date .= ' and '; $result_date .= getDayWithSuffix($date2); $result_date .= ' '.$date1->format('F'); $result_date .= ' '.$date1->format('Y'); } else { $result_date = getDayWithSuffix($date1); $result_date .= ' to '; $result_date .= getDayWithSuffix($date2); $result_date .= ' '.$date1->format('F'); $result_date .= ' '.$date1->format('Y'); } } else { if($interval->days == 1){ $result_date = getDayWithSuffix($date1); $result_date .= ' '.$date1->format('F'); $result_date .= ' and '; $result_date .= getDayWithSuffix($date2); $result_date .= ' '.$date2->format('F'); $result_date .= ' '.$date1->format('Y'); } else { $result_date = getDayWithSuffix($date1); $result_date .= ' '.$date1->format('F'); $result_date .= ' to '; $result_date .= getDayWithSuffix($date2); $result_date .= ' '.$date2->format('F'); $result_date .= ' '.$date1->format('Y'); } }
优化后的实现
可以通过抽离重复逻辑、简化条件判断让代码更简洁易维护,核心思路是:
- 统一处理日期后缀生成
- 根据日期间隔确定连接词(
and用于间隔1天,to用于间隔多天) - 根据日期是否同月/跨年,决定月份和年份的展示方式
完整优化代码
/** * 生成带后缀的日期天数(如1st, 2nd, 3rd, 4th) * @param DateTime $date * @return string */ function getDayWithSuffix(DateTime $date): string { $day = (int)$date->format('j'); $suffixes = ['th', 'st', 'nd', 'rd']; $mod = $day % 10; $suffix = ($mod >= 1 && $mod <=3 && ($day <11 || $day>13)) ? $suffixes[$mod] : $suffixes[0]; return "{$day}{$suffix}"; } /** * 格式化日期范围 * @param DateTime $date1 * @param DateTime $date2 * @return string */ function formatDateRange(DateTime $date1, DateTime $date2): string { $interval = $date1->diff($date2); // 确定连接词:间隔1天用and,否则用to $connector = $interval->days === 1 ? ' and ' : ' to '; $day1 = getDayWithSuffix($date1); $day2 = getDayWithSuffix($date2); // 同月同一年的情况 if ($date1->format('Ym') === $date2->format('Ym')) { return "{$day1}{$connector}{$day2} {$date1->format('F Y')}"; } // 不同月或跨年情况 $year1 = $date1->format('Y'); $year2 = $date2->format('Y'); $yearPart = $year1 === $year2 ? " {$year1}" : " {$year1} and {$year2}"; return "{$day1} {$date1->format('F')}{$connector}{$day2} {$date2->format('F')}{$yearPart}"; } // 测试示例 echo formatDateRange(new DateTime('2024-11-29'), new DateTime('2024-11-30')); // 29th and 30th November 2024 echo "\n"; echo formatDateRange(new DateTime('2024-11-28'), new DateTime('2024-11-30')); // 28th to 30th November 2024 echo "\n"; echo formatDateRange(new DateTime('2024-10-28'), new DateTime('2024-11-30')); // 28th October to 30th November 2024 echo "\n"; echo formatDateRange(new DateTime('2024-11-30'), new DateTime('2024-12-01')); // 30th November and 1st December 2024 echo "\n"; echo formatDateRange(new DateTime('2024-12-30'), new DateTime('2025-01-01')); // 30th December and 1st January 2024 and 2025
优化点说明
- 逻辑复用:拆分出独立的后缀生成和范围格式化函数,提升代码可维护性
- 简化判断:将多层嵌套的if-else简化为两步判断,逻辑更清晰
- 兼容跨年:原代码未处理跨年场景,优化后的代码自动适配
- 减少冗余:复用格式化结果,避免重复调用
format方法和字符串拼接
内容的提问来源于stack exchange,提问作者B L Praveen
相关产品推荐
相关产品推荐

