时区

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

如果您的用户居住在多个时区,并且您想根据每个用户的挂钟显示 datetime 信息,这将非常方便。

即使你只在一个时区中运行 Airflow,在数据库中以 UTC 存储数据仍然是一种好习惯(在 Airflow 变得支持时区之前,这也是推荐的甚至必需的设置)。主要原因是许多国家/地区使用夏令时 (DST),其中时钟在春季调快,在秋季调慢。如果你在当地时间工作,则可能会在过渡发生时每年遇到两次错误。(Pendulum 和 pytz 文档更详细地讨论了这些问题。)对于简单的 DAG 来说,这可能无关紧要,但如果你从事金融服务等行业,则会出现问题,因为你必须满足一天结束时的截止时间。

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

注意

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

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 子类的实例。当设置此属性并描述偏移量时,datetime 对象是已知的。否则,它就是朴素的。

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

因为 Airflow 使用时区已知的 datetime 对象。如果你的代码创建 datetime 对象,它们也需要已知。

from airflow.utils import timezone

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

朴素 datetime 对象的解释

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

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 会引发异常。这就是为什么在启用时区支持时你应该始终创建已知的 datetime 对象的原因。

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

默认时区

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

[core]
default_timezone = utc

注意

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

支持时区的 DAG

创建支持时区的 DAG 非常简单。只需确保使用 pendulum 提供支持时区的 start_date 即可。不要尝试使用标准库 时区,因为众所周知它们存在局限性,并且我们故意不允许在 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 将在每天 05:00 UTC 运行,而不管夏令时如何。

此条目是否有用?