You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Polars中按行指定的时区动态转换时间?

Polars按行指定时区转换时间的优雅实现

问题背景

我尝试用Polars根据每行指定的时区计算对应时间,示例代码如下:

import polars as pl
from datetime import datetime
from polars import col as c

df = pl.DataFrame({
    "time": [datetime(2023, 4, 3, 2), datetime(2023, 4, 4, 3), datetime(2023, 4, 5, 4)],
    "tzone": ["Asia/Tokyo", "America/Chicago", "Europe/Paris"]
}).with_columns(c.time.dt.replace_time_zone("UTC"))

# 单独计算每个时区的方式能得到预期结果,但扩展性差
df.with_columns(
    tokyo=c.time.dt.convert_time_zone("Asia/Tokyo").dt.hour(),
    chicago=c.time.dt.convert_time_zone("America/Chicago").dt.hour(),
    paris=c.time.dt.convert_time_zone("Europe/Paris").dt.hour()
)

这种方式能得到对应每行time在tzone时区的小时数[11, 22, 6],但如果时区种类多,逐个列处理效率低且难以维护。

直接将tzone列传入convert_time_zone会触发类型错误:

df.with_columns(c.time.dt.convert_time_zone(c.tzone).dt.hour())
# TypeError: argument 'time_zone': 'Expr' object cannot be converted to 'PyString'

解决方案

方案1:兼容性强的逐行映射(适配旧版Polars)

使用map_elements实现逐行的时区转换,通过自定义函数处理每行的time和tzone值,代码简洁且扩展性好:

import polars as pl
from datetime import datetime
from polars import col as c

df = pl.DataFrame({
    "time": [datetime(2023, 4, 3, 2), datetime(2023, 4, 4, 3), datetime(2023, 4, 5, 4)],
    "tzone": ["Asia/Tokyo", "America/Chicago", "Europe/Paris"]
}).with_columns(c.time.dt.replace_time_zone("UTC"))

def convert_timezone(time_val, tz_str):
    return time_val.convert_time_zone(tz_str).hour()

result_df = df.with_columns(
    local_hour=c.time.map_elements(convert_timezone, c.tzone, return_dtype=pl.Int32)
)

print(result_df)

方案2:高性能向量化操作(Polars 0.20+)

如果你使用Polars 0.20及以上版本,dt.convert_time_zone已支持直接接收表达式作为时区参数,可直接用向量化操作实现,性能更优:

result_df = df.with_columns(
    local_hour=c.time.dt.convert_time_zone(c.tzone).dt.hour()
)

方案对比

  • 方案1兼容性更好,适合旧版本Polars或需要自定义转换逻辑的场景;
  • 方案2是原生向量化操作,性能更出色,是新版本Polars的首选方案。

内容的提问来源于stack exchange,提问作者Sungmin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:40:30