Skip to content

narwhals.Series.dt

convert_time_zone(time_zone)

Convert time zone.

If converting from a time-zone-naive column, then conversion happens as if converting from UTC.

Parameters:

Name Type Description Default
time_zone str

Target time zone.

required

Examples:

>>> from datetime import datetime, timezone
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> import pandas as pd
>>> import polars as pl
>>> import pyarrow as pa
>>> data = [
...     datetime(2024, 1, 1, tzinfo=timezone.utc),
...     datetime(2024, 1, 2, tzinfo=timezone.utc),
... ]
>>> s_pd = pd.Series(data)
>>> s_pl = pl.Series(data)
>>> s_pa = pa.chunked_array([data])

Let's define a dataframe-agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.convert_time_zone("Asia/Kathmandu").to_native()

We can then pass pandas / PyArrow / Polars / any other supported library:

>>> my_library_agnostic_function(s_pd)
0   2024-01-01 05:45:00+05:45
1   2024-01-02 05:45:00+05:45
dtype: datetime64[ns, Asia/Kathmandu]
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [datetime[μs, Asia/Kathmandu]]
[
    2024-01-01 05:45:00 +0545
    2024-01-02 05:45:00 +0545
]
>>> my_library_agnostic_function(s_pa)
<pyarrow.lib.ChunkedArray object at ...>
[
  [
    2024-01-01 00:00:00.000000Z,
    2024-01-02 00:00:00.000000Z
  ]
]

date()

Get the date in a datetime series.

Raises:

Type Description
NotImplementedError

If pandas default backend is being used.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> dates = [datetime(2012, 1, 7, 10, 20), datetime(2023, 3, 10, 11, 32)]
>>> s_pd = pd.Series(dates).convert_dtypes(dtype_backend="pyarrow")
>>> s_pl = pl.Series(dates)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.date().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    2012-01-07
1    2023-03-10
dtype: date32[day][pyarrow]
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [date]
[
   2012-01-07
   2023-03-10
]

day()

Extracts the day in a datetime series.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> dates = [datetime(2022, 1, 1), datetime(2022, 1, 5)]
>>> s_pd = pd.Series(dates)
>>> s_pl = pl.Series(dates)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.day().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    1
1    5
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i8]
[
   1
   5
]

hour()

Extracts the hour in a datetime series.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> dates = [datetime(2022, 1, 1, 5, 3), datetime(2022, 1, 5, 9, 12)]
>>> s_pd = pd.Series(dates)
>>> s_pl = pl.Series(dates)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.hour().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    5
1    9
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i8]
[
   5
   9
]

microsecond()

Extracts the microseconds in a datetime series.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> dates = [
...     datetime(2023, 5, 21, 12, 55, 10, 400000),
...     datetime(2023, 5, 21, 12, 55, 10, 600000),
...     datetime(2023, 5, 21, 12, 55, 10, 800000),
...     datetime(2023, 5, 21, 12, 55, 11, 0),
...     datetime(2023, 5, 21, 12, 55, 11, 200000),
... ]
>>> s_pd = pd.Series(dates)
>>> s_pl = pl.Series(dates)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.microsecond().alias("datetime").to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    400000
1    600000
2    800000
3         0
4    200000
Name: datetime, dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (5,)
Series: 'datetime' [i32]
[
   400000
   600000
   800000
   0
   200000
]

millisecond()

Extracts the milliseconds in a datetime series.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> dates = [
...     datetime(2023, 5, 21, 12, 55, 10, 400000),
...     datetime(2023, 5, 21, 12, 55, 10, 600000),
...     datetime(2023, 5, 21, 12, 55, 10, 800000),
...     datetime(2023, 5, 21, 12, 55, 11, 0),
...     datetime(2023, 5, 21, 12, 55, 11, 200000),
... ]
>>> s_pd = pd.Series(dates)
>>> s_pl = pl.Series(dates)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.millisecond().alias("datetime").to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    400
1    600
2    800
3      0
4    200
Name: datetime, dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (5,)
Series: 'datetime' [i32]
[
    400
    600
    800
    0
    200
]

minute()

Extracts the minute in a datetime series.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> dates = [datetime(2022, 1, 1, 5, 3), datetime(2022, 1, 5, 9, 12)]
>>> s_pd = pd.Series(dates)
>>> s_pl = pl.Series(dates)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.minute().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0     3
1    12
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i8]
[
   3
   12
]

month()

Gets the month in a datetime series.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> dates = [datetime(2023, 2, 1), datetime(2023, 8, 3)]
>>> s_pd = pd.Series(dates)
>>> s_pl = pl.Series(dates)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.month().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    2
1    8
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i8]
[
   2
   8
]

nanosecond()

Extract the nanoseconds in a date series.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> dates = [
...     datetime(2022, 1, 1, 5, 3, 10, 500000),
...     datetime(2022, 1, 5, 9, 12, 4, 60000),
... ]
>>> s_pd = pd.Series(dates)
>>> s_pl = pl.Series(dates)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.nanosecond().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    500000000
1     60000000
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i32]
[
   500000000
   60000000
]

ordinal_day()

Get ordinal day.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> data = [datetime(2020, 1, 1), datetime(2020, 8, 3)]
>>> s_pd = pd.Series(data)
>>> s_pl = pl.Series(data)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.ordinal_day().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0      1
1    216
dtype: int32
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i16]
[
   1
   216
]

replace_time_zone(time_zone)

Replace time zone.

Parameters:

Name Type Description Default
time_zone str | None

Target time zone.

required

Examples:

>>> from datetime import datetime, timezone
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> import pandas as pd
>>> import polars as pl
>>> import pyarrow as pa
>>> data = [
...     datetime(2024, 1, 1, tzinfo=timezone.utc),
...     datetime(2024, 1, 2, tzinfo=timezone.utc),
... ]
>>> s_pd = pd.Series(data)
>>> s_pl = pl.Series(data)
>>> s_pa = pa.chunked_array([data])

Let's define a dataframe-agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.replace_time_zone("Asia/Kathmandu").to_native()

We can then pass pandas / PyArrow / Polars / any other supported library:

>>> my_library_agnostic_function(s_pd)
0   2024-01-01 00:00:00+05:45
1   2024-01-02 00:00:00+05:45
dtype: datetime64[ns, Asia/Kathmandu]
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [datetime[μs, Asia/Kathmandu]]
[
    2024-01-01 00:00:00 +0545
    2024-01-02 00:00:00 +0545
]
>>> my_library_agnostic_function(s_pa)
<pyarrow.lib.ChunkedArray object at ...>
[
  [
    2023-12-31 18:15:00.000000Z,
    2024-01-01 18:15:00.000000Z
  ]
]

second()

Extracts the seconds in a datetime series.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> dates = [datetime(2022, 1, 1, 5, 3, 10), datetime(2022, 1, 5, 9, 12, 4)]
>>> s_pd = pd.Series(dates)
>>> s_pl = pl.Series(dates)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.second().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    10
1     4
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i8]
[
   10
    4
]

timestamp(time_unit='us')

Return a timestamp in the given time unit.

Parameters:

Name Type Description Default
time_unit Literal['ns', 'us', 'ms']

{'ns', 'us', 'ms'} Time unit.

'us'

Examples:

>>> from datetime import date
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> import pandas as pd
>>> import polars as pl
>>> import pyarrow as pa
>>> data = [date(2001, 1, 1), None, date(2001, 1, 3)]
>>> s_pd = pd.Series(data, dtype="datetime64[ns]")
>>> s_pl = pl.Series(data)
>>> s_pa = pa.chunked_array([data])

Let's define a dataframe-agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.timestamp("ms").to_native()

We can then pass pandas / PyArrow / Polars / any other supported library:

>>> my_library_agnostic_function(s_pd)
0    9.783072e+11
1             NaN
2    9.784800e+11
dtype: float64
>>> my_library_agnostic_function(s_pl)
shape: (3,)
Series: '' [i64]
[
        978307200000
        null
        978480000000
]
>>> my_library_agnostic_function(s_pa)
<pyarrow.lib.ChunkedArray object at ...>
[
  [
    978307200000,
    null,
    978480000000
  ]
]

total_microseconds()

Get total microseconds.

Notes

The function outputs the total microseconds in the int dtype by default, however, pandas may change the dtype to float when there are missing values, consider using fill_null() in this case.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import timedelta
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> data = [
...     timedelta(microseconds=10),
...     timedelta(milliseconds=1, microseconds=200),
... ]
>>> s_pd = pd.Series(data)
>>> s_pl = pl.Series(data)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.total_microseconds().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0      10
1    1200
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i64]
[
        10
        1200
]

total_milliseconds()

Get total milliseconds.

Notes

The function outputs the total milliseconds in the int dtype by default, however, pandas may change the dtype to float when there are missing values, consider using fill_null() in this case.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import timedelta
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> data = [
...     timedelta(milliseconds=10),
...     timedelta(milliseconds=20, microseconds=40),
... ]
>>> s_pd = pd.Series(data)
>>> s_pl = pl.Series(data)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.total_milliseconds().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    10
1    20
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i64]
[
        10
        20
]

total_minutes()

Get total minutes.

Notes

The function outputs the total minutes in the int dtype by default, however, pandas may change the dtype to float when there are missing values, consider using fill_null() in this case.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import timedelta
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> data = [timedelta(minutes=10), timedelta(minutes=20, seconds=40)]
>>> s_pd = pd.Series(data)
>>> s_pl = pl.Series(data)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.total_minutes().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    10
1    20
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i64]
[
        10
        20
]

total_nanoseconds()

Get total nanoseconds.

Notes

The function outputs the total nanoseconds in the int dtype by default, however, pandas may change the dtype to float when there are missing values, consider using fill_null() in this case.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import timedelta
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> data = ["2024-01-01 00:00:00.000000001", "2024-01-01 00:00:00.000000002"]
>>> s_pd = pd.to_datetime(pd.Series(data))
>>> s_pl = pl.Series(data).str.to_datetime(time_unit="ns")

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.diff().dt.total_nanoseconds().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    NaN
1    1.0
dtype: float64
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i64]
[
        null
        1
]

total_seconds()

Get total seconds.

Notes

The function outputs the total seconds in the int dtype by default, however, pandas may change the dtype to float when there are missing values, consider using fill_null() in this case.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import timedelta
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> data = [timedelta(seconds=10), timedelta(seconds=20, milliseconds=40)]
>>> s_pd = pd.Series(data)
>>> s_pl = pl.Series(data)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.total_seconds().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    10
1    20
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i64]
[
        10
        20
]

to_string(format)

Convert a Date/Time/Datetime series into a String series with the given format.

Notes

Unfortunately, different libraries interpret format directives a bit differently.

  • Chrono, the library used by Polars, uses "%.f" for fractional seconds, whereas pandas and Python stdlib use ".%f".
  • PyArrow interprets "%S" as "seconds, including fractional seconds" whereas most other tools interpret it as "just seconds, as 2 digits".

Therefore, we make the following adjustments:

  • for pandas-like libraries, we replace "%S.%f" with "%S%.f".
  • for PyArrow, we replace "%S.%f" with "%S".

Workarounds like these don't make us happy, and we try to avoid them as much as possible, but here we feel like it's the best compromise.

If you just want to format a date/datetime Series as a local datetime string, and have it work as consistently as possible across libraries, we suggest using:

  • "%Y-%m-%dT%H:%M:%S%.f" for datetimes
  • "%Y-%m-%d" for dates

though note that, even then, different tools may return a different number of trailing zeros. Nonetheless, this is probably consistent enough for most applications.

If you have an application where this is not enough, please open an issue and let us know.

Examples:

>>> from datetime import datetime
>>> import pandas as pd
>>> import polars as pl
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> data = [
...     datetime(2020, 3, 1),
...     datetime(2020, 4, 1),
...     datetime(2020, 5, 1),
... ]
>>> s_pd = pd.Series(data)
>>> s_pl = pl.Series(data)

We define a dataframe-agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.to_string("%Y/%m/%d").to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    2020/03/01
1    2020/04/01
2    2020/05/01
dtype: object
>>> my_library_agnostic_function(s_pl)
shape: (3,)
Series: '' [str]
[
   "2020/03/01"
   "2020/04/01"
   "2020/05/01"
]

year()

Get the year in a datetime series.

Examples:

>>> import pandas as pd
>>> import polars as pl
>>> from datetime import datetime
>>> import narwhals as nw
>>> from narwhals.typing import IntoSeriesT
>>> dates = [datetime(2012, 1, 7), datetime(2023, 3, 10)]
>>> s_pd = pd.Series(dates)
>>> s_pl = pl.Series(dates)

We define a library agnostic function:

>>> def my_library_agnostic_function(s_native: IntoSeriesT) -> IntoSeriesT:
...     s = nw.from_native(s_native, series_only=True)
...     return s.dt.year().to_native()

We can then pass either pandas or Polars to func:

>>> my_library_agnostic_function(s_pd)
0    2012
1    2023
dtype: int...
>>> my_library_agnostic_function(s_pl)
shape: (2,)
Series: '' [i32]
[
   2012
   2023
]