这是 Chrono 时间库中的 traits 模块,定义了日期和时间组件的基本操作接口。
模块概述
该模块包含两个核心 trait:
Datelike- 日期组件的通用方法集合Timelike- 时间组件的通用方法集合
Datelike Trait 解析
基本信息获取方法
rust
pub trait Datelike: Sized {
fn year(&self) -> i32; // 年份 (包含公元前)
fn month(&self) -> u32; // 月份 (1-12)
fn month0(&self) -> u32; // 月份 (0-11)
fn day(&self) -> u32; // 日 (1-31)
fn day0(&self) -> u32; // 日 (0-30)
fn ordinal(&self) -> u32; // 年中日 (1-366)
fn ordinal0(&self) -> u32; // 年中日 (0-365)
fn weekday(&self) -> Weekday; // 星期几
fn iso_week(&self) -> IsoWeek; // ISO 周
}
便捷计算方法
年份处理:
rust
fn year_ce(&self) -> (bool, u32) {
let year = self.year();
if year < 1 { (false, (1 - year) as u32) } else { (true, year as u32) }
}
- 返回
(is_ce, year_number)元组 is_ce: true 表示公元后(CE/AD),false 表示公元前(BCE/BC)
季度计算:
rust
fn quarter(&self) -> u32 {
(self.month() - 1).div_euclid(3) + 1
}
- 返回 1-4 的季度数
日期修改方法
警告:这些方法需要谨慎使用,因为:
- 中间值可能不存在(如 2月29日改为非闰年)
- 不应连续使用多个
with_*方法
rust
fn with_year(&self, year: i32) -> Option<Self>; // 修改年份
fn with_month(&self, month: u32) -> Option<Self>; // 修改月份
fn with_month0(&self, month0: u32) -> Option<Self>; // 修改月份(0-based)
fn with_day(&self, day: u32) -> Option<Self>; // 修改日
fn with_day0(&self, day0: u32) -> Option<Self>; // 修改日(0-based)
fn with_ordinal(&self, ordinal: u32) -> Option<Self>; // 修改年中日
fn with_ordinal0(&self, ordinal0: u32) -> Option<Self>; // 修改年中日(0-based)
错误情况:
- 结果日期不存在(如 2月29日改为非闰年)
- 时区转换问题(对于
DateTime<Tz>) - 数值超出范围
高级日期计算
儒略日计算:
rust
fn num_days_from_ce(&self) -> i32 {
// 计算从公元1年1月1日开始的日数
let mut year = self.year() - 1;
let mut ndays = 0;
// 处理公元前年份
if year < 0 {
let excess = 1 + (-year) / 400;
year += excess * 400;
ndays -= excess * 146_097; // 400年的天数
}
let div_100 = year / 100;
ndays += ((year * 1461) >> 2) - div_100 + (div_100 >> 2);
ndays + self.ordinal() as i32
}
月份天数:
rust
fn num_days_in_month(&self) -> u8 {
use num_traits::FromPrimitive;
let month = Month::from_u32(self.month()).unwrap();
month.num_days(self.year()).unwrap()
}
Timelike Trait 解析
基本信息获取
rust
pub trait Timelike: Sized {
fn hour(&self) -> u32; // 小时 (0-23)
fn minute(&self) -> u32; // 分钟 (0-59)
fn second(&self) -> u32; // 秒 (0-59)
fn nanosecond(&self) -> u32; // 纳秒 (0-1,999,999,999)
}
时间格式转换
12小时制:
rust
fn hour12(&self) -> (bool, u32) {
let hour = self.hour();
let mut hour12 = hour % 12;
if hour12 == 0 { hour12 = 12; } // 0点转为12点
(hour >= 12, hour12) // (is_pm, hour_12)
}
时间修改方法
rust
fn with_hour(&self, hour: u32) -> Option<Self>; // 修改小时
fn with_minute(&self, min: u32) -> Option<Self>; // 修改分钟
fn with_second(&self, sec: u32) -> Option<Self>; // 修改秒
fn with_nanosecond(&self, nano: u32) -> Option<Self>; // 修改纳秒
时间计算
午夜后秒数:
rust
fn num_seconds_from_midnight(&self) -> u32 {
self.hour() * 3600 + self.minute() * 60 + self.second()
}
测试模块
儒略日计算验证
测试中提供了一个替代实现来验证 num_days_from_ce 的正确性:
rust
fn num_days_from_ce<Date: Datelike>(date: &Date) -> i32 {
let year = date.year();
let diff = move |div| in_between(1, year, div);
date.ordinal() as i32 + 365 * diff(1) + diff(4) - diff(100) + diff(400)
}
这个实现更直观地展示了闰年规则:
- 每年365天
- 每4年加1天(闰年)
- 每100年减1天(例外)
- 每400年加1天(例外中的例外)
月份天数测试
验证不同情况下月份天数的正确性:
- 闰年2月:29天
- 平年2月:28天
- 大月:31天
设计特点
- 零基和壹基并存 :提供
month()/month0()等对应方法 - 错误安全 :修改方法返回
Option<Self> - 性能优化:使用位运算和数学优化
- 完整性:支持公元前日期和闰秒
- 实用性:提供常用计算如季度、12小时制等
使用注意事项
- 避免链式修改 :不要连续调用多个
with_*方法 - 理解语义 :
with_year保持月日不变,可能改变序数日 - 时区考虑:对于有时区的日期时间,修改可能涉及时区转换问题
这些 trait 为 Chrono 库提供了统一的日期时间操作接口,确保了类型安全和操作的一致性。