在 PHP 中判斷當前時間是否落於某個時段(如營業時間 09:00–19:00),核心在於將「今天的特定時分秒」轉換為 Unix 時間戳記進行比對。mktime() 函數正是實現此需求的關鍵工具。
// 取得「今天」的指定時間點時間戳
$today = new DateTimeImmutable(); // 或 date() 取得年月日
$startTs = mktime(9, 0, 0, $today->format('m'), $today->format('d'), $today->format('Y')); // 09:00:00
$endTs = mktime(19, 0, 0, $today->format('m'), $today->format('d'), $today->format('Y')); // 19:00:00
$nowTs = time(); // 當前時間戳
if ($nowTs >= $startTs && $nowTs <= $endTs) {
echo '在營業時間內';
} else {
echo '非營業時間';
}
mktime(
int $hour,
int $minute,
int $second,
int $month,
int $day,
int $year,
int $is_dst = -1 // PHP 5.1.0 棄用,7.0.0 移除
): int|false
falsedate.timezone 設定或 date_default_timezone_set() 決定$startTs = mktime(9, 0, 0, date('m'), date('d'), date('Y'));
$endTs = mktime(19, 0, 0, date('m'), date('d'), date('Y'));
// 明天 09:00
$tomorrow9 = mktime(9, 0, 0, date('m'), date('d') + 1, date('Y'));
// 下週一 00:00(strtotime 更適合相對日期)
$nextMonday = strtotime('next Monday 00:00:00');
// 或 mktime 配合 date('N') 計算
$daysToMonday = (8 - date('N')) % 7; // 今天是週一則為 7
$nextMonday = mktime(0, 0, 0, date('m'), date('d') + $daysToMonday, date('Y'));
// 設定預設時區(建議在 bootstrap 階段設定一次)
date_default_timezone_set('Asia/Taipei');
// 取得指定時區的「今天 09:00」時間戳
$tz = new DateTimeZone('America/New_York');
$dt = new DateTimeImmutable('now', $tz);
$ny9am = mktime(9, 0, 0, $dt->format('m'), $dt->format('d'), $dt->format('Y'));
// 注意:mktime() 使用的是 date_default_timezone_set() 設定的時區
// 跨時區精確運算建議改用 DateTime 物件
function isToday(int $timestamp): bool {
$todayStart = mktime(0, 0, 0);
$todayEnd = mktime(23, 59, 59);
return $timestamp >= $todayStart && $timestamp <= $todayEnd;
}
// 更簡潔:比較日期字串
function isTodaySimple(int $timestamp): bool {
return date('Y-m-d', $timestamp) === date('Y-m-d');
}
mktime() 屬於程序式 API,現代 PHP 建議使用物件導向的 DateTimeImmutable,功能更強、時區處理更正確、不可變特性避免副作用。
use DateTimeImmutable;
use DateTimeZone;
$tz = new DateTimeZone('Asia/Taipei');
$now = new DateTimeImmutable('now', $tz);
// 今天 09:00
$start = $now->setTime(9, 0, 0);
// 今天 19:00
$end = $now->setTime(19, 0, 0);
if ($now >= $start && $now <= $end) {
echo '營業時間';
}
// 取得時間戳(如需儲存資料庫/傳 API)
$startTs = $start->getTimestamp();
$endTs = $end->getTimestamp();
$dt->setTimezone(new DateTimeZone('UTC'))new DateTimeImmutable('first day of next month')$dt->format('Y-m-d H:i:s')DateTimeInterface 可型別提示| 方法 | 100萬次執行時間 | 適用場景 |
|---|---|---|
mktime() + date() | ~0.35 秒 | 簡單腳本、舊版 PHP、單次計算 |
strtotime() | ~0.48 秒 | 解析英文相對日期字串 |
DateTimeImmutable | ~0.62 秒 | 複雜日期運算、時區處理、現代專案標準 |
純時間戳計算 mktime() 最快;但開發效率與正確性考量,新專案首選 DateTimeImmutable。
mktime() 配合系統時區資料庫自動處理,但邏輯上「09:00-19:00」可能不存在或重複,業務需求需明確定義mktime() 支援 1901–2038,64 位系統無此限制(PHP 5.0+)mktime(時, 分, 秒, 月, 日, 年) —— 月日年順序與直覺不同,建議用具名參數(PHP 8.0+):mktime(hour: 9, minute: 0, month: 1, day: 1, year: 2024)class BusinessHours {
private DateTimeZone $timezone;
private array $schedule; // ['mon' => ['09:00','19:00'], ...]
public function __construct(string $timezone = 'Asia/Taipei', array $schedule = []) {
$this->timezone = new DateTimeZone($timezone);
$this->schedule = $schedule ?: [
1 => ['09:00', '19:00'], // 週一
2 => ['09:00', '19:00'],
3 => ['09:00', '19:00'],
4 => ['09:00', '19:00'],
5 => ['09:00', '19:00'],
6 => ['10:00', '16:00'], // 週六
7 => ['00:00', '00:00'], // 週日休息
];
}
public function isOpen(?DateTimeInterface $at = null): bool {
$at = $at ?? new DateTimeImmutable('now', $this->timezone);
$dayOfWeek = (int)$at->format('N'); // 1=Mon ... 7=Sun
$schedule = $this->schedule[$dayOfWeek] ?? ['00:00', '00:00'];
[$startH, $startM] = explode(':', $schedule[0]);
[$endH, $endM] = explode(':', $schedule[1]);
if ($startH === '00' && $startM === '00' && $endH === '00' && $endM === '00') {
return false; // 休息日
}
$start = (clone $at)->setTime((int)$startH, (int)$startM, 0);
$end = (clone $at)->setTime((int)$endH, (int)$endM, 0);
// 跨午夜營業(如 22:00-04:00)
if ($end <= $start) {
$end = $end->modify('+1 day');
}
return $at >= $start && $at <= $end;
}
public function getNextOpenTime(?DateTimeInterface $from = null): ?DateTimeImmutable {
$from = $from ?? new DateTimeImmutable('now', $this->timezone);
for ($i = 0; $i < 14; $i++) { // 最多找兩週
$checkDay = (clone $from)->modify("+$i day");
if ($this->isOpen($checkDay)) {
$dayOfWeek = (int)$checkDay->format('N');
[$h, $m] = explode(':', $this->schedule[$dayOfWeek][0]);
return (clone $checkDay)->setTime((int)$h, (int)$m, 0);
}
}
return null;
}
}
// 使用
$biz = new BusinessHours('Asia/Taipei');
if ($biz->isOpen()) {
echo '我們正在營業!';
} else {
$next = $biz->getNextOpenTime();
echo '目前休息,下次營業時間:' . $next?->format('Y-m-d H:i');
}
mktime() 是 PHP 早期核心日期函數,適合簡單的「指定年月日時分秒轉時間戳」需求。現代開發中,強烈建議改用 DateTimeImmutable,獲得更好的時區支援、不可變安全性、豐富的日期運算 API 與更清晰的語意。無論用哪種方式,核心邏輯皆為:將業務時間邊界轉為時間戳,與當前時間戳比較。