Text and timestamps arrive messy in every dataset; parsing and cleaning them vectorized is a daily task.
Type-specific methods live in namespaces on expressions.
The str namespace: len_chars(), to_lowercase(), strip_chars(), contains(pattern), replace(pattern, value) (first match) and replace_all, extract(pattern, group), split(",") (returns a list), slice(offset, length), starts_with(). Patterns are regular expressions unless you pass literal=True.
Parsing text into time types uses the str namespace: str.to_date("%d/%m/%Y"), str.to_datetime(...), str.to_time(...). In Polars 2, cast(pl.Date) on a string column raises, so always parse explicitly. strict=False turns unparseable values into null instead of failing.
The dt namespace works on Date, Datetime and Duration: year(), month(), weekday() (Monday = 1), truncate("1mo"), offset_by("2d"), strftime(fmt), total_days(), plus convert_time_zone() and replace_time_zone() for zone-aware datetimes. Subtracting two dates gives a Duration.
General conversions use cast: pl.col("x").cast(pl.Int32). A failing cast raises by default; cast(..., strict=False) gives null instead. Shrinking ints and using pl.Categorical or pl.Enum for repeated strings saves memory.
Example
import polars as pl
df = pl.DataFrame({
"raw": [" Oslo-2026/03/01 ", "lima-2026/12/24", "rome-bad"],
"qty": ["3", "x", "5"],
})
out = df.select(
city=pl.col("raw").str.strip_chars().str.extract(r"^(\w+)-", 1)
.str.to_titlecase(),
day=pl.col("raw").str.extract(r"(\d{4}/\d{2}/\d{2})", 1)
.str.to_date("%Y/%m/%d", strict=False),
qty=pl.col("qty").cast(pl.Int64, strict=False),
).with_columns(
month=pl.col("day").dt.month(),
weekday=pl.col("day").dt.weekday(),
)
print(out.rows())
# [('Oslo', datetime.date(2026, 3, 1), 3, 3, 7),
# ('Lima', datetime.date(2026, 12, 24), None, 12, 4),
# ('Rome', None, 5, None, None)]Remember
stranddtnamespaces give vectorized text and time methods- Parse with
str.to_date/to_datetime; Polars 2 won't cast strings to dates strict=Falseturns bad values into null instead of raising
Watch out for
- Expecting
str.replaceto replace every match: it replaces the first; usereplace_all.