跳转到主要内容

Python的C语言编写的快速ISO8601日期时间解析器

项目描述

https://img.shields.io/circleci/project/github/closeio/ciso8601.svg https://img.shields.io/pypi/v/ciso8601.svg https://img.shields.io/pypi/pyversions/ciso8601.svg

ciso8601ISO 8601RFC 3339 日期时间字符串转换为Python datetime对象。

由于它是作为C模块编写的,因此比其他Python库要快得多。已在cPython 2.7、3.4、3.5、3.6、3.7、3.8、3.9、3.10、3.11、3.12上测试。

(对类似项目感兴趣吗?Close 正在寻找优秀工程师加入我们的团队)

快速入门

% pip install ciso8601
In [1]: import ciso8601

In [2]: ciso8601.parse_datetime('2014-12-05T12:30:45.123456-05:30')
Out[2]: datetime.datetime(2014, 12, 5, 12, 30, 45, 123456, tzinfo=pytz.FixedOffset(330))

In [3]: ciso8601.parse_datetime('20141205T123045')
Out[3]: datetime.datetime(2014, 12, 5, 12, 30, 45)

迁移到v2

《ciso8601》的2.0.0版本改变了核心实现。这并不完全向后兼容,迁移时应谨慎。请参阅变更日志以获取迁移指南。

我不应该使用 ciso8601 的情况

《ciso8601》可能不是每个用例的最佳解决方案(尤其是从Python 3.11开始)。请参阅是否应该使用ciso8601?

错误处理

从v2.0.0版本开始,《ciso8601》在解析字符串方面提供了强大的保证。

parse_datetime(dt: String): datetime 是一个函数,它接受一个字符串并返回

  • 如果整个字符串符合支持ISO 8601子集,则返回正确解析的Python datetime对象

  • 如果字符串不符合支持ISO 8601子集,则引发带有描述原因的 ValueError

如果提供了时区信息,将返回一个带有时区信息的datetime对象。否则,返回一个无时区的datetime对象。

基准测试

解析没有时区信息的戳记(例如,2014-01-09T21:48:00

模块

Python 3.12

Python 3.11

Python 3.10

Python 3.9

相对于ciso8601和最新Python的相对减速

Python 3.8

Python 3.7

Python 2.7

ciso8601

98 nsec

90 nsec

122 nsec

122 nsec

N/A

118 nsec

124 nsec

134 nsec

backports.datetime_fromisoformat

N/A

N/A

112 nsec

108 nsec

0.9x

106 nsec

118 nsec

N/A

datetime (内置)

129 nsec

132 nsec

N/A

N/A

1.3x

N/A

N/A

N/A

pendulum

N/A

180 nsec

187 nsec

186 nsec

2.0x

196 nsec

200 nsec

8.52 usec

udatetime

695 nsec

662 nsec

674 nsec

692 nsec

7.1x

724 nsec

713 nsec

586 nsec

str2date

6.86 usec

5.78 usec

6.59 usec

6.4 usec

70.0x

6.66 usec

6.96 usec

iso8601utils

N/A

N/A

N/A

8.59 usec

70.5x

8.6 usec

9.59 usec

11.2 usec

iso8601

10 usec

8.24 usec

8.96 usec

9.21 usec

102.2x

9.14 usec

9.63 usec

25.7 usec

isodate

11.1 usec

8.76 usec

10.2 usec

9.76 usec

113.6x

9.92 usec

11 usec

44.1 usec

PySO8601

17.2 usec

13.6 usec

16 usec

15.8 usec

175.3x

16.1 usec

17.1 usec

17.7 usec

aniso8601

22.2 usec

17.8 usec

23.2 usec

23.1 usec

227.0x

24.3 usec

27.2 usec

30.7 usec

zulu

23.3 usec

19 usec

22 usec

21.3 usec

237.9x

21.6 usec

22.7 usec

N/A

maya

N/A

36.1 usec

42.5 usec

42.7 usec

401.6x

41.3 usec

44.2 usec

N/A

python-dateutil

57.6 usec

51.4 usec

63.3 usec

62.6 usec

587.7x

63.7 usec

67.3 usec

119 usec

arrow

62 usec

54 usec

65.5 usec

65.7 usec

633.0x

66.6 usec

70.2 usec

78.8 usec

metomi-isodatetime

1.29 msec

1.33 msec

1.76 msec

1.77 msec

13201.1x

1.79 msec

1.91 msec

N/A

moment

1.81 msec

1.65 msec

1.75 msec

1.79 msec

18474.8x

1.78 msec

1.84 msec

N/A

ciso8601 耗时 98 纳秒,比内置的 datetime(datetime)快 1.3 倍,是本比较中 Python 3.12 解析器中速度第二快的。

解析带有时区信息的时间戳(例如,2014-01-09T21:48:00-05:30

模块

Python 3.12

Python 3.11

Python 3.10

Python 3.9

相对于ciso8601和最新Python的相对减速

Python 3.8

Python 3.7

Python 2.7

ciso8601

95 纳秒

96.8 纳秒

128 纳秒

123 纳秒

N/A

125 纳秒

125 纳秒

140 纳秒

backports.datetime_fromisoformat

N/A

N/A

147 纳秒

149 纳秒

1.1 倍

138 纳秒

149 纳秒

N/A

datetime (内置)

198 纳秒

207 纳秒

N/A

N/A

2.1 倍

N/A

N/A

N/A

pendulum

N/A

225 纳秒

214 纳秒

211 纳秒

2.3 倍

219 纳秒

224 纳秒

13.5 微秒

udatetime

799 纳秒

803 纳秒

805 纳秒

830 纳秒

8.4 倍

827 纳秒

805 纳秒

768 纳秒

str2date

7.73 微秒

6.75 微秒

7.78 微秒

7.8 微秒

81.4 倍

7.74 微秒

8.13 微秒

iso8601

13.7 微秒

11.3 微秒

12.7 微秒

12.5 微秒

143.8 倍

12.4 微秒

12.6 微秒

31.1 微秒

isodate

13.7 微秒

11.3 微秒

12.9 微秒

12.7 微秒

144.0 倍

12.7 微秒

13.9 微秒

46.7 微秒

iso8601utils

N/A

N/A

N/A

21.4 微秒

174.9 倍

22.1 微秒

23.4 微秒

28.3 微秒

PySO8601

25.1 微秒

20.4 微秒

23.2 usec

23.8 微秒

263.8 倍

23.5 微秒

24.8 微秒

25.3 微秒

zulu

26.3 微秒

21.4 微秒

25.7 usec

24 微秒

277.2 倍

24.5 微秒

25.3 微秒

N/A

aniso8601

27.7 微秒

23.7 微秒

30.3 微秒

30 微秒

291.3 倍

31.6 微秒

33.8 微秒

39.2 微秒

maya

N/A

36 微秒

41.3 usec

41.8 微秒

372.0 倍

42.4 微秒

42.7 usec

N/A

python-dateutil

70.7 微秒

65.1 微秒

77.9 微秒

80.2 微秒

744.0 倍

79.4 微秒

83.6 微秒

100 微秒

arrow

73 微秒

62.8 微秒

74.5 微秒

73.9 微秒

768.6 倍

75.1 微秒

80 微秒

148 微秒

metomi-isodatetime

1.22 毫秒

1.25 毫秒

1.72 毫秒

1.72 毫秒

12876.3 倍

1.76 msec

1.83 毫秒

N/A

moment

2305822.8 倍

N/A

ciso8601 耗时 95 纳秒,比内置的 datetime(datetime)快 2.1 倍,是本比较中 Python 3.12 解析器中速度第二快的。

在 Linux 5.15.49-linuxkit 上使用以下模块进行测试

aniso8601==9.0.1
arrow==1.3.0 (on Python 3.8, 3.9, 3.10, 3.11, 3.12), arrow==1.2.3 (on Python 3.7), arrow==0.17.0 (on Python 2.7)
backports.datetime_fromisoformat==2.0.1
ciso8601==2.3.0
iso8601==2.1.0 (on Python 3.8, 3.9, 3.10, 3.11, 3.12), iso8601==0.1.16 (on Python 2.7)
iso8601utils==0.1.2
isodate==0.6.1
maya==0.6.1
metomi-isodatetime==1!3.1.0
moment==0.12.1
pendulum==2.1.2
PySO8601==0.2.0
python-dateutil==2.8.2
str2date==0.905
udatetime==0.0.17
zulu==2.0.0

有关完整的基准测试详情(或自行运行基准测试),请参阅 benchmarking/README.rst

支持的ISO 8601子集

ciso8601 只支持 ISO 8601 的一部分,但支持 Python 本身支持的范围之外的部分(datetime.fromisoformat),并支持整个 RFC 3339 规范。

日期格式

以下日期格式受支持

格式

示例

受支持

YYYY-MM-DD(扩展)

2018-04-29

YYYY-MM(扩展)

2018-04

YYYYMMDD(基本)

20180429

YYYY-Www-D(周日期)

2009-W01-1

YYYY-Www(周日期)

2009-W01

YYYYWwwD(周日期)

2009W011

YYYYWww(周日期)

2009W01

YYYY-DDD(序数日期)

1981-095

YYYYDDD(序数日期)

1981095

不受支持的罕见 ISO 8601 日期格式

格式

示例

受支持

--MM-DD(省略年份)

--04-29

--MMDD(省略年份)

--0429

±YYYYY-MM(>4 位年份)

+10000-04

+YYYY-MM(前导+号)

+2018-04

-YYYY-MM(负号-)

-2018-04

时间格式

时间可选,并且通过字母T与日期隔开。

RFC 3339一致,ciso8601也允许使用空格字符或小写的t来代替T

支持以下时间格式

格式

示例

受支持

hh

11

hhmm

1130

hh:mm

11:30

hhmmss

113059

hh:mm:ss

11:30:59

hhmmss.ssssss

113059.123456

hh:mm:ss.ssssss

11:30:59.123456

hhmmss,ssssss

113059,123456

hh:mm:ss,ssssss

11:30:59,123456

午夜(特殊情况)

24:00:00

hh.hhh(分数小时)

11.5

hh:mm.mmm(分数分钟)

11:30.5

注意:Python datetime对象只有微秒精度(6位数字)。任何额外的精度都将被截断。

时区信息

时区信息可以以下格式提供

格式

示例

受支持

Z

Z

z

z

±hh

+11

±hhmm

+1130

±hh:mm

+11:30

虽然ISO 8601规范允许在时区分隔符中使用负号(U+2212),但ciso8601只支持使用连字符减号(U+002D)字符。

RFC 3339一致,ciso8601也允许使用小写的z来代替Z

严格RFC 3339解析

ciso8601解析ISO 8601日期时间,可以将其视为RFC 3339的子集(大致)。在您可能希望严格解析RFC 3339的情况下,ciso8601提供了一个parse_rfc3339方法,其行为与parse_datetime类似。

parse_rfc3339(dt: String): datetime是一个函数,它接受一个字符串并执行以下操作:

  • 如果整个字符串符合RFC 3339,则返回正确解析的Python datetime。

  • 如果字符串不符合RFC 3339,则抛出描述原因的ValueError

解析时忽略时区信息

解析包含时区信息的日期时间戳可能需要更多时间,特别是如果它们不是UTC。然而,有时您可能不关心时区信息,而希望生成无知的日期时间。例如,如果您确信您的程序只会解析来自单个时区的日期时间戳,您可能想删除时区信息,只输出无知的日期时间。

在这些有限的情况下,提供了一个第二个函数。 parse_datetime_as_naive将忽略它找到的任何时区信息,因此对于包含时区信息的日期时间戳来说更快。

In [1]: import ciso8601

In [2]: ciso8601.parse_datetime_as_naive('2014-12-05T12:30:45.123456-05:30')
Out[2]: datetime.datetime(2014, 12, 5, 12, 30, 45, 123456)

注意: parse_datetime_as_naive仅在您的日期时间戳具有时区信息但您想忽略它的情况下才有用。这有点不寻常。如果您的日期时间戳没有时区信息(即无知的),请直接使用parse_datetime。它一样快。

由以下机构支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页