时区

默认情况下启用对时区的支持。Airflow 在内部和数据库中以 UTC 格式存储日期时间信息。它允许您使用依赖时区的计划运行 DAG。目前,Airflow 不会在用户界面中将其转换为最终用户的时区。它将始终在那里以 UTC 格式显示。此外,操作符中使用的模板也不会进行转换。时区信息是公开的,由 DAG 的编写者决定如何处理它。

如果您的用户居住在多个时区,并且您希望根据每个用户的时钟显示日期时间信息,这将非常方便。

即使您仅在一个时区中运行 Airflow,在数据库中以 UTC 格式存储数据仍然是一个好习惯(在 Airflow 具有时区感知能力之前,这也是推荐甚至必需的设置)。主要原因是许多国家/地区使用夏令时 (DST),在春季将时钟向前拨,在秋季向后拨。如果您使用本地时间,则在转换发生时,您很可能会每年遇到两次错误。(pendulum 和 pytz 文档更详细地讨论了这些问题。)这对于简单的 DAG 可能并不重要,但如果您在(例如)金融服务领域,需要满足每天结束的截止日期,则这是一个问题。

时区在 airflow.cfg 中设置。默认情况下,它设置为 UTC,但您可以将其更改为使用系统的设置或任意 IANA 时区,例如 Europe/Amsterdam。它依赖于 pendulum,它比 pytz 更准确。安装 Airflow 时会安装 Pendulum。

注意

Pendulum 默认依赖于自己的时区数据库,该数据库的更新频率不如 IANA 数据库。您可以通过将 PYTZDATA_TZDATADIR 环境变量设置为系统的数据库来使 Pendulum 依赖于系统的数据库,例如 /usr/share/zoneinfo

Web UI

默认情况下,Web UI 将以 UTC 格式显示时间。可以使用右上角的菜单更改显示的时区(单击时钟以激活它)

../_images/ui-timezone-chooser.png

“本地”是从浏览器的时区检测到的。“服务器”值来自 [core] 部分中的 default_timezone 设置。

用户选择的时区存储在 LocalStorage 中,因此是每个浏览器的设置。

注意

如果您已将 Airflow 安装配置为使用不同的默认时区,并且希望 UI 使用相同的时区,请将 [webserver] 部分中的 default_ui_timezone 设置为空字符串或相同的值。

(它目前默认为 UTC,以保持 UI 在点发布之间默认行为的一致性。)

概念

朴素和感知日期时间对象

Python 的 datetime.datetime 对象具有一个 tzinfo 属性,该属性可用于存储时区信息,表示为 datetime.tzinfo 子类的实例。当设置此属性并描述偏移量时,日期时间对象是感知的。否则,它是朴素的。

您可以使用 timezone.is_localized()timezone.is_naive() 来确定日期时间是感知的还是朴素的。

因为 Airflow 使用时区感知的日期时间对象。如果您的代码创建日期时间对象,它们也需要是感知的。

from airflow.utils import timezone

now = timezone.utcnow()
a_date = timezone.datetime(2017, 1, 1)

朴素日期时间对象的解释

尽管 Airflow 完全以时区感知的方式运行,但它仍然接受 DAG 定义中的 start_datesend_dates 的朴素日期时间对象。这主要是为了保留向后兼容性。如果遇到朴素的 start_dateend_date,则应用默认时区。它的应用方式是假设朴素日期时间已位于默认时区。换句话说,如果您的默认时区设置为 Europe/Amsterdam,并且创建了 datetime(2017, 1, 1) 的朴素日期时间 start_date,则假定它是 2017 年 1 月 1 日阿姆斯特丹时间的 start_date

dag = DAG(
    "my_dag",
    start_date=pendulum.datetime(2017, 1, 1, tz="UTC"),
    default_args={"retries": 3},
)
op = BashOperator(task_id="hello_world", bash_command="Hello World!", dag=dag)
print(op.retries)  # 3

不幸的是,在 DST 转换期间,某些日期时间不存在或不明确。在这种情况下,pendulum 会引发异常。这就是为什么在启用时区支持时,您应该始终创建感知日期时间对象的原因。

实际上,这很少成为问题。Airflow 在模型和 DAG 中为您提供时区感知的日期时间对象,并且大多数情况下,新的日期时间对象是通过 timedelta 算法从现有对象创建的。应用程序代码中经常创建的唯一日期时间是当前时间,并且 timezone.utcnow() 会自动执行正确的操作。

默认时区

默认时区是由 [core] 下的 default_timezone 设置定义的时区。如果您刚安装了 Airflow,它将设置为 utc,这是推荐的设置。您还可以将其设置为 system 或 IANA 时区(例如 Europe/Amsterdam)。DAG 也会在 Airflow 工作节点上进行评估,因此确保所有 Airflow 节点上的此设置相等非常重要。

[core]
default_timezone = utc

注意

有关设置配置的更多信息,请参阅 设置配置选项

时区感知的 DAG

创建一个时区感知的 DAG 非常简单。只需确保使用 pendulum 提供一个时区感知的 start_date 即可。不要尝试使用标准库 timezone,因为它们已知存在限制,并且我们故意禁止在 DAG 中使用它们。

import pendulum

dag = DAG("my_tz_dag", start_date=pendulum.datetime(2016, 1, 1, tz="Europe/Amsterdam"))
op = EmptyOperator(task_id="empty", dag=dag)
print(dag.timezone)  # <Timezone [Europe/Amsterdam]>

请注意,虽然可以为任务设置 start_dateend_date,但 DAG 时区或全局时区(按此顺序)将始终用于计算数据间隔。第一次遇到时,开始日期或结束日期将使用与 start_dateend_date 关联的时区转换为 UTC,然后对于计算,将忽略此时间信息。

注意

在创作时区感知 DAG 时,您必须确保基础时区库(例如:pendulum)已使用法规的最新更改(夏令时更改等)进行更新。当预期发生时间更改时,您应该使用基础时区库验证切换是否按预期发生。可能需要更新库版本。作为一般建议,如果您可以用 UTC 创作 DAG,则首选这种方式。

模板

Airflow 在模板中返回时区感知的日期时间,但不会将其转换为本地时间,因此它们仍保留在 UTC 中。这留给 DAG 来处理。

import pendulum

local_tz = pendulum.timezone("Europe/Amsterdam")
local_tz.convert(logical_date)

Cron 调度

使用 cron 调度的时区感知 DAG 遵循夏令时。例如,在 US/Eastern 时区中具有起始日期且计划为 0 0 * * * 的 DAG 将在夏令时期间每天在 04:00 UTC 运行,否则在 05:00 运行。

时间差

使用 timedeltarelativedelta 调度的时间感知 DAG 会考虑开始日期夏令时的影响,但在安排后续运行时不会调整夏令时。例如,一个开始日期为 pendulum.datetime(2020, 1, 1, tz="UTC") 并且调度间隔为 timedelta(days=1) 的 DAG 将每天在 UTC 时间 05:00 运行,而不会考虑夏令时。

此条目是否对您有所帮助?