
本文介绍如何在 Polars 中根据另一列的 UTC 偏移值(如 -4、-5),为字符串日期时间列动态添加时区偏移,生成统一 UTC 时区的 datetime 列,全程使用原生表达式链,避免 map_elements 或逐行迭代。
本文介绍如何在 polars 中根据另一列的 utc 偏移值(如 -4、-5),为字符串日期时间列动态添加时区偏移,生成统一 utc 时区的 datetime 列,全程使用原生表达式链,避免 `map_elements` 或逐行迭代。
在 Polars 中,str.to_datetime() 的 time_zone 参数不支持动态表达式(即不能传入 pl.Expr),因此无法直接通过列值指定不同时区。但我们可以绕过“命名时区”限制,转而采用UTC 基准 + 时间偏移量校正的策略:先将所有时间解析为带 UTC 时区的 datetime,再利用 .dt.offset_by() 按每行的 Timezone 值动态增减小时数。
关键在于理解时区偏移的符号逻辑:
- 若原始时间是 EDT(UTC−4),其字符串 2022-01-01 12:52:23 实际对应 UTC 时间 2022-01-01 16:52:23;
- 即:本地时间 → UTC = 本地时间 + |UTC offset| 小时(因 offset 为负数,加正数等价于减负数);
- 因此需对 Timezone 列取负后构造偏移字符串,例如 -(-4) = +4h。
以下是完整实现:
import polars as pl
df = pl.DataFrame({
"Datetime": ["2022-01-01 12:52:23", "2023-03-31 04:22:59"],
"Timezone": [-4, -5]
})
result = df.with_columns(
pl.col("Datetime")
.str.to_datetime("%Y-%m-%d %H:%M:%S", time_zone="UTC")
.dt.offset_by(pl.format("{}h", -pl.col("Timezone")))
.alias("Datetime") # 覆盖原列,保持结构一致
)
print(result)输出:
shape: (2, 2) ┌─────────────────────────┬──────────┐ │ Datetime ┆ Timezone │ │ --- ┆ --- │ │ datetime[μs, UTC] ┆ i64 │ ╞═════════════════════════╪══════════╡ │ 2022-01-01 16:52:23 UTC ┆ -4 │ │ 2023-03-31 09:22:59 UTC ┆ -5 │ └─────────────────────────┴──────────┘
✅ 优势说明:
- 完全向量化,无 Python 层循环或 map_elements,性能优异;
- 无需外部依赖(如 zoneinfo 或 pytz);
- 输出为标准 datetime[μs, UTC] 类型,兼容后续 .dt 时间运算(如 .dt.hour, .dt.date 等)。
⚠️ 注意事项:
- 此方法将结果统一转为 UTC 时区,不保留原始时区名称(如 "America/New_York"),仅做数值偏移校正;
- 若需最终转换为特定命名时区(如 "US/Eastern"),需额外使用 .dt.convert_time_zone(),但前提是原始时间已正确标注时区——而本例中原始数据无时区信息,故推荐以 UTC 为中间标准;
- pl.format("{}h", ...) 中的单位 h 支持 h(小时)、m(分钟),若 Timezone 列含半小时偏移(如 +5.5),需先转换为分钟整数(pl.col("Timezone") * 60)并使用 {}m 格式。
总结:当 Polars 不支持动态 time_zone 参数时,to_datetime(..., time_zone="UTC").dt.offset_by() 是高效、简洁且符合函数式风格的标准解法。

















