首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 計算任意日期區間內所有日期並判斷大小月

     編輯:PHP 相關知識

需求背景

專案常需列出某日期區間內的每一天,並標註該月為大月(31天)或小月(30天/28/29天)。本文提供一個純 PHP 實作,無需資料庫即可完成。

核心邏輯

  1. 從「今天」開始倒推,逐日遞減直到達到目標結束日期。
  2. 判斷月份大小:1-7 月奇數月為大月、偶數月為小月;8-12 月偶數月為大月、奇數月為小月;2 月單獨處理閏年。
  3. 輸出日期與大小月標記。

完整程式碼

<?php
/**
 * 列出從今天倒推至指定結束日期的所有日期,並標註大小月
 * 
 * @param string $end_date 結束日期 (YYYY-MM-DD)
 * @return void 直接輸出 HTML
 */
function list_dates_to($end_date) {
    $end_ts = strtotime($end_date);
    if ($end_ts === false) {
        echo "結束日期格式錯誤,請使用 YYYY-MM-DD";
        return;
    }
    
    $current_ts = time(); // 今天 00:00:00
    $current_ts = strtotime(date('Y-m-d', $current_ts)); // 歸零時分秒
    
    if ($current_ts < $end_ts) {
        echo "結束日期不能晚於今天";
        return;
    }
    
    echo "
    "; while ($current_ts >= $end_ts) { $date_str = date('Y-m-d', $current_ts); $month = (int)date('m', $current_ts); $year = (int)date('Y', $current_ts); // 判斷大小月 $month_type = get_month_type($month, $year); echo "
  • $date_str ($month_type)
  • "; // 遞減一天 $current_ts -= 86400; // 24*60*60 } echo "
"; } /** * 判斷月份類型 * @return string '大月' | '小月' | '閏年二月' | '平年二月' */ function get_month_type($month, $year) { if ($month === 2) { return is_leap_year($year) ? '閏年二月(29天)' : '平年二月(28天)'; } // 1-7月:奇大偶小;8-12月:偶大奇小 $is_big = ($month <= 7) ? ($month % 2 === 1) : ($month % 2 === 0); return $is_big ? '大月(31天)' : '小月(30天)'; } function is_leap_year($year) { return ($year % 4 === 0 && $year % 100 !== 0) || ($year % 400 === 0); } // 使用範例 list_dates_to('2024-01-01'); ?>

輸出範例

2024-12-20 (大月(31天))
2024-12-19 (大月(31天))
...
2024-02-29 (閏年二月(29天))
2024-02-28 (閏年二月(29天))
...
2024-01-01 (大月(31天))

優化版:支援正向/反向、自定義格式、陣列回傳

<?php
class DateRangeIterator implements Iterator {
    private $start_ts;
    private $end_ts;
    private $current_ts;
    private $step; // +86400 或 -86400
    private $format;
    
    public function __construct($start_date, $end_date, $format = 'Y-m-d') {
        $this->start_ts = strtotime($start_date);
        $this->end_ts = strtotime($end_date);
        $this->format = $format;
        
        if ($this->start_ts <= $this->end_ts) {
            $this->current_ts = $this->start_ts;
            $this->step = 86400;
        } else {
            $this->current_ts = $this->start_ts;
            $this->step = -86400;
        }
    }
    
    public function current() {
        return [
            'date' => date($this->format, $this->current_ts),
            'timestamp' => $this->current_ts,
            'month_type' => $this->getMonthType(),
            'is_weekend' => in_array(date('N', $this->current_ts), [6,7]),
        ];
    }
    
    public function next() { $this->current_ts += $this->step; }
    public function key() { return $this->current_ts; }
    public function valid() { 
        return ($this->step > 0) ? ($this->current_ts <= $this->end_ts) : ($this->current_ts >= $this->end_ts);
    }
    public function rewind() { 
        $this->current_ts = ($this->step > 0) ? $this->start_ts : $this->start_ts; 
    }
    
    private function getMonthType() {
        $m = (int)date('m', $this->current_ts);
        $y = (int)date('Y', $this->current_ts);
        if ($m === 2) return is_leap_year($y) ? 'leap_feb' : 'common_feb';
        $big = ($m <= 7) ? ($m % 2 === 1) : ($m % 2 === 0);
        return $big ? 'big' : 'small';
    }
}

function is_leap_year($y) {
    return ($y % 4 === 0 && $y % 100 !== 0) || ($y % 400 === 0);
}

// 使用
foreach (new DateRangeIterator('2024-01-01', '2024-12-31') as $info) {
    echo "{$info['date']} [{$info['month_type']}]" . ($info['is_weekend'] ? ' ⚡' : '') . "
"; } ?>

現代替代方案:DatePeriod (PHP 5.3+)

<?php
$start = new DateTime('2024-01-01');
$end = new DateTime('2024-12-31');
$end->modify('+1 day'); // 包含結束日
$interval = new DateInterval('P1D');
$period = new DatePeriod($start, $interval, $end);

foreach ($period as $dt) {
    $m = (int)$dt->format('m');
    $y = (int)$dt->format('Y');
    $type = ($m === 2) 
        ? (($y % 4 === 0 && $y % 100 !== 0) || ($y % 400 === 0) ? '閏年二月' : '平年二月')
        : ((($m <= 7 && $m % 2 === 1) || ($m >= 8 && $m % 2 === 0)) ? '大月' : '小月');
    echo $dt->format('Y-m-d') . " ($type)
"; } ?>

總結

利用 strtotime()、date() 與簡單數學運算即可實現日期區間遍歷與大小月判斷。現代專案建議使用 DateTime、DatePeriod 物件導向介面,更直觀且自動處理時區、閏秒等邊界情況。記得:2月單獨判斷閏年,1-7月奇大偶小,8-12月偶大奇小 是核心邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved