This is an automated email from the ASF dual-hosted git repository.
jason810496 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 7dd84f3eed5 Fix TaskInstance duration calculation with SQLite (#68142)
7dd84f3eed5 is described below
commit 7dd84f3eed5e5ed53cdc9a1e88ce42e35dfc635f
Author: Henry Chen <[email protected]>
AuthorDate: Thu Jun 25 20:09:07 2026 +0800
Fix TaskInstance duration calculation with SQLite (#68142)
---
airflow-core/src/airflow/models/taskinstance.py | 5 ++-
.../tests/unit/models/test_taskinstance.py | 37 +++++++++++++++++++++-
2 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/airflow-core/src/airflow/models/taskinstance.py
b/airflow-core/src/airflow/models/taskinstance.py
index fcf4367c910..c5b4f4ef542 100644
--- a/airflow-core/src/airflow/models/taskinstance.py
+++ b/airflow-core/src/airflow/models/taskinstance.py
@@ -2286,9 +2286,8 @@ class TaskInstance(Base, LoggingMixin, BaseWorkload):
return query.values(
{
"end_date": end_date,
- "duration": (
- (func.strftime("%s", end_date) - func.strftime("%s",
cls.start_date))
- + func.round((func.strftime("%f", end_date) -
func.strftime("%f", cls.start_date)), 3)
+ "duration": func.round(
+ (func.julianday(end_date) -
func.julianday(cls.start_date)) * 86400, 3
),
}
)
diff --git a/airflow-core/tests/unit/models/test_taskinstance.py
b/airflow-core/tests/unit/models/test_taskinstance.py
index 9b30c71cfa9..a4a92835f4f 100644
--- a/airflow-core/tests/unit/models/test_taskinstance.py
+++ b/airflow-core/tests/unit/models/test_taskinstance.py
@@ -34,7 +34,7 @@ import uuid6
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.trace.propagation.tracecontext import
TraceContextTextMapPropagator
-from sqlalchemy import delete, func, inspect as sa_inspect, select
+from sqlalchemy import delete, func, inspect as sa_inspect, select, update
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import load_only
from sqlalchemy.orm.attributes import set_committed_value
@@ -1805,6 +1805,41 @@ class TestTaskInstance:
ti.set_duration()
assert ti.duration is None
+ @pytest.mark.backend("sqlite")
+ @pytest.mark.parametrize(
+ ("start_date", "end_date", "expected_duration"),
+ [
+ (
+ timezone.datetime(2026, 6, 7, 12, 0, 1, 200000),
+ timezone.datetime(2026, 6, 7, 12, 0, 3, 500000),
+ 2.3,
+ ),
+ (
+ timezone.datetime(2026, 6, 7, 12, 0, 59, 200000),
+ timezone.datetime(2026, 6, 7, 12, 1, 0, 500000),
+ 1.3,
+ ),
+ (
+ timezone.datetime(2026, 6, 7, 12),
+ timezone.datetime(2026, 6, 7, 13),
+ 3600.0,
+ ),
+ ],
+ )
+ def test_duration_expression_update_sqlite(
+ self, create_task_instance, session, start_date, end_date,
expected_duration
+ ):
+ ti = create_task_instance()
+ ti.start_date = start_date
+ session.flush()
+
+ query = update(TI).where(TI.id == ti.id)
+ session.execute(TI.duration_expression_update(end_date, query,
session.get_bind()))
+ ti.refresh_from_db(session=session)
+
+ assert ti.end_date == end_date
+ assert ti.duration == expected_duration
+
def test_outlet_asset_extra(self, dag_maker: DagMaker, session: Session):
from airflow.sdk.definitions.asset import Asset