Skip to content

Time zones

Tom Scott

You really should never, ever deal with time zones if you can help it.

The Datetime datatype can have a time zone associated with it. Examples of valid time zones are:

  • None: no time zone, also known as "time zone naive";
  • UTC: Coordinated Universal Time;
  • Asia/Kathmandu: time zone in "area/location" format. See the list of tz database time zones to see what's available;
  • +01:00: fixed offsets. May be useful when parsing, but you almost certainly want the "Area/Location" format above instead as it will deal with irregularities such as DST (Daylight Saving Time) for you.

Note that, because a Datetime can only have a single time zone, it is impossible to have a column with multiple time zones. If you are parsing data with multiple offsets, you may want to pass utc=True to convert them all to a common time zone (UTC), see parsing dates and times.

The main methods for setting and converting between time zones are:

  • dt.convert_time_zone: convert from one time zone to another;
  • dt.replace_time_zone: set/unset/change time zone;

Let's look at some examples of common operations:

strptime · replace_time_zone · Available on feature timezone

ts = ["2021-03-27 03:00", "2021-03-28 03:00"]
tz_naive = pl.Series("tz_naive", ts).str.strptime(pl.Datetime)
tz_aware = tz_naive.dt.replace_time_zone("UTC").rename("tz_aware")
time_zones_df = pl.DataFrame([tz_naive, tz_aware])
print(time_zones_df)

let ts = ["2021-03-27 03:00", "2021-03-28 03:00"];
let tz_naive = Series::new("tz_naive", &ts);
let time_zones_df = DataFrame::new(vec![tz_naive])?
    .lazy()
    .select([col("tz_naive").str().strptime(
        DataType::Datetime(TimeUnit::Milliseconds, None),
        StrptimeOptions::default(),
    )])
    .with_columns([col("tz_naive")
        .dt()
        .replace_time_zone(Some("UTC".to_string()), None)
        .alias("tz_aware")])
    .collect()?;

println!("{}", &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 │
└─────────────────────┴─────────────────────────┘

convert_time_zone · replace_time_zone · Available on feature timezone

time_zones_operations = time_zones_df.select(
    [
        pl.col("tz_aware")
        .dt.replace_time_zone("Europe/Brussels")
        .alias("replace time zone"),
        pl.col("tz_aware")
        .dt.convert_time_zone("Asia/Kathmandu")
        .alias("convert time zone"),
        pl.col("tz_aware").dt.replace_time_zone(None).alias("unset time zone"),
    ]
)
print(time_zones_operations)

let time_zones_operations = time_zones_df
    .lazy()
    .select([
        col("tz_aware")
            .dt()
            .replace_time_zone(Some("Europe/Brussels".to_string()), None)
            .alias("replace time zone"),
        col("tz_aware")
            .dt()
            .convert_time_zone("Asia/Kathmandu".to_string())
            .alias("convert time zone"),
        col("tz_aware")
            .dt()
            .replace_time_zone(None, None)
            .alias("unset time zone"),
    ])
    .collect()?;
println!("{}", &time_zones_operations);
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 │
└───────────────────────────────┴──────────────────────────────┴─────────────────────┘