10 个版本
0.2.1 | 2023年12月20日 |
---|---|
0.2.0 | 2023年10月31日 |
0.1.1 | 2023年9月11日 |
0.0.6 | 2023年9月2日 |
0.0.3 | 2023年5月20日 |
#112 在 日期和时间
65 每月下载量
80KB
1.5K SLoC
datealgo
库的低级日期算法
这个库旨在以一种无偏见的、最高性能的方式提供日期操作算法。它旨在被各种日期和时间库使用,然后为用户提供易于使用且具有意见的接口。
用法
此 crate 对日期库的主要贡献是在 Unix 纪元(1970年1月1日)的日数与格里历日期之间的转换
use datealgo::{rd_to_date, date_to_rd};
assert_eq!(date_to_rd((1970, 1, 1)), 0);
assert_eq!(date_to_rd((2023, 5, 12)), 19489);
assert_eq!(rd_to_date(19489), (2023, 5, 12));
为了方便,还有转换到和从 Unix 时间戳的转换器
use datealgo::{secs_to_datetime, datetime_to_secs};
assert_eq!(datetime_to_secs((1970, 1, 1, 0, 0, 0)), 0);
assert_eq!(datetime_to_secs((2023, 5, 20, 9, 24, 38)), 1684574678);
assert_eq!(secs_to_datetime(1684574678), (2023, 5, 20, 9, 24, 38));
如果启用了 std
功能,还有到和从 SystemTime
的转换器
use datealgo::{systemtime_to_datetime, datetime_to_systemtime};
use std::time::{Duration, UNIX_EPOCH};
assert_eq!(systemtime_to_datetime(UNIX_EPOCH), Some((1970, 1, 1, 0, 0, 0, 0)));
assert_eq!(systemtime_to_datetime(UNIX_EPOCH + Duration::from_secs(1684574678)), Some((2023, 5, 20, 9, 24, 38, 0)));
assert_eq!(datetime_to_systemtime((2023, 5, 20, 9, 24, 38, 0)), UNIX_EPOCH.checked_add(Duration::from_secs(1684574678)));
功能
该 crate 在 no_std
环境中工作,并且没有分配。大多数函数也在常数上下文中工作。
std
(默认):包括SystemTime
转换
背景
由于标准库中没有包含处理日期的任何工具,因此 Rust 有许多针对不同用例的日期和时间库。这些库中的大多数都包含它们自己的日期算法副本,最显著的是从纪元以来的日数到格里历日期(年、月、日)的转换。这些算法来自各种地方,具有各种许可证,通常由机器或手动从不同 libc 变体中找到的 C 算法翻译而来。这些算法通常在性能上进行了某种优化,但并不快于可用的最快算法。
注意
该库不公开任何类型的 Date
或 DateTime
结构,而只是必要的值的元组。边界检查仅通过 debug_assert
进行,这意味着方法在发布版本中保证不会 panic。调用者需要自行进行边界检查。数据类型选择为适合值的最小类型。
当前库实现了普鲁勒克格利高里历法的算法,这是我们的当前历法向后无限延伸。格利高里历法通过定义每四年为闰年(除非该年能被100整除但不能被400整除)来定义平均年为365.2425天。
算法不考虑闰秒,这是Unix时间的惯例。每一天的长度恰好是86400秒,计算的时间不会调整时间戳之间的闰秒。
我们将儒略日定义为从1970年1月1日开始计算的天数,这是Unix纪元。我们使用缩写rd
来简洁地引用这些值。这与Howard Jacobson最初选择的纪元不同,但更方便使用。
出于性能原因,儒略日值以i32
表示。所需的计算将范围减少到大约有效的i30
整数范围,这意味着大约-1,460,000到1,460,000年的可用范围。
基准测试
在Intel(R) Core(TM) i9-10900K CPU @ 3.70GHz上的结果
函数 | datealgo | hinnant | httpdate | humantime | time | chrono |
---|---|---|---|---|---|---|
date_to_rd | 2.1 纳秒 | 3.3 纳秒 | 3.3 纳秒 | 3.6 纳秒 | 15.1 纳秒 | 6.5 纳秒 |
rd_to_date | 3.2 纳秒 | 7.6 纳秒 | 13.5 纳秒 | 13.5 纳秒 | 24.3 纳秒 | 8 纳秒 |
datetime_to_systemtime | 5.1 纳秒 | 8.8 纳秒 | 9 纳秒 | 31.3 纳秒 | 22.8 纳秒 | |
systemtime_to_datetime | 17.8 纳秒 | 28.4 纳秒 | 30.9 纳秒 | 44.1 纳秒 | 98.4 纳秒 |
在现代处理器上获得可靠和可重复的微基准测试非常困难。即使如此,它们的使用也有限,因为周围的代码将决定很多性能方面。这些基准测试并不是要成为权威性的,而是说明算法之间可能存在的相对速度差异。您的结果可能会有所不同,因此请始终对实际用例进行基准测试。
致谢
这个crate基于许多来源的公开算法,但最值得注意的是Cassio Neri。他直接贡献了新型算法,并提供了宝贵的反馈和建议。
- Cassio Neri和Lorenz Schneider:在寻找最佳日期转换方法时,我偶然发现了一篇研究论文,它解释了一种优化性能的新方法。这些算法是根据已发表的论文实现的。没有他们的工作,这个日期转换库的性能将不会是最优的。
- Howard Hinnant:在寻找“永久日历”算法时,我偶然发现了Howard Hinnant的一个非常相似的想法。这个算法既干净又简单,同时保持了出色的性能。
- Rich Felker:原始的musl
__time_to_tm
函数已经广泛传播并被翻译成多种语言,并且仍然是许多独立实现的基础。 - newlib
gmtime_r.c
的许多作者:newlib实现随着时间的推移已经发生了显著的变化,并且现在已根据Howard Hinnant的工作进行了更新。
版本发布
请参阅变更日志
许可证
许可协议之一
- Apache License,版本2.0(LICENSE-APACHE 或 http://www.apache.org/licenses/LICENSE-2.0)
- MIT许可协议(《LICENSE-MIT》 或 http://opensource.org/licenses/MIT)
任选其一。
贡献
除非你明确声明,否则根据Apache-2.0许可协议定义的,你有意提交以包含在作品中的任何贡献,应按上述方式双重许可,不附加任何额外条款或条件。