專案需要月曆功能,參考現有開源專案發現功能雖強但過於複雜,決定自行實作輕量級萬年曆函數。本文分享核心邏輯與完整程式碼,支援指定年月顯示、閏年判斷、星期對齊,並預留日期連結擴充介面。
getdate(mktime()) 取得 1 號星期幾,決定起始偏移<?php
/**
* 產生指定年月的月曆 HTML
* @param int $year 年份(如 2024)
* @param int|string $month 月份(1-12,支援 "08" 格式)
* @return string 月曆 HTML 字串
*/
function calendar($year, $month) {
// 正規化月份格式
$month = (int)$month;
if ($month < 1 || $month > 12) return "月份錯誤";
// 月份天數陣列
$daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
// 閏年判斷(標準演算法)
if (($year % 4 === 0 && $year % 100 !== 0) || $year % 400 === 0) {
$daysInMonth[1] = 29;
}
$totalDays = $daysInMonth[$month - 1];
// 取得 1 號星期幾 (0=週日, 1=週一, ..., 6=週六)
$firstDayInfo = getdate(mktime(0, 0, 0, $month, 1, $year));
$firstWeekday = $firstDayInfo['wday'];
$html = "<table class='calendar'>\n";
$html .= " <tr><th>日</th><th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th></tr>\n";
$html .= " <tr>\n";
// 1 號前的空白格
for ($i = 0; $i < $firstWeekday; $i++) {
$html .= " <td> </td>\n";
}
// 日期迴圈
for ($day = 1; $day <= $totalDays; $day++) {
$weekday = ($firstWeekday + $day - 1) % 7;
// 每週日換行(週日為 0,若 day=1 則已處理)
if ($weekday === 0 && $day !== 1) {
$html .= " </tr>\n <tr>\n";
}
// 日期格式化(兩位數)
$dayStr = sprintf("%02d", $day);
// 這裡可擴充日期連結,例如:<a href="?date={$year}-{$month}-{$dayStr}">{$day}</a>
$html .= " <td>{$day}</td>\n";
}
// 最後一週補齊空白格
$lastWeekday = ($firstWeekday + $totalDays - 1) % 7;
for ($i = $lastWeekday + 1; $i < 7; $i++) {
$html .= " <td> </td>\n";
}
$html .= " </tr>\n</table>\n";
return $html;
}
// 測試
echo calendar(2024, 8);
?>
<style>
.calendar { border-collapse: collapse; width: 100%; max-width: 400px; font-family: sans-serif; }
.calendar th, .calendar td { border: 1px solid #ddd; padding: 8px; text-align: center; }
.calendar th { background: #f0f0f0; font-weight: bold; }
.calendar td:hover { background: #e8f4fd; cursor: pointer; }
.calendar td:empty { background: #fafafa; }
</style>
| 功能 | 實作方式 |
|---|---|
| 日期事件標記 | 傳入事件陣列,對應日期加 CSS class 或 tooltip |
| 農曆/節氣顯示 | 引入農曆轉換庫(如 ChineseCalendar) |
| 月份導航 | 輸出上/下月連結,配合 $_GET 參數切換 |
| 今日高亮 | 比對 date('Y-m-d') 加入 .today 樣式 |
| 多語系星期 | 使用 setlocale + strftime 或 IntlDateFormatter |
| 響應式設計 | CSS Grid/Flexbox 適配行動裝置 |
原始碼作者於 2000 年開發,採用 mktime、getdate 等經典函數,邏輯清晰易懂。現代專案建議善用 PHP 內建 DateTime 類別與 Intl 擴充套件,處理時區、本地化、曆法轉換等複雜需求更為可靠。