时区

默认启用时区支持。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用户界面

默认情况下,Web界面会显示UTC时间。您可以通过右上角的菜单(点击时钟激活)来更改显示的时区:

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

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

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

注意

如果您已将Airflow配置为使用不同的默认时区,并希望用户界面也使用相同的时区,请在[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)

原生日期时间对象的解释

尽管Airflow完全支持时区感知,但在DAG定义中仍接受原生日期时间对象作为start_datesend_dates。这主要是为了保持向后兼容性。当遇到原生start_dateend_date时,将应用默认时区。应用方式假定原生日期时间已在默认时区中。换句话说,如果您的默认时区设置为Europe/Amsterdam并创建原生日期时间start_datedatetime(2017, 1, 1),则假定该start_date为阿姆斯特丹时间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

不幸的是,在夏令时转换期间,某些日期时间可能不存在或存在歧义。 在这种情况下,pendulum会抛出异常。这就是为什么在启用时区支持时,您应该始终创建感知型 datetime对象。

实际上,这很少成为问题。Airflow在模型和DAG中为您提供时区感知的datetime对象,大多数情况下,新的datetime对象是通过timedelta算法从现有对象创建的。在应用程序代码中经常创建的唯一datetime是当前时间,而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时区的DAG,调度设置为0 0 * * *将在夏令时期间每天04:00 UTC运行,其他时间则在05:00运行。

时间间隔

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

这篇内容对您有帮助吗?