我想在极性的datetime对象中添加/减去UTC
偏移量(通常以小时为单位),但我似乎找不到这样做的方法。世界协调时的抵消可以是动态的,因为有一个日历年度的日照节约期发挥作用。(例如,EST/EDT分别映射到UTC
偏移的5/4小时)。
from datetime import datetime
import pytz
import polars as pl
from datetime import date
# Make a datetime-only dataframe that covers DST period of year, in UTC time first.
df = pl.DataFrame(
pl.date_range(low=date(2022,1,3),
high=date(2022,9,30),
interval="5m",
time_unit="ns",
time_zone="UTC")
.alias("timestamp")
)
# Convert timezone to "America/New_York", which covers both EST and EDT.
us_df = df.with_column(
pl.col("timestamp")
.dt
.cast_time_zone(tz="America/New_York")
.alias("datetime")
)
# Check us_df output
us_df
# output, here `polars` is showing US time without the UTC offset
# Before 0.14.22 `polars` is showing time with UTC offset
# i.e., `23:45:00 UTC` should be `19:45:00 EDT`
# Now `polars` is showing `15:45:00 EDT`, without 4 hours of offset
┌─────────────────────────┬────────────────────────────────┐
│ timestamp ┆ datetime │
│ --- ┆ --- │
│ datetime[ns, UTC] ┆ datetime[ns, America/New_York] │
╞═════════════════════════╪════════════════════════════════╡
│ 2022-01-03 00:00:00 UTC ┆ 2022-01-02 14:00:00 EST │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-01-03 00:05:00 UTC ┆ 2022-01-02 14:05:00 EST │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-01-03 00:10:00 UTC ┆ 2022-01-02 14:10:00 EST │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-01-03 00:15:00 UTC ┆ 2022-01-02 14:15:00 EST │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ ... ┆ ... │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-09-29 23:45:00 UTC ┆ 2022-09-29 15:45:00 EDT │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-09-29 23:50:00 UTC ┆ 2022-09-29 15:50:00 EDT │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-09-29 23:55:00 UTC ┆ 2022-09-29 15:55:00 EDT │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-09-30 00:00:00 UTC ┆ 2022-09-29 16:00:00 EDT │
└─────────────────────────┴────────────────────────────────┘
转换to_pandas
时,我们应该注意到底层的datetime
对象不包括实际时间中的4小时偏移量(请记住,EST也在这个数据中,并且它有一个5小时的偏移量)。
# Convert to pandas
us_pd = us_df.to_pandas()
us_pd
# output
timestamp datetime
0 2022-01-03 00:00:00+00:00 2022-01-02 14:00:00-05:00
1 2022-01-03 00:05:00+00:00 2022-01-02 14:05:00-05:00
2 2022-01-03 00:10:00+00:00 2022-01-02 14:10:00-05:00
3 2022-01-03 00:15:00+00:00 2022-01-02 14:15:00-05:00
4 2022-01-03 00:20:00+00:00 2022-01-02 14:20:00-05:00
... ... ...
77756 2022-09-29 23:40:00+00:00 2022-09-29 15:40:00-04:00
77757 2022-09-29 23:45:00+00:00 2022-09-29 15:45:00-04:00
77758 2022-09-29 23:50:00+00:00 2022-09-29 15:50:00-04:00
77759 2022-09-29 23:55:00+00:00 2022-09-29 15:55:00-04:00
77760 2022-09-30 00:00:00+00:00 2022-09-29 16:00:00-04:00
我想要的是将UTC
偏移量包含到实际时间中,这样我就可以(以自然的方式)对时间进行过滤。例如,如果我看到2300 use是1900 DST,我可以直接使用1900使用过滤器(请注意,我不能在过滤期间动态地添加/减UTC
偏移量,因为给定DST的小时数是一个动态变量)。
底层的python datetime
确实有utcoffset
函数,它可以应用于每个datetime对象,但是我需要首先将polars
转换为pandas
(我不知道如何在polars
中这样做)。
我还观察到了这种奇特的差别:
us_pd.datetime[us_pd.shape[0]-1].to_pydatetime()
# We can see it is identical to what's already in `polars` and `pandas` dataframe.
datetime.datetime(2022, 9, 29, 16, 0, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
# Now we create a single datetime object with arbitrary UTC time and convert it to New York time
datetime(2022, 9, 30, 22, 45, 0,0, pytz.utc).astimezone(pytz.timezone("America/New_York"))
# The representation here is actually the correct New York time (as in, the offset has been included)
datetime.datetime(2022, 9, 30, 18, 45, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
发布于 2022-10-23 10:03:01
看来你在找with_time_zone
;
from datetime import date
import polars as pl
df = pl.DataFrame(
pl.date_range(
low=date(2022, 1, 3),
high=date(2022, 9, 30),
interval="5m",
time_unit="ns",
time_zone="UTC",
).alias("timestamp")
)
us_df = df.with_column(
pl.col("timestamp").dt.with_time_zone(tz="America/New_York").alias("datetime")
)
us_df
shape: (77761, 2)
┌─────────────────────────┬────────────────────────────────┐
│ timestamp ┆ datetime │
│ --- ┆ --- │
│ datetime[ns, UTC] ┆ datetime[ns, America/New_York] │
╞═════════════════════════╪════════════════════════════════╡
│ 2022-01-03 00:00:00 UTC ┆ 2022-01-02 19:00:00 EST │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-01-03 00:05:00 UTC ┆ 2022-01-02 19:05:00 EST │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-01-03 00:10:00 UTC ┆ 2022-01-02 19:10:00 EST │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-01-03 00:15:00 UTC ┆ 2022-01-02 19:15:00 EST │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ ... ┆ ... │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-09-29 23:45:00 UTC ┆ 2022-09-29 19:45:00 EDT │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-09-29 23:50:00 UTC ┆ 2022-09-29 19:50:00 EDT │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-09-29 23:55:00 UTC ┆ 2022-09-29 19:55:00 EDT │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-09-30 00:00:00 UTC ┆ 2022-09-29 20:00:00 EDT │
└─────────────────────────┴────────────────────────────────┘
固执己见的在Polarsv0.14.22中,医生们似乎在这个话题上有点稀疏。with_time_zone
不应该修改时间戳,而cast_time_zone
应该修改时间戳。鉴于这里显示的结果,我对此感到困惑。极地开发人员通过“(而不是)修改时间戳”来理解什么?使用像熊猫的tz_localize和tz_convert这样的东西可能会更直观一些(设置和转换tz)。
发布于 2022-10-27 17:18:50
问得好。
如果你想要快速回答
df = (
pl.DataFrame(
pl.date_range(low=date(2022,2,3),
high=date(2022,5,30),
interval="1mo",
)
.alias("utc")
)
.with_column(
pl.col("utc").cast(pl.Datetime)
)
.with_columns(
[
pl.col("utc").dt.with_time_zone("UTC"),
pl.col("utc").dt.with_time_zone("America/New_York").alias("nyc")
]
)
.with_column(
(pl.col("utc") - pl.col("nyc").dt.cast_time_zone("UTC")).alias("diff")
)
)
shape: (4, 3)
┌─────────────────────────┬────────────────────────────────┬──────────────┐
│ utc ┆ nyc ┆ diff │
│ --- ┆ --- ┆ --- │
│ datetime[μs, UTC] ┆ datetime[μs, America/New_York] ┆ duration[μs] │
╞═════════════════════════╪════════════════════════════════╪══════════════╡
│ 2022-02-03 00:00:00 UTC ┆ 2022-02-02 19:00:00 EST ┆ -5h │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-03-03 00:00:00 UTC ┆ 2022-03-02 19:00:00 EST ┆ -5h │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-04-03 00:00:00 UTC ┆ 2022-04-02 20:00:00 EDT ┆ -4h │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-05-03 00:00:00 UTC ┆ 2022-05-02 20:00:00 EDT ┆ -4h │
└─────────────────────────┴────────────────────────────────┴──────────────┘
我认为通过一些基础知识来充分理解这一点是有帮助的。
我把日期范围改为每月一次,这样就更容易理解了。
首先,我们创建一个日期时间范围,并给它一个UTC时区:
from datetime import datetime
import pytz
import polars as pl
from datetime import date
df = (
pl.DataFrame(
pl.date_range(low=date(2022,2,3),
high=date(2022,5,30),
interval="1mo",
)
.alias("utc")
)
.with_column(
pl.col("utc").cast(pl.Datetime)
)
.with_column(
pl.col("utc").dt.with_time_zone("UTC")
)
)
shape: (4, 1)
┌─────────────────────────┐
│ utc │
│ --- │
│ datetime[μs, UTC] │
╞═════════════════════════╡
│ 2022-02-03 00:00:00 UTC │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-03-03 00:00:00 UTC │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-04-03 00:00:00 UTC │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2022-05-03 00:00:00 UTC │
└─────────────────────────┘
日期时间列是什么?简单地说,我们可以把它看作是从底层整数表示到日期时间字符串的映射。
当我们使用with_time_zone
设置时区时,我们告诉极性调整映射,以便相同整数映射到不同的日期时间字符串。在UTC的情况下,字符串中唯一的区别是我们将UTC添加到末尾。
如果我们想得到两个时区之间的时间差,我们可以使用cast_time_zone
。这个函数告诉极地
但是,由于我们已经更改了整数表示形式,所以字符串表示也必须更新。因此,在UTC上面的时间戳列中,第一行有一个用于午夜的字符串。在datetime列中,在EST 14:00之前有一个字符串,用于10小时--因为整数表示已经减少了5小时,加上EST比UTC晚了5小时!
尽管如此,您在正确的轨道上使用cast_time_zone
-整数表示已经改变了之间的时区偏移量。但是,当您查看其字符串表示形式中的输出时,这是没有直接意义的!
因此,为了在协调世界时和纽约之间的几个小时内得到抵消,我们:
为了清晰起见,我已经在下面的中间步骤中完成了它,您可以在一个表达式中完成所有操作。
# Cast timezone to "America/New_York", which covers both EST and EDT.
us_df = (
# Cast UTC to NYC to get the offset in the integer representation
df.with_column(
pl.col("utc")
.dt
.cast_time_zone(tz="America/New_York")
.alias("nyc")
)
# Add columns that display the integer representations
.with_column(
pl.all().to_physical().suffix("_physical")
)
# Subtract the integer representations to get the offset in hours
.with_column(
((pl.col("utc_physical") - pl.col("nyc_physical"))/(3600*1e6)).alias("diff_in_hours")
)
shape: (4, 5)
┌─────────────────────────┬───────────────────────────┬──────────────────┬──────────────────┬──────┐
│ utc ┆ nyc ┆ utc_phys ┆ nyc_phys ┆ diff │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ datetime[μs, UTC] ┆ datetime[μs, ┆ i64 ┆ i64 ┆ f64 │
│ ┆ America/New_York] ┆ ┆ ┆ │
╞═════════════════════════╪═══════════════════════════╪══════════════════╪══════════════════╪══════╡
│ 2022-02-03 00:00:00 UTC ┆ 2022-02-02 14:00:00 EST ┆ 1643846400000000 ┆ 1643828400000000 ┆ 5.0 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2022-03-03 00:00:00 UTC ┆ 2022-03-02 14:00:00 EST ┆ 1646265600000000 ┆ 1646247600000000 ┆ 5.0 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2022-04-03 00:00:00 UTC ┆ 2022-04-02 16:00:00 EDT ┆ 1648944000000000 ┆ 1648929600000000 ┆ 4.0 │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌┤
│ 2022-05-03 00:00:00 UTC ┆ 2022-05-02 16:00:00 EDT ┆ 1651536000000000 ┆ 1651521600000000 ┆ 4.0 │
└─────────────────────────┴───────────────────────────┴──────────────────┴──────────────────┴──────
https://stackoverflow.com/questions/74165901
复制相似问题