Chrono
模块概述
这是 Chrono 库的核心时间间隔处理模块,提供了高精度、有符号的时间持续时间处理功能。TimeDelta 类型替代了原有的 Duration 名称,提供更准确的语义表达。
核心架构设计
TimeDelta 结构体定义
pub struct TimeDelta {
secs: i64, // 秒数部分(有符号)
nanos: i32, // 纳秒部分,始终满足 0 <= nanos < NANOS_PER_SEC
}
设计特点:
- 双字段存储:秒数 + 纳秒,避免浮点数精度问题
- 有符号支持:支持正负时间间隔
- 范围限制:纳秒部分严格规范在 0-999,999,999 范围内
范围边界定义
// 最小时间间隔:-i64::MAX 毫秒
pub(crate) const MIN: TimeDelta = TimeDelta {
secs: -i64::MAX / MILLIS_PER_SEC - 1,
nanos: NANOS_PER_SEC + (-i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
};
// 最大时间间隔:i64::MAX 毫秒
pub(crate) const MAX: TimeDelta = TimeDelta {
secs: i64::MAX / MILLIS_PER_SEC,
nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
};
重要设计决策:使用 -i64::MAX 而不是 i64::MIN 作为最小值,这样可以安全地进行绝对值操作而不会溢出。
构造函数系统
安全构造模式
// 基础构造函数 - 返回 Option 进行错误处理
pub const fn new(secs: i64, nanos: u32) -> Option<TimeDelta> {
if secs < MIN.secs
|| secs > MAX.secs
|| nanos >= 1_000_000_000
|| (secs == MAX.secs && nanos > MAX.nanos as u32)
|| (secs == MIN.secs && nanos < MIN.nanos as u32)
{
return None;
}
Some(TimeDelta { secs, nanos: nanos as i32 })
}
时间单位构造器
双重API设计模式:
try_*方法:返回Option<TimeDelta>,用于需要错误处理的场景- 直接方法:panic 在越界时,用于确定不会越界的场景
// 示例:周数构造
pub const fn weeks(weeks: i64) -> TimeDelta {
expect(TimeDelta::try_weeks(weeks), "TimeDelta::weeks out of bounds")
}
pub const fn try_weeks(weeks: i64) -> Option<TimeDelta> {
TimeDelta::try_seconds(try_opt!(weeks.checked_mul(SECS_PER_WEEK)))
}
支持的时间单位:
- 周(weeks)
- 天(days)
- 小时(hours)
- 分钟(minutes)
- 秒(seconds)
- 毫秒(milliseconds)
- 微秒(microseconds)
- 纳秒(nanoseconds)
数值提取方法
整数部分提取
// 提取整周数
pub const fn num_weeks(&self) -> i64 {
self.num_days() / 7
}
// 提取整天数
pub const fn num_days(&self) -> i64 {
self.num_seconds() / SECS_PER_DAY
}
// 核心:提取整秒数(处理负数的纳秒部分)
pub const fn num_seconds(&self) -> i64 {
if self.secs < 0 && self.nanos > 0 {
self.secs + 1
} else {
self.secs
}
}
小数部分提取
// 纳秒小数部分
pub const fn subsec_nanos(&self) -> i32 {
if self.secs < 0 && self.nanos > 0 {
self.nanos - NANOS_PER_SEC
} else {
self.nanos
}
}
// 浮点数表示
pub fn as_seconds_f64(self) -> f64 {
self.secs as f64 + self.nanos as f64 / NANOS_PER_SEC as f64
}
数学运算实现
安全检查的算术运算
// 加法运算
pub const fn checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
let mut secs = self.secs + rhs.secs;
let mut nanos = self.nanos + rhs.nanos;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
secs += 1;
}
TimeDelta::new(secs, nanos as u32)
}
// 乘法运算(使用i128防止溢出)
pub const fn checked_mul(&self, rhs: i32) -> Option<TimeDelta> {
let total_nanos = self.nanos as i64 * rhs as i64;
let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
let secs: i128 = self.secs as i128 * rhs as i128 + extra_secs as i128;
if secs <= i64::MIN as i128 || secs >= i64::MAX as i128 {
return None;
};
Some(TimeDelta { secs: secs as i64, nanos: nanos as i32 })
}
运算符重载
impl Add for TimeDelta {
type Output = TimeDelta;
fn add(self, rhs: TimeDelta) -> TimeDelta {
self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed")
}
}
impl Neg for TimeDelta {
type Output = TimeDelta;
fn neg(self) -> TimeDelta {
let (secs_diff, nanos) = match self.nanos {
0 => (0, 0),
nanos => (1, NANOS_PER_SEC - nanos),
};
TimeDelta { secs: -self.secs - secs_diff, nanos }
}
}
标准库互操作性
与 std::time::Duration 转换
// 从标准库 Duration 转换
pub const fn from_std(duration: Duration) -> Result<TimeDelta, OutOfRangeError> {
if duration.as_secs() > MAX.secs as u64 {
return Err(OutOfRangeError(()));
}
match TimeDelta::new(duration.as_secs() as i64, duration.subsec_nanos()) {
Some(d) => Ok(d),
None => Err(OutOfRangeError(())),
}
}
// 转换为标准库 Duration(仅支持非负值)
pub const fn to_std(&self) -> Result<Duration, OutOfRangeError> {
if self.secs < 0 {
return Err(OutOfRangeError(()));
}
Ok(Duration::new(self.secs as u64, self.nanos as u32))
}
格式化输出
ISO 8601 持续时间格式
impl fmt::Display for TimeDelta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
write!(f, "{sign}P")?;
if abs.secs == 0 && abs.nanos == 0 {
return f.write_str("0D");
}
f.write_fmt(format_args!("T{}", abs.secs))?;
if abs.nanos > 0 {
// 去除尾随零,只显示有效数字
let mut figures = 9usize;
let mut fraction_digits = abs.nanos;
loop {
let div = fraction_digits / 10;
let last_digit = fraction_digits % 10;
if last_digit != 0 { break; }
fraction_digits = div;
figures -= 1;
}
f.write_fmt(format_args!(".{fraction_digits:0figures$}"))?;
}
f.write_str("S")?;
Ok(())
}
}
输出示例:
P0D- 零持续时间PT42S- 42秒PT0.042S- 42毫秒-PT86401S- 负86401秒
特性集成
序列化支持(Serde)
#[cfg(feature = "serde")]
impl Serialize for TimeDelta {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
<(i64, i32) as Serialize>::serialize(&(self.secs, self.nanos), serializer)
}
}
零拷贝序列化(Rkyv)
#[cfg(any(feature = "rkyv", feature = "rkyv-16", ...))]
#[derive(Archive, Deserialize, Serialize)]
pub struct TimeDelta {
secs: i64,
nanos: i32,
}
测试数据生成(Arbitrary)
#[cfg(all(feature = "arbitrary", feature = "std"))]
impl arbitrary::Arbitrary<'_> for TimeDelta {
fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<TimeDelta> {
// 生成在有效范围内的随机 TimeDelta
}
}
错误处理
范围错误类型
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OutOfRangeError(());
impl fmt::Display for OutOfRangeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Source duration value is out of range for the target type")
}
}
工具函数
除法工具函数
#[inline]
const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
(this.div_euclid(other), this.rem_euclid(other))
}
设计哲学总结
- 安全性优先:所有操作都进行边界检查,防止溢出
- 性能优化:使用常量函数,编译时计算
- 类型安全:清晰的错误处理路径
- 互操作性:与标准库和其他序列化框架良好集成
- 用户体验:提供 panic 和非 panic 两种API选择
这个模块为 Rust 提供了工业级的时间间隔处理能力,特别适合需要高精度时间计算和跨平台一致性的应用场景。

被折叠的 条评论
为什么被折叠?



