On this page:
1.4.3.1 Zoned values from Racket

1.4.3 Time zones🔗ℹ

Avoid time zones when you can. A datetime column has none (it is naive), "UTC", or an area/location zone from the tz database such as "Asia/Kathmandu"; its dtype is '(datetime unit "Zone/Name"). Fixed offsets such as +02:00 are better avoided: Polars keeps one as "Etc/GMT-2", which knows no daylight saving. A column has one zone, so data with several offsets parses to UTC (Mixed offsets).

dt-convert-time-zone converts from one zone to another, keeping each instant; dt-replace-time-zone sets, changes or, given #f, unsets the zone, keeping each wall-clock time:

> (define ts '("2021-03-27 03:00" "2021-03-28 03:00"))
> (define tz-naive
    (~> (dataframe (list (series ts #:name "tz_naive")))
        (select (str->datetime "tz_naive"))
        (ref "tz_naive")))
> (define tz-aware (~> tz-naive (dt-replace-time-zone "UTC") (rename "tz_aware")))
> (define time-zones-df (dataframe (list tz-naive tz-aware)))
> time-zones-df

shape: (2, 2)

┌─────────────────────┬─────────────────────────┐

│ tz_naive            ┆ tz_aware                │

│ ---                 ┆ ---                     │

│ datetime[μs]        ┆ datetime[μs, UTC]       │

╞═════════════════════╪═════════════════════════╡

│ 2021-03-27 03:00:00 ┆ 2021-03-27 03:00:00 UTC │

│ 2021-03-28 03:00:00 ┆ 2021-03-28 03:00:00 UTC │

└─────────────────────┴─────────────────────────┘

> (select time-zones-df
          (~> (col "tz_aware") (dt-replace-time-zone "Europe/Brussels")
              (alias "replace time zone"))
          (~> (col "tz_aware") (dt-convert-time-zone "Asia/Kathmandu")
              (alias "convert time zone"))
          (~> (col "tz_aware") (dt-replace-time-zone #f) (alias "unset time zone")))

shape: (2, 3)

┌───────────────────────────────┬──────────────────────────────┬─────────────────────┐

│ replace time zone             ┆ convert time zone            ┆ unset time zone     │

│ ---                           ┆ ---                          ┆ ---                 │

│ datetime[μs, Europe/Brussels] ┆ datetime[μs, Asia/Kathmandu] ┆ datetime[μs]        │

╞═══════════════════════════════╪══════════════════════════════╪═════════════════════╡

│ 2021-03-27 03:00:00 CET       ┆ 2021-03-27 08:45:00 +0545    ┆ 2021-03-27 03:00:00 │

│ 2021-03-28 03:00:00 CEST      ┆ 2021-03-28 08:45:00 +0545    ┆ 2021-03-28 03:00:00 │

└───────────────────────────────┴──────────────────────────────┴─────────────────────┘

1.4.3.1 Zoned values from Racket🔗ℹ

A gregor moment is an instant in a zone, as Python’s aware datetime is, and a zoned column’s values come back as moments in its zone. A list takes the zone of its first moment, as Python’s does; a fixed offset gives UTC:

> (define landings
    (series (list (moment 2021 3 27 9 #:tz "Europe/Brussels")
                  (moment 2021 3 28 9 #:tz "Europe/Brussels")
                  (moment 2021 3 27 18 #:tz "Asia/Kathmandu"))
            #:name "landed"))
> landings

shape: (3,)

Series: 'landed' [datetime[us, Europe/Brussels]]

[

2021-03-27 09:00:00 CET

2021-03-28 09:00:00 CEST

2021-03-27 13:15:00 CET

]

> (series->list landings)

'(#<moment 2021-03-27T09:00:00+01:00[Europe/Brussels]>

  #<moment 2021-03-28T09:00:00+02:00[Europe/Brussels]>

  #<moment 2021-03-27T13:15:00+01:00[Europe/Brussels]>)

> (dtype (series (list (moment 2021 3 27 9 #:tz 3600))))

'(datetime microseconds "UTC")

A moment read back carries Polars’ offset, from chrono-tz’s tz database. gregor reads the system’s zoneinfo, which can disagree before 1970 or after 2037, so a moment built there can name another instant than Polars would (Dates, times, datetimes and durations).