# 時區
> 貢獻者:[@morefreeze](https://github.com/morefreeze)
默認情況下啟用對時區的支持。 Airflow 在內部處理和數據庫中以 UTC 格式存儲日期時間信息。 這樣您就可以在調度中執行帶有時區的 DAG。 目前,Airflow 不支持在 Web UI 中顯示最終用戶時區,它始終以 UTC 顯示。 此外,`Operator`中使用的模板也不會被轉換。 時區信息取決于 DAG 作者如何使用它。
如果您的用戶居住在多個時區,并且您希望根據每個用戶的掛鐘(wall clock)顯示日期時間信息,這將非常方便。
即使您只在一個時區運行 Airflow,在數據庫中以 UTC 格式存儲數據仍然是一種很好的做法(在 Airflow 關心時區問題之前也是如此,這也是推薦的甚至是必需的設置)。 主要原因是夏令時(DST)。 許多國家都有 DST 系統,其中時間在春季向前移動,在秋季向后移動。 如果您在當地工作,那么當發生轉換時,您可能每年會遇到兩次錯誤。 (pendulum 和 pytz 文檔更詳細地討論了這些問題。)這可能并不影響簡單的 DAG,但如果您涉及金融服務中,這可能就變成災難。
時區在`airflow.cfg`中設置。 默認情況下,它設置為 utc,您可以將其更改為使用系統設置或任意 IANA 時區,例如`Europe/Amsterdam` (阿姆斯特丹)。 安裝 Airflow 時會安裝 Pendulum,它比 pytz 更精確,也會讓您更容易處理時區問題。
請注意,**Web UI 目前僅顯示 UTC 時間**。
## 概念
### 了解 datetime 時區敏感對象
tzinfo 是 datetime.datetime 對象中表示時區信息的屬性,它是 datetime.tzinfo 類的對象。 設置 tzinfo 會使 datetime 對象變為時區敏感,否則就是不敏感。
您可以使用`timezone.is_aware()`和`timezone.is_naive()`來確定 datetime 是否時區敏感。
因為 Airflow 使用時區敏感 datetime 對象,所以您創建 datetime 對象時也應該考慮時區問題。
```py
from airflow.utils import timezone
now = timezone.utcnow()
a_date = timezone.datetime(2017,1,1)
```
### 理解原生 datetime 對象
盡管 Airflow 現在是時區敏感的,但為了向后兼容,它仍然允許在 DAG 定義中使用原生 datetime 為`start_dates`和`end_dates`賦值。 如果遇到使用原生 datetime 的`start_date`或`end_date`則使用默認時區。 換句話說,如果您設置了默認時區為`Europe/Amsterdam`,那么對于`start_date = datetime(2017,1,1)`,則認定它是 2017 年 1 月 1 日的 Amesterdam 時間。
```py
default_args = dict(
start_date = datetime(2016, 1, 1),
owner = 'Airflow'
)
dag = DAG ('my_dag', default_args=default_args)
op = DummyOperator(task_id='dummy', dag=dag)
print(op.owner) # Airflow
```
不幸的是,在 DST 轉換期間,某些時間不存在或有二義性。 在這種情況下,pendulum 會拋出異常。 這就是為什么在啟用時區支持時應始終創建時區敏感的 datetime 對象。
實際上,這個問題幾乎不會發生。 在 model 或 DAG 中,Airflow 總是返回給您的是時區敏感的 datetime 對象,通常新的 datetime 對象是通過現有對象和 timedelta 計算而來的。 唯一經常創建并且可能出問題的是當前時間,用`timezone.utcnow()`會避免這些麻煩。
### 默認時區
默認時區是在`airflow.cfg`中的`[core]`下的`default_timezone`定義的。 如果您剛剛安裝了 Airflow,它推薦您設置為 utc。 您還可以將其設置為系統或 IANA 時區(例如`Europe/Amsterdam`)。 DAG 也會在 worker 上進行計算,因此確保所有 worker 節點上的此設置相同。
```py
[core]
default_timezone = utc
```
## 時區敏感 DAG
只需設置`start_date`為時區敏感的 datetime,就創建了時區敏感的 DAG。 建議使用 pendulum,但也可以使用 pytz(手動安裝)。
```py
import pendulum
local_tz = pendulum.timezone("Europe/Amsterdam")
default_args = dict (
start_date = datetime(2016, 1, 1, tzinfo=local_tz),
owner = 'Airflow'
)
dag = DAG('my_tz_dag', default_args=default_args)
op = DummyOperator(task_id='dummy', dag=dag)
print(dag.timezone) # <Timezone [Europe/Amsterdam]>
```
### 模板
Airflow 在模板中返回時區敏感的 datetime,但不會將它們轉換為本地時間,因此它們仍然是 UTC 時區。 由 DAG 來處理轉換。
```py
import pendulum
local_tz = pendulum.timezone("Europe/Amsterdam")
local_tz.convert(execution_date)
```
### Cron 安排
如果您設置了 crontab,Airflow 會假定您始終希望在同一時間運行。 然后它將忽略 DST。 比如,您有一個調度要在每天格林威治標準時間 +1 的 08:00 運行,它將始終在這個時間運行,**無論 DST 是否發生**。
### 時間增量調度
對于具有時間增量的調度,Airflow 假定您始終希望以指定的間隔運行。 比如,您指定`timedelta(hours=2)`運行,它將始終每兩小時運行一次。 在這種情況下,**將考慮 DST**。