diff --git a/narwhals/_duckdb/expr_dt.py b/narwhals/_duckdb/expr_dt.py index c3ed9710e..fa8e0c618 100644 --- a/narwhals/_duckdb/expr_dt.py +++ b/narwhals/_duckdb/expr_dt.py @@ -130,3 +130,55 @@ def date(self) -> DuckDBExpr: "date", returns_scalar=self._compliant_expr._returns_scalar, ) + + def total_minutes(self) -> DuckDBExpr: + from duckdb import ConstantExpression + from duckdb import FunctionExpression + + return self._compliant_expr._from_call( + lambda _input: FunctionExpression( + "datepart", ConstantExpression("minute"), _input + ), + "total_minutes", + returns_scalar=self._compliant_expr._returns_scalar, + ) + + def total_seconds(self) -> DuckDBExpr: + from duckdb import ConstantExpression + from duckdb import FunctionExpression + + return self._compliant_expr._from_call( + lambda _input: 60 + * FunctionExpression("datepart", ConstantExpression("minute"), _input) + + FunctionExpression("datepart", ConstantExpression("second"), _input), + "total_seconds", + returns_scalar=self._compliant_expr._returns_scalar, + ) + + def total_milliseconds(self) -> DuckDBExpr: + from duckdb import ConstantExpression + from duckdb import FunctionExpression + + return self._compliant_expr._from_call( + lambda _input: 60_000 + * FunctionExpression("datepart", ConstantExpression("minute"), _input) + + FunctionExpression("datepart", ConstantExpression("millisecond"), _input), + "total_milliseconds", + returns_scalar=self._compliant_expr._returns_scalar, + ) + + def total_microseconds(self) -> DuckDBExpr: + from duckdb import ConstantExpression + from duckdb import FunctionExpression + + return self._compliant_expr._from_call( + lambda _input: 60_000_000 + * FunctionExpression("datepart", ConstantExpression("minute"), _input) + + FunctionExpression("datepart", ConstantExpression("microsecond"), _input), + "total_microseconds", + returns_scalar=self._compliant_expr._returns_scalar, + ) + + def total_nanoseconds(self) -> DuckDBExpr: + msg = "`total_nanoseconds` is not implemented for DuckDB" + raise NotImplementedError(msg) diff --git a/tests/expr_and_series/dt/datetime_duration_test.py b/tests/expr_and_series/dt/datetime_duration_test.py index 7ec281daa..32bf5d904 100644 --- a/tests/expr_and_series/dt/datetime_duration_test.py +++ b/tests/expr_and_series/dt/datetime_duration_test.py @@ -46,7 +46,9 @@ def test_duration_attributes( ) -> None: if PANDAS_VERSION < (2, 2) and "pandas_pyarrow" in str(constructor): request.applymarker(pytest.mark.xfail) - if ("pyspark" in str(constructor)) or "duckdb" in str(constructor): + if "pyspark" in str(constructor): + request.applymarker(pytest.mark.xfail) + if "duckdb" in str(constructor) and attribute == "total_nanoseconds": request.applymarker(pytest.mark.xfail) df = nw.from_native(constructor(data))