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日期和时间

Download history 18/week @ 2024-03-14 9/week @ 2024-03-28 11/week @ 2024-04-04

65 每月下载量

MIT/Apache

80KB
1.5K SLoC

Assembly 1K SLoC Rust 374 SLoC // 0.1% comments Shell 56 SLoC // 0.0% comments Pan 17 SLoC // 0.2% comments

Crates.io docs.rs Crates.io Crates.io GitHub Workflow Status Maintenance

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 算法翻译而来。这些算法通常在性能上进行了某种优化,但并不快于可用的最快算法。

注意

该库不公开任何类型的 DateDateTime 结构,而只是必要的值的元组。边界检查仅通过 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-2.0许可协议定义的,你有意提交以包含在作品中的任何贡献,应按上述方式双重许可,不附加任何额外条款或条件。

无运行时依赖