如何在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
相关产品推荐
相关产品推荐

