20181102 Airflow 中的时区问题

TL;DR:在北京时间,想要在 0:00~8:00 每日触发任务且代码中需要使用执行日期,则需使用 next_dstomorrow_ds 来避免日期偏差问题。


Airflow 支持时区设定,但内部处理时间的时候都是转换成 UTC 的,所以在按天进行调度的时候,可能会有显示时间不一致的问题。

比如我们希望每天早上 9:00 的时候运行昨天一天的任务,无论是按照文档中写的创建一个带时区的 start_date:

1
2
3
4
5
6
7
8
9
import pendulum

local_tz = pendulum.timezone("Asia/Shanghai")

with DAG(dag_id='test_timezone',
schedule_interval='0 9 * * *',
start_date=datetime(2018, 10, 20, tzinfo=local_tz),
catchup=True
) as dag:

还是直接转换成 UTC 的时间,即 1:00,对应 +8 区的 9:00

1
2
3
4
5
with DAG(dag_id='test_timezone',
schedule_interval='0 1 * * *',
start_date=datetime(2018, 10, 20),
catchup=True
) as dag:

这时任务执行中,使用 ds 都是没有问题的,比如处理 2018-10-31 的数据,ds 也会被渲染成 2018-10-31,因为在 2018-11-01 09:00:00+08:00 对应的 UTC 时间是 2018-11-01 01:00:00+00:00,此时两者的日期是一样的。

但假如我们想每天早上 7:00 执行任务,这时 2018-11-01 07:00:00+08:00 对应的 UTC 时间就是 2018-10-31 23:00:00+00:00,此时 ds 会被渲染成 2018-10-31,所以假如代码中依赖了执行日期,则需要使用 next_dstomorrow_ds 来避免日期偏差问题。

在内部,marcos 中的这些时间都是通过 execution_date 进行格式转换输出的,而 execution_date 是在 TaskInstance.__init__() 中被转换成 UTC 时间的,无论是设定了 start_date 的时区,还是直接修改了 Airflow 的默认时区。