如何使用python解析包含毫秒的时间字符串?

262

我可以使用 time.strptime 解析包含日期/时间的字符串。

>>> import time
>>> time.strptime('30/03/09 16:31:32', '%d/%m/%y %H:%M:%S')
(2009, 3, 30, 16, 31, 32, 0, 89, -1)

如何解析包含毫秒的时间字符串?

>>> time.strptime('30/03/09 16:31:32.123', '%d/%m/%y %H:%M:%S')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.5/_strptime.py", line 333, in strptime
    data_string[found.end():])
ValueError: unconverted data remains: .123
8个回答

421

Python 2.6新增了一个名为%f的strftime/strptime宏。文档有点误导,因为它们只提到了微秒,但实际上%f可以解析任何带有最多6位数字的小数秒,这意味着它也适用于毫秒甚至厘秒或分秒。

time.strptime('30/03/09 16:31:32.123', '%d/%m/%y %H:%M:%S.%f')

但是,time.struct_time实际上并不存储毫秒/微秒。你最好使用datetime,像这样:

>>> from datetime import datetime
>>> a = datetime.strptime('30/03/09 16:31:32.123', '%d/%m/%y %H:%M:%S.%f')
>>> a.microsecond
123000

正如您所见,.123 被正确解释为 123 000 微秒。


5
我可以告诉你Python文档需要更新了。time模块的文档没有提到%f - phunehehe
17
Python文档在2.7.3版本中有点误导人。对于strptime,%f实际上可以表示任意数量的小数位数,而不仅仅是像人们可能期望的微秒的6位。因此,上面的代码将解析32.123秒并将其存储为123,000µs,这正是我们想要的。 - Michael Scheper
10
%f 中的数字会在右侧添加零(而不是左侧),直到小数点后有六位数字。数字 1 被解析为 100000,数字 12 被解析为 120000,而数字 1234567 则产生 ValueError: unconverted data remains: 7 的错误信息。 - user443854
28
是我理解错了还是这个问题讨论的是毫秒而不是微秒? - Purrell
4
@Purrell: 这是你的个人情况。我想表达的是 %f 可以用于类似 '23.123' 的字符串。(很抱歉我没有解释一下 123,000µs = 123ms;有时候我会忘记还有一些国家没有采用国际单位制,因此对标准指数前缀不太熟悉。) - Michael Scheper
显示剩余7条评论

12

我知道这是一个比较老的问题,但我仍在使用Python 2.4.3,并且我需要找到一种更好的方法将数据字符串转换为日期时间。

如果datetime不支持%f并且不需要try/except,解决方案如下:

    (dt, mSecs) = row[5].strip().split(".") 
    dt = datetime.datetime(*time.strptime(dt, "%Y-%m-%d %H:%M:%S")[0:6])
    mSeconds = datetime.timedelta(microseconds = int(mSecs))
    fullDateTime = dt + mSeconds 

对于输入字符串"2010-10-06 09:42:52.266000",此方法有效。


1
dt.replace(microsecond=int(mSecs)) - haridsv
这适用于Python 2.5及更早版本。Python 2.6支持strptime '%f'。 - smci

4

为了提供 nstehr's answer 所涉及的代码(来自 它的源代码):

def timeparse(t, format):
    """Parse a time string that might contain fractions of a second.

    Fractional seconds are supported using a fragile, miserable hack.
    Given a time string like '02:03:04.234234' and a format string of
    '%H:%M:%S', time.strptime() will raise a ValueError with this
    message: 'unconverted data remains: .234234'.  If %S is in the
    format string and the ValueError matches as above, a datetime
    object will be created from the part that matches and the
    microseconds in the time string.
    """
    try:
        return datetime.datetime(*time.strptime(t, format)[0:6]).time()
    except ValueError, msg:
        if "%S" in format:
            msg = str(msg)
            mat = re.match(r"unconverted data remains:"
                           " \.([0-9]{1,6})$", msg)
            if mat is not None:
                # fractional seconds are present - this is the style
                # used by datetime's isoformat() method
                frac = "." + mat.group(1)
                t = t[:-len(frac)]
                t = datetime.datetime(*time.strptime(t, format)[0:6])
                microsecond = int(float(frac)*1e6)
                return t.replace(microsecond=microsecond)
            else:
                mat = re.match(r"unconverted data remains:"
                               " \,([0-9]{3,3})$", msg)
                if mat is not None:
                    # fractional seconds are present - this is the style
                    # used by the logging module
                    frac = "." + mat.group(1)
                    t = t[:-len(frac)]
                    t = datetime.datetime(*time.strptime(t, format)[0:6])
                    microsecond = int(float(frac)*1e6)
                    return t.replace(microsecond=microsecond)

        raise

3

上面的DNS回答实际上是错误的。该提问者询问的是毫秒,但回答是针对微秒的。不幸的是,Python没有毫秒的指令,只有微秒(请参见文档),但您可以通过在字符串末尾添加三个零并将其解析为微秒来解决这个问题,例如:

datetime.strptime(time_str + '000', '%d/%m/%y %H:%M:%S.%f')

其中time_str的格式为30/03/09 16:31:32.123

希望这能帮到您。


7
我一开始也是这么想的,但是看了答案下面的评论和文档之后,我发现这里使用的是左侧补零的微秒表示法,所以.123被正确地解释为123,000微秒。 - aschmied

1

我的第一个想法是尝试传递'30/03/09 16:31:32.123'(秒和毫秒之间使用句点而不是冒号)。但那行不通。快速浏览文档表明,在任何情况下都会忽略小数秒...

啊,版本差异。这被报告为错误,现在在2.6+中,您可以使用“%S.%f”来解析它。


那行不通,time.strptime函数根本无法处理毫秒。 - DNS

1

来自Python邮件列表:解析毫秒线程。那里发布了一个函数,似乎可以完成任务,尽管如作者所述它有点“hack”。它使用正则表达式处理引发的异常,然后进行一些计算。

您也可以在传递给strptime之前先处理正则表达式和计算。


是的,我知道那个线程。但是我正在寻找一种更简单的方法。在标准Python库中有没有任何模块可以用毫秒解析时间? - ilkinulas

1
对于Python 2,我做了这个。
print ( time.strftime("%H:%M:%S", time.localtime(time.time())) + "." + str(time.time()).split(".",1)[1])

这段代码打印出时间"%H:%M:%S",将time.time()拆分为两个子字符串(小数点前和小数点后)xxxxxxx.xx。由于.xx是毫秒,我将第二个子字符串添加到我的"%H:%M:%S"中。

希望这样说得通 :) 示例输出:

13:31:21.72 Blink 01


13:31:21.81 结束Blink 01


13:31:26.3 闪烁 01


13:31:26.39 BLINK 01 结束


13:31:34.65 开始第01车道



0
它使用fromisoformat来检测格式,但是挑战在于编写它。
创建一个自定义的格式化程序是我发现的最方便的方法。
from datetime import datetime
import pytz

d = datetime.fromisoformat("2022-08-05 08:47:50.17+00").astimezone(pytz.utc)
print(f"{d.year:04d}-{d.month:02d}-{d.day:02d}T{d.hour:02d}:{d.minute:02d}:{d.second:02d}.{int(d.microsecond/1000):02d}Z")

所以,格式化后的值是:2022-08-05T08:47:50.170Z

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接