Rust 日期时间库 Jiff 发布 1.0 版本
来源标题:Jiff – A datetime library for Rust – reaches 1.0
Rust 日期时间库 Jiff 正式发布 1.0 版本,作者承诺除非发现重大缺陷,将持续保持 1.0 API 稳定。该库将时区处理置于 API 核心以自动应对夏令时等问题,已被 uv、Cargo、Starship、fd、Nushell 等项目采用,并成为 AWS LLRT 中 Temporal 实现的基础。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
Jiff 是一个 Rust 日期时间库,它鼓励你直接踏入成功的坦途。Jiff 将时区处理置于 API 的核心位置,从而自动处理许多与夏令时相关的常见问题。Jiff 已在 Rust 生态系统中获得广泛采用。Jiff 的发音类似于“gif”,但“g”发软音,如同“gem”中的发音。本篇博客通过展示其 API 来宣布 Jiff 1.0 的发布。目标读者:需要便捷日期时间处理的 Rust 程序员。Jiff 已在许多项目的生产环境中使用:uv、Cargo、Starship、fd、Nushell、mise、Jujutsu、uutils/coreutils,甚至作为 AWS LLRT 中 Temporal 实现的基础。是时候称其为 1.0 了。除非在 Jiff 的 API 中发现某些重大缺陷,否则我的计划是无限期地承诺 Jiff 1.0。这一点很重要,因为其意图是让 Jiff 成为出现在其他库公共 API 中的生态系统构建块。这使得 Jiff 成为一个有吸引力的公共依赖项,这意味着 semver 不兼容的版本发布可能会在生态系统中造成显著痛苦。此类发布不会被轻率做出。要查看 Jiff 0.2 与 Jiff 1.0 之间的破坏性变更列表,请查阅 CHANGELOG。
在编程中,日期时间库的核心功能位于计算机系统的时间概念与人类的时间概念的交汇处。系统时间的流行概念是 Unix 时间。人类的时间概念要复杂得多,但最流行的此类模型是公历结合 12 小时制或 24 小时制。每个日期时间库的核心都包含一些在这些概念之间进行转换的例程。日期时间库通常提供的远不止这些。事实上,日期时间处理历来非常困难。我个人的看法是,这种困难源于对领域的建模不佳。许多日期时间库没有将复杂性封装在可复用的代码包中,而是将部分或全部复杂性传递给用户。Jiff 则努力封装复杂性,使用户难以做错事。(Jiff 并非第一个这样做的!)
在博客的这一部分,我们将做一些非常基础的介绍。要跟随博客中的示例,请创建一个新的 Cargo 项目,依赖 jiff 和 anyhow:mkdir jiff-playground cd jiff-playground cargo init --bin cargo add jiff anyhow $EDITOR src/main.rs 大多数示例都是完整的自包含 Rust 程序。只需复制代码并替换 src/main.rs 中的内容。然后运行程序:cargo run
术语 我不愿呈现一本字典。然而,日期时间领域充斥着容易混淆的术语,所以我认为在共享词汇上定位自己很重要。我尽可能保持这一节简短。(某些术语,如“时区”,在此省略,因为它们最好通过后续章节的探索来定义。)TAI 和闰秒不会成为本篇博客的特性,但在此列出它们是为了传达 Unix 时间与 UTC 之间的区别。作为过渡到 Jiff 一些核心类型的方式,我逐渐将其日期时间类型想象成洋葱。按相反顺序,我们可以构建其层次,一直到 ZonedDateTime。所以让我们从更多术语开始,但这一次,它们也是 Jiff 中的类型:
为了更具体一些,我们可以看看这在代码中是什么样子。由于时区可以将民用日期时间映射到时间中的某个瞬间,创建带时区日期时间的一种方式只需要一个民用日期时间和一个时区: use jiff::civil; fn main() -> anyhow::Result<()> { let date = civil::date(2026, 11, 1); let time = civil::time(17, 30, 0, 0); let datetime = date.to_datetime(time); // zdt is an initialism for "ZonedDateTime" let zdt = datetime.in_tz("America/New_York")?; assert_eq!(zdt.timestamp().as_second(), 1793572200); Ok(()) }
创建带时区日期时间的另一种方式只需要一个时间戳和一个时区。这是因为时区也可以将时间戳映射到特定的民用日期时间: use jiff::{civil, Timestamp}; fn main() -> anyhow::Result<()> { let timestamp = Timestamp::from_second(1793572200)?; let zdt = timestamp.in_tz("America/New_York")?; // This is a shortcut for creating a civil datetime. // The previous example spells it out a bit more verbosely // for clarity. let expected = civil::date(2026, 11, 1).at(17, 30, 0, 0); assert_eq!(zdt.datetime(), expected); Ok(()) }
注意,在两种情况下我们都得到了等价的带时区日期时间,但我们是从不同方向达到的。在第一种情况下,我们从可能在时钟和日历上看到的时间开始。在第二种情况下,我们从可能从数据库、文件系统或其他系统调用中获得的特定时间瞬间开始。
带时区日期时间的洋葱示例中缺少一个部分:时区偏移量。偏移量表示为了得到民用时间而必须调整 UTC 时间的量。例如,考虑 UTC 时间 2026-11-01T22:30:00。为了得到居住在纽约的人的民用日期时间,需要减去 5 小时:2026-11-01T22:30:00 - 05:00 = 2026-11-01T17:30:00。事实上,每个带时区日期时间都关联着一个偏移量: use jiff::{civil, tz, Timestamp}; fn main() -> anyhow::Result<()> { let timestamp = Timestamp::from_second(1793572200)?; let zdt = timestamp.in_tz("America/New_York")?; assert_eq!(zdt.offset().seconds(), -(5 * 60 * 60)); let dt = civil::date(2026, 11, 1).at(17, 30, 0, 0); let zdt = dt.in_tz("America/New_York")?; assert_eq!(zdt.offset(), tz::offset(-5)); Ok(()) }
注意:上面示例中看到的 America/New_York 字符串是一个 IANA 时区数据库标识符。IANA 时区数据库是一组时区定义,可以通过一个短
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。