持续时间字符串的 strptime() 转换出现问题

问题描述 投票:0回答:2

我有一些无法使用

strptime
转换的持续时间类型数据(单圈时间),而常规日期时间按预期工作。 在 df 中读取的示例(类型
str
/
pl.Utf8
):

["01:14.007", "01:18.880", ...] 

分钟(在 : 之前)和秒(在 . 之前)always 填充到两位数,毫秒是 always 3 位数字。

df = df.with_columns(
    [
        pl.col('release_date').str.strptime(pl.Date, fmt="%B %d, %Y"), # works
        pl.col('lap_time').str.strptime(pl.Time, fmt="%M:%S.%3f").cast(pl.Duration), # fails
    ]
)

所以我使用了

https://docs.rs/chrono/latest/chrono/format/strftime/index.html
中的chrono格式说明符定义,它根据
polars
strptime

文档使用

第二次转换(对于

lap_time
)总是失败,无论我是否使用
.%f
.%3f
%.3f
。显然,
strptime
不允许直接创建
pl.Duration
,所以我尝试使用
pl.Time
但它失败并显示错误:

ComputeError: strict conversion to dates failed, maybe set strict=False

但是设置 strict=False 会产生整个系列的所有

null
值。

我是否遗漏了某些东西或

chrono
python-polars
部分的一些奇怪行为?

编辑:根据已接受的答案改编的解决方案

df = df.with_columns(
    [
        pl.col('release_date').str.strptime(pl.Date, fmt="%B %d, %Y"),
        pl.duration(
            minutes=pl.col("lap_time").str.slice(0,2),
            seconds=pl.col("lap_time").str.slice(3,2),
            milliseconds=pl.col("lap_time").str.slice(6,3)
        ).alias('lap_time'),
    ]
)
datetime duration python-polars rust-chrono
2个回答
3
投票

您不能在没有指定时间的情况下使用

pl.Time
。当您将
00
小时添加到您的时间时,代码将起作用:

df = pl.DataFrame({"str_time": ["01:14.007", "01:18.880"]})

df.with_columns(
    duration = (pl.lit("00:") + pl.col("str_time"))\
        .str.strptime(pl.Time, fmt="%T%.3f")\
        .cast(pl.Duration)
)
┌───────────┬──────────────┐
│ str_time  ┆ duration     │
│ ---       ┆ ---          │
│ str       ┆ duration[μs] │
╞═══════════╪══════════════╡
│ 01:14.007 ┆ 1m 14s 7ms   │
│ 01:18.880 ┆ 1m 18s 880ms │
└───────────┴──────────────┘

一般情况

如果您的 duration 可能超过 24 小时,您可以使用 regex 模式从字符串中提取数据(分钟、秒等):

df = pl.DataFrame({
    "time": ["+01:14.007", "100:20.000", "-05:00.000"]
})

df.with_columns(
    pl.col("time").str.extract_all(r"([+-]?\d+)")
    #                                /
    #                 you will get array of length 3
    #                 ["min", "sec", "ms"]
).with_columns(
    pl.duration(
        minutes=pl.col("time").arr.get(0),
        seconds=pl.col("time").arr.get(1),
        milliseconds=pl.col("time").arr.get(2)
    ).alias("time")
)
┌──────────────┐
│ time         │
│ ---          │
│ duration[ns] │
╞══════════════╡
│ 1m 14s 7ms   │
│ 1h 40m 20s   │
│ -5m          │
└──────────────┘

1
投票

Create your own parser -

strptime
仅适用于日期时间戳,不适用于时间增量。接受的答案是不好的做法,因为它无法用于合理的输入,例如 80 分钟的持续时间或负持续时间。

您可以使用

pl.Series.str.extract()
制作自己的正则表达式解析器,并在将它们传递给
Duration
构造函数之前提取所需的值。

据我所知,Rust 中没有“持续时间戳”解析器。如果有人正在阅读这篇文章,也许是一个板条箱的好主意。语法可能类似于

strptime
但处理以下情况:负持续时间,最重要的“数字”/子单元不换行,在这种情况下,它是“分钟持续时间戳”,您将在 60 秒而不是分钟换行。特别是确保 61 仍然是 61.

© www.soinside.com 2019 - 2024. All rights reserved.