测试数据:
import polars as pl
import pandas as pd
from datetime import date, time, datetime
# polars df for Jan to 12th, March 2022 before DST transition.
tdf = pl.DataFrame(
pl.date_range(
low=date(2022, 1, 3),
high=date(2022, 3, 12),
interval="5m",
time_unit="ns",
time_zone="UTC",
).alias("UTC")
)
我的用例是将 UTC 数据(或不了解时区)转换为 EST/EDT 数据(或了解时区),然后在时间范围(9:30 到 16:00)上过滤数据。
tz_replaced_filtered = tdf.with_columns(
pl.col("UTC").dt.replace_time_zone(time_zone="US/Eastern").alias("NY")
).filter(
pl.col("NY").cast(pl.Time).is_between(time(9), time(16), closed="both")
)
# output
shape: (5780, 2)
┌─────────────────────────┬──────────────────────────┐
│ UTC ┆ NY │
│ --- ┆ --- │
│ datetime[ns, UTC] ┆ datetime[ns, US/Eastern] │
╞═════════════════════════╪══════════════════════════╡
│ 2022-01-03 04:00:00 UTC ┆ 2022-01-03 04:00:00 EST │
│ 2022-01-03 04:05:00 UTC ┆ 2022-01-03 04:05:00 EST │
│ 2022-01-03 04:10:00 UTC ┆ 2022-01-03 04:10:00 EST │
│ 2022-01-03 04:15:00 UTC ┆ 2022-01-03 04:15:00 EST │
│ … ┆ … │
│ 2022-03-11 10:45:00 UTC ┆ 2022-03-11 10:45:00 EST │
│ 2022-03-11 10:50:00 UTC ┆ 2022-03-11 10:50:00 EST │
│ 2022-03-11 10:55:00 UTC ┆ 2022-03-11 10:55:00 EST │
│ 2022-03-11 11:00:00 UTC ┆ 2022-03-11 11:00:00 EST │
└─────────────────────────┴──────────────────────────┘
显然这个结果中没有明显的 9 到 16 时间范围df
.
我进一步探究:
tz_replaced_filtered.with_columns(
pl.col("NY").cast(pl.Time).alias("NY_TIME"),
pl.col("UTC").cast(pl.Time).alias("UTC_TIME")
)
# output
shape: (5780, 4)
┌─────────────────────────┬──────────────────────────┬──────────┬──────────┐
│ UTC ┆ NY ┆ NY_TIME ┆ UTC_TIME │
│ --- ┆ --- ┆ --- ┆ --- │
│ datetime[ns, UTC] ┆ datetime[ns, US/Eastern] ┆ time ┆ time │
╞═════════════════════════╪══════════════════════════╪══════════╪══════════╡
│ 2022-01-03 04:00:00 UTC ┆ 2022-01-03 04:00:00 EST ┆ 09:00:00 ┆ 04:00:00 │
│ 2022-01-03 04:05:00 UTC ┆ 2022-01-03 04:05:00 EST ┆ 09:05:00 ┆ 04:05:00 │
│ 2022-01-03 04:10:00 UTC ┆ 2022-01-03 04:10:00 EST ┆ 09:10:00 ┆ 04:10:00 │
│ 2022-01-03 04:15:00 UTC ┆ 2022-01-03 04:15:00 EST ┆ 09:15:00 ┆ 04:15:00 │
│ … ┆ … ┆ … ┆ … │
│ 2022-03-11 10:45:00 UTC ┆ 2022-03-11 10:45:00 EST ┆ 15:45:00 ┆ 10:45:00 │
│ 2022-03-11 10:50:00 UTC ┆ 2022-03-11 10:50:00 EST ┆ 15:50:00 ┆ 10:50:00 │
│ 2022-03-11 10:55:00 UTC ┆ 2022-03-11 10:55:00 EST ┆ 15:55:00 ┆ 10:55:00 │
│ 2022-03-11 11:00:00 UTC ┆ 2022-03-11 11:00:00 EST ┆ 16:00:00 ┆ 11:00:00 │
└─────────────────────────┴──────────────────────────┴──────────┴──────────┘
底层时间戳似乎确实表明我成功地在时间范围 9 到 16 上进行了过滤;这只是不同步的字符串表示形式。
tdf.with_columns(
pl.col("UTC").dt.replace_time_zone(time_zone="US/Eastern").alias("NY_REPLACED"),
pl.col("UTC").dt.convert_time_zone(time_zone="US/Eastern").alias("NY_CONVERTED")
)
# output
shape: (19585, 3)
┌─────────────────────────┬──────────────────────────┬──────────────────────────┐
│ UTC ┆ NY_REPLACED ┆ NY_CONVERTED │
│ --- ┆ --- ┆ --- │
│ datetime[ns, UTC] ┆ datetime[ns, US/Eastern] ┆ datetime[ns, US/Eastern] │
╞═════════════════════════╪══════════════════════════╪══════════════════════════╡
│ 2022-01-03 00:00:00 UTC ┆ 2022-01-03 00:00:00 EST ┆ 2022-01-02 19:00:00 EST │
│ 2022-01-03 00:05:00 UTC ┆ 2022-01-03 00:05:00 EST ┆ 2022-01-02 19:05:00 EST │
│ 2022-01-03 00:10:00 UTC ┆ 2022-01-03 00:10:00 EST ┆ 2022-01-02 19:10:00 EST │
│ 2022-01-03 00:15:00 UTC ┆ 2022-01-03 00:15:00 EST ┆ 2022-01-02 19:15:00 EST │
│ … ┆ … ┆ … │
│ 2022-03-11 23:45:00 UTC ┆ 2022-03-11 23:45:00 EST ┆ 2022-03-11 18:45:00 EST │
│ 2022-03-11 23:50:00 UTC ┆ 2022-03-11 23:50:00 EST ┆ 2022-03-11 18:50:00 EST │
│ 2022-03-11 23:55:00 UTC ┆ 2022-03-11 23:55:00 EST ┆ 2022-03-11 18:55:00 EST │
│ 2022-03-12 00:00:00 UTC ┆ 2022-03-12 00:00:00 EST ┆ 2022-03-11 19:00:00 EST │
└─────────────────────────┴──────────────────────────┴──────────────────────────┘
最后一步的结论是replaced_time_zone
and convert_time_zone
不会为相同的时区转换操作生成相同的字符串表示形式。
进一步来说,replaced_time_zone
确实替换了底层时间戳,但它不会“替换”字符串表示形式;什么replaced_time_zone
表面上对于 UTC(或者只是不知道时区的时间戳)来说就像with_time_zone
,即简单地将时区信息附加到现有时间戳上。
如果有人能澄清上述问题,我将不胜感激。
问题背景
这是针对 Polars 用户和开发人员的,以便我提出的所有与时区转换相关的问题polars
可以方便地参考。
我首先提出this https://stackoverflow.com/questions/74165901/polars-add-substract-utc-offset-from-datetime-object看看我们如何根据转换后的时间戳(考虑 utc 偏移量)进行过滤,然后polars
假如replace_time_zone
a question https://stackoverflow.com/questions/75793219/polars-replace-time-zone-function-throws-error-of-no-such-local-time因为它也被提高了。
@FObersteiner 提到的一个相关问题是here https://stackoverflow.com/questions/75268283/how-to-truncate-a-datetime-to-just-the-day.
暂时我的理解是replace_time_zone
应该提供相同的字符串表示形式convert_time_zone
,因为本质上他们所做的事情是相同的。这将使过滤日期/时间范围polars
WYSIWYG(所见即所得)。
背景资料
Polars
提供replace_time_zone
and convert_time_zone
来处理这样的场景。
convert_time_zone
仅更改呈现给用户的字符串表示形式,而不更改底层时间戳。所以cast
在我的用例中,它不适用于“转换后的”时间戳(过滤仍然在原始的底层时间戳上)。
关于replace_time_zone
, DST 转换导致problem https://stackoverflow.com/questions/75793219/polars-replace-time-zone-function-throws-error-of-no-such-local-time当用户尝试replace_time_zone
鉴于由于 DST 转换而导致特定时间戳不存在,这个问题似乎是普遍存在的:
# demo polars df
tpl = pl.DataFrame(
pl.date_range(
low=date(2022, 3, 13),
high=date(2022, 3, 15),
interval="5m",
time_unit="ns",
time_zone="UTC",
).alias("UTC")
)
tpl.select(
pl.col("UTC").dt.replace_time_zone(time_zone="America/New_York").alias("NY")
)
# Panic Exception: no such local time
# demo pandas pf
tpn = pd.DataFrame(
pd.date_range(start="2022-03-13",
end="2022-03-15",
freq="5T", # 5 minute interval
tz=None, # default to UTC
inclusive="both"),
columns=["UTC"]
)
tpn.UTC.dt.tz_localize("America/New_York")
# NonExistentTimeError: 2022-03-13 02:00:00