diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst
index 4c3e53ddcfa26..f500613fc363e 100644
--- a/doc/source/whatsnew/v1.4.0.rst
+++ b/doc/source/whatsnew/v1.4.0.rst
@@ -225,7 +225,8 @@ Other enhancements
- :class:`ExtensionDtype` and :class:`ExtensionArray` are now (de)serialized when exporting a :class:`DataFrame` with :meth:`DataFrame.to_json` using ``orient='table'`` (:issue:`20612`, :issue:`44705`).
- Add support for `Zstandard `_ compression to :meth:`DataFrame.to_pickle`/:meth:`read_pickle` and friends (:issue:`43925`)
- :meth:`DataFrame.to_sql` now returns an ``int`` of the number of written rows (:issue:`23998`)
-
+- :meth:`Timedelta.total_seconds()` now properly taking into account any nanoseconds contribution (:issue:`40946`)
+-
.. ---------------------------------------------------------------------------
diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx
index a6dc8cc16b229..ba370940cd957 100644
--- a/pandas/_libs/tslibs/conversion.pyx
+++ b/pandas/_libs/tslibs/conversion.pyx
@@ -504,7 +504,7 @@ cdef _TSObject convert_datetime_to_tsobject(datetime ts, tzinfo tz,
if obj.tzinfo is not None and not is_utc(obj.tzinfo):
offset = get_utcoffset(obj.tzinfo, ts)
- obj.value -= int(offset.total_seconds() * 1e9)
+ obj.value -= int(offset.total_seconds() * 1_000_000_000)
if isinstance(ts, ABCTimestamp):
obj.value += ts.nanosecond
diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx
index 6ca43aebed89c..f8f46d19968af 100644
--- a/pandas/_libs/tslibs/nattype.pyx
+++ b/pandas/_libs/tslibs/nattype.pyx
@@ -442,7 +442,31 @@ class NaTType(_NaT):
Monday == 1 ... Sunday == 7.
""",
)
- total_seconds = _make_nan_func("total_seconds", timedelta.total_seconds.__doc__)
+ total_seconds = _make_nan_func(
+ "total_seconds",
+ """
+ Total seconds in the duration with default us precision
+ (for compatibility with `datetime.timedelta`).
+
+ Parameters
+ ----------
+ ns_precision : bool, default False
+ Return the duration with ns precision.
+
+ Examples
+ --------
+ >>> td = pd.Timedelta(days=6, minutes=50, seconds=3,
+ ... milliseconds=10, microseconds=10, nanoseconds=12)
+ >>> td
+ Timedelta('6 days 00:50:03.010010012')
+
+ >>> td.total_seconds()
+ 521403.01001
+
+ >>> td.total_seconds(ns_precision=True)
+ 521403.010010012
+ """
+ )
month_name = _make_nan_func(
"month_name",
"""
diff --git a/pandas/_libs/tslibs/timedeltas.pyx b/pandas/_libs/tslibs/timedeltas.pyx
index a908eefd41768..b88344481bfe4 100644
--- a/pandas/_libs/tslibs/timedeltas.pyx
+++ b/pandas/_libs/tslibs/timedeltas.pyx
@@ -1539,6 +1539,34 @@ class Timedelta(_Timedelta):
div = other // self
return div, other - div * self
+ # GH45129
+ def total_seconds(self, *, ns_precision=False) -> float:
+ """
+ Total seconds in the duration with default us precision
+ (for compatibility with `datetime.timedelta`).
+
+ Parameters
+ ----------
+ ns_precision : bool, default False
+ Return the duration with ns precision.
+
+ Examples
+ --------
+ >>> td = pd.Timedelta(days=6, minutes=50, seconds=3,
+ ... milliseconds=10, microseconds=10, nanoseconds=12)
+ >>> td
+ Timedelta('6 days 00:50:03.010010012')
+
+ >>> td.total_seconds()
+ 521403.01001
+
+ >>> td.total_seconds(ns_precision=True)
+ 521403.010010012
+ """
+ if ns_precision:
+ return self.value / 1_000_000_000
+ return super().total_seconds()
+
cdef bint is_any_td_scalar(object obj):
"""
diff --git a/pandas/tests/tslibs/test_timedeltas.py b/pandas/tests/tslibs/test_timedeltas.py
index c72d279580cca..7107d26866678 100644
--- a/pandas/tests/tslibs/test_timedeltas.py
+++ b/pandas/tests/tslibs/test_timedeltas.py
@@ -46,3 +46,24 @@ def test_huge_nanoseconds_overflow():
# GH 32402
assert delta_to_nanoseconds(Timedelta(1e10)) == 1e10
assert delta_to_nanoseconds(Timedelta(nanoseconds=1e10)) == 1e10
+
+
+# GH40946
+@pytest.mark.parametrize(
+ "obj, expected_ns, expected_us",
+ [
+ (Timedelta("1us"), 1e-6, 1e-6),
+ (Timedelta("500ns"), 5e-7, 0.0),
+ (Timedelta(nanoseconds=500), 5e-7, 0.0),
+ (Timedelta(seconds=1, nanoseconds=500), 1 + 5e-7, 1.0),
+ (Timedelta(seconds=1e-9, milliseconds=1e-5, microseconds=1e-1), 111e-9, 0.0),
+ (
+ Timedelta(days=1, seconds=1e-9, milliseconds=1e-5, microseconds=1e-1),
+ 24 * 3600 + 111e-9,
+ 24 * 3600,
+ ),
+ ],
+)
+def test_total_seconds(obj: Timedelta, expected_ns, expected_us):
+ assert obj.total_seconds() == expected_us
+ assert obj.total_seconds(ns_precision=True) == expected_ns