時間相關的 bug 有一個很討厭的特性:寫的時候測起來全部正常。
你在下午三點寫一條「晚上十點到早上六點進入夜間模式」的自動化,按下儲存,一切看起來都對。然後它從那天起一次都沒有啟動過,而你要兩個月後才會發現 —— 因為「沒有啟動」不會報錯、不會亮紅燈、不會出現在任何清單上。
這篇的重點不只是列出有哪些時間函式,而是怎麼在下午三點就把「凌晨兩點會發生什麼」測出來 。
這篇會做完的事
把時區設對,並且用一個會在設錯時明顯出錯的方法驗證它
建一組「時間診斷卡片」—— 一眼看出系統現在對時間的所有判斷
搞懂 now / utcnow / today_at / as_local 各自該用在哪
學會 time_since 與 time_until(順便處理 relative_time 已經被棄用這件事)
寫一個跨午夜的時段判斷,並且當場測試它在凌晨兩點的行為
處理 time_pattern 最常見的兩個手滑(斜線、前導零)
把上面全部組成一條真的會動的夜間模式自動化
全部做完約 90 分鐘,不需要買任何東西。
第零步:先把時區弄對
0-1 設定
設定 → 系統 → 一般 ,時區選 Asia/Taipei ,國家選台灣,按更新。
0-2 用一個會出錯的方法驗證它
不要只看設定頁顯示什麼。 到 開發者工具 → 範本 ,把左邊輸入框清空,貼上這一整段:
本地時間 {{ now() }} UTC 時間 {{ utcnow() }} 時區名稱 {{ now().tzinfo }} 與 UTC 差幾小時 {{ ((now() - utcnow()).total_seconds() / 3600) | round(0) | int }} 今天是星期幾(0=一 6=日) {{ now().weekday() }} 複製代碼
你會看到 右邊即時顯示:
本地時間 2026-09-25 08:45:12.345678+08:00 UTC 時間 2026-09-25 00:45:12.345678+00:00 時區名稱 CST 與 UTC 差幾小時 8 今天是星期幾(0=一 6=日) 4 複製代碼
四個判準,缺一不可:
本地時間結尾是 +08:00
UTC 時間比本地時間早 8 小時
「與 UTC 差幾小時」是 8 ,不是 0 也不是 -8
本地時間的「時」跟你手錶上的一致
「與 UTC 差幾小時」是 0 → 時區設成 UTC 了。所有排程會提早八小時執行。
時間看起來對但時區名稱是 UTC → 這是最陰險的狀況:機器的系統時鐘被人手動撥快八小時來「修正」。這樣一來 now() 顯示的數字是對的,但 UTC 時間也跟著錯了八小時,而 last_changed 這類內部時間戳是以 UTC 儲存的 —— 所有「距離現在多久」的計算會全部錯八小時。一定要把系統時鐘調回 UTC,用時區設定去修正顯示。
0-3 順便記住一個關鍵事實
Home Assistant 內部所有時間戳都存 UTC。 包括:
states.X.last_changed UTC states.X.last_updated UTC 資料庫的 last_updated_ts Unix 秒數(本來就沒有時區) 觸發器的 trigger.now 本地時間 now() 本地時間 utcnow() UTC 複製代碼
這張表是後面所有坑的根源。
第一步:建一張「時間診斷卡片」
這張卡片的用途是:出問題的時候,一眼看出系統現在對時間的每一個判斷。做一次,之後受用。
1-1 加範本感測器
加進 /config/configuration.yaml 最外層:
# /config/configuration.yaml template: - trigger: - trigger: time_pattern minutes: "/1" sensor: - name: 診斷 現在時刻 unique_id: diag_now state: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}" - name: 診斷 星期 unique_id: diag_weekday state: > {% set w = ['一','二','三','四','五','六','日'] %} 星期{{ w[now().weekday()] }} - name: 診斷 UTC 位移 unique_id: diag_utc_offset unit_of_measurement: h state: > {{ ((now() - utcnow()).total_seconds() / 3600) | round(0) | int }} binary_sensor: - name: 診斷 現在是夜間 unique_id: diag_is_night state: > {{ now() >= today_at('22:00') or now() < today_at('06:00') }} - name: 診斷 現在是上班時間 unique_id: diag_is_work_hours state: > {{ now().weekday() < 5 and today_at('09:00') <= now() < today_at('18:00') }} 複製代碼
1-2 檢查設定 → 重新載入
開發者工具 → YAML → 檢查設定 ,綠燈之後 重新載入範本實體 (第一次加 template: 整合要完整重新啟動)。
1-3 加卡片
設定 → 儀表板 → 鉛筆 → 新增卡片 → 手動 :