sebastienrousseau/dtt
GitHub: sebastienrousseau/dtt
一款注重往返安全性和时区消歧的 Rust 日期时间操作库,提供严格的解析、验证与格式化能力。
Stars: 7 | Forks: 0
DateTime (DTT)
一个符合人体工程学的 Rust 库,用于解析、验证、操作和格式化日期、时间与时区——具有保证的往返安全性和明确的时区代码。
## 目录 - [安装](#install) - [快速开始](#quick-start) - [为什么选择 DTT?](#why-dtt) - [功能](#features) - [支持的时区缩写](#supported-timezone-abbreviations) - [API 概览](#api-highlights) - [开发](#development) - [故障排除](#troubleshooting) - [文档](#documentation) - [贡献](#contributing) - [许可证](#license) ## 安装 ``` cargo add dtt ``` 或者添加到 `Cargo.toml`: ``` [dependencies] dtt = "0.0.11" ``` ### 前置条件 DTT 要求 **Rust 1.88.0 或更高版本**(由 `time = 0.3.47` 锁定,其中包含了针对 `time < 0.3.47` 中 [RUSTSEC 栈耗尽 DoS](https://rustsec.org/) 的上游修复)。 | 平台 | 设置 | |----------|-------| | **macOS** | `brew install rustup-init && rustup-init -y` | | **Linux** | `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \| sh -s -- -y` | | **WSL** | 与 Linux 相同,在你的 WSL 发行版中运行 | | **Windows** | 从 [rustup.rs](https://rustup.rs/) 下载 `rustup-init.exe` | 安装后,使用 `rustc --version` 验证(必须 ≥ 1.88.0)。使用 `rustup update stable` 升级现有工具链。 ## 快速开始 ``` use dtt::prelude::*; fn main() -> Result<(), AppError> { // Current UTC time let now = DateTime::new(); println!("Current time: {}", now); // Parse — strict, offset-required for time-bearing inputs let parsed = DateTime::parse("2024-01-15T10:30:00Z")?; println!("Parsed: {}", parsed); // Round-trip is guaranteed: parse(format(x)) == x let s = parsed.format_rfc3339()?; assert_eq!(parsed, DateTime::parse(&s)?); // Arithmetic let next_week = parsed.add_days(7)?; let next_year = parsed.add_years(1)?; println!("Next week: {next_week}, next year: {next_year}"); // Timezone conversion (note the explicit USA suffix) let est = parsed.convert_to_tz("EST_USA")?; println!("In US Eastern: {est}"); // Validation assert!(DateTime::is_valid_iso_8601("2024-01-15T10:30:00Z")); assert!(!DateTime::is_valid_year("10000")); // outside time crate range Ok(()) } ``` 运行完整演示: ``` cargo run --example dtt ``` ## 为什么选择 DTT? 大多数日期时间库会在令人意想不到的地方默默地产生错误结果。DTT 的设计理念是**大声报错**,而不是进行猜测: - **往返安全性:** `DateTime::parse(&dt.format_rfc3339()?)? == dt` 始终成立。没有默默的纯日期截断。 - **明确的时区:** `IST` 可能表示印度 (+05:30)、爱尔兰 (+01:00) 或以色列 (+02:00)。DTT 要求使用明确的后缀(`IST_INDIA`、`IST_IRELAND`、`IST_ISRAEL`),这样您就不会意外地使用错误的时区。 - **拒绝混合符号的偏移量:** `new_with_custom_offset(5, -30)` 会返回错误,而不是默默地产生 `+05:30`。 - **确定性的 `Default`:** `DateTime::default()` 返回 Unix epoch,而不是本地时钟时间,因此测试是可复现的。 - **UTC 标准化的相等性:** 表示同一时刻的两个 `DateTime` 值比较结果为相等,无论它们是以哪种偏移量存储的。 - **严格验证:** `is_valid_year` 限定在实际的 `time::Date` 范围(`-9999..=9999`)内,因此验证器和构建器始终保持一致。 ## 功能 | | | | :--- | :--- | | **解析** | 带偏移量的 RFC 3339,仅日期的 ISO 8601,自定义格式字符串 | | **格式化** | RFC 3339,自定义格式描述符 | | **验证** | 组件、范围、闰年、ISO 8601、时间字符串 | | **算术运算** | `add_days`、`add_months`、`add_years`(带有溢出检查) | | **比较** | `Eq`、`Ord`、`Hash` — 全部经过 UTC 标准化 | | **日历辅助方法** | `start_of_week`、`end_of_month`、`iso_week`、`iso_year` | | **时区支持** | 22 个已消歧的缩写 + 自定义偏移量 | | **序列化** | 通过规范的 RFC 3339 字符串进行 `serde` 往返 | | **跨平台** | macOS、Linux、WSL、Windows | ## 支持的时区缩写 常见缩写经过了刻意的**消歧义**。像 `EST`、`CST`、`IST` 和 `WADT` 这样的裸代码是**不被接受**的,因为它们在现实世界中指向多个时区。 | 代码 | 偏移量 | 区域 | |------|-------:|--------| | `UTC`、`GMT` | +00:00 | 协调世界时 | | `EST_USA` | −05:00 | 美国东部标准时间 | | `EDT` | −04:00 | 美国东部夏令时 | | `CST_USA` | −06:00 | 美国中部标准时间 | | `CDT` | −05:00 | 美国中部夏令时 | | `MST` / `MDT` | −07/−06 | 美国山区 | | `PST` / `PDT` | −08/−07 | 美国太平洋 | | `CET` / `CEST` | +01/+02 | 中欧 | | `EET` / `EEST` | +02/+03 | 东欧 | | `IST_IRELAND` | +01:00 | 爱尔兰标准时间 | | `IST_ISRAEL` | +02:00 | 以色列标准时间 | | `IST_INDIA` | +05:30 | 印度标准时间 | | `JST` | +09:00 | 日本 | | `HKT` | +08:00 | 香港 | | `CST_CHINA` | +08:00 | 中国标准时间 | | `EST_AUS` / `AEST` | +10:00 | 澳大利亚东部 | | `AEDT` | +11:00 | 澳大利亚东部夏令时 | | `ACWST` | +08:45 | 澳大利亚中西部 | 对于任何其他时区,请使用 [`DateTime::new_with_custom_offset(hours, minutes)`](https://docs.rs/dtt/latest/dtt/datetime/struct.DateTime.html#method.new_with_custom_offset)。 ## API 概览 ### 构造 ``` use dtt::prelude::*; use time::UtcOffset; let now = DateTime::new(); // current UTC let utc = DateTime::new_with_tz("UTC")?; // explicit let mumbai = DateTime::new_with_tz("IST_INDIA")?; // disambiguated let custom = DateTime::new_with_custom_offset(5, 30)?; // +05:30 let exact = DateTime::from_components(2024, 1, 15, 10, 30, 0, UtcOffset::UTC)?; let epoch = DateTime::default(); // 1970-01-01T00:00:00Z // Builder pattern let dt = DateTimeBuilder::new() .year(2024).month(1).day(15) .hour(10).minute(30).second(0) .offset(UtcOffset::UTC) .build()?; # Ok::<(), AppError>(()) ``` ### 解析与格式化 ``` # use dtt::prelude::*; let dt1 = DateTime::parse("2024-01-15T10:30:00Z")?; let dt2 = DateTime::parse("2024-01-15T10:30:00+05:30")?; let dt3 = DateTime::parse("2024-01-15")?; // date-only OK let custom = DateTime::parse_custom_format( "15/01/2024 10:30", "[day]/[month]/[year] [hour]:[minute]", )?; let s: String = dt1.format_rfc3339()?; let pretty = dt1.format("[year]-[month]-[day]")?; # Ok::<(), AppError>(()) ``` ### 算术与日历运算 ``` # use dtt::prelude::*; let dt = DateTime::parse("2024-01-31T00:00:00Z")?; let next_day = dt.next_day()?; let prev_day = dt.previous_day()?; let next_week = dt.add_days(7)?; let next_feb = dt.add_months(1)?; // → 2024-02-29 (leap year aware) let next_year = dt.add_years(1)?; let monday = dt.start_of_week()?; let sunday = dt.end_of_week()?; let last_day = dt.end_of_month()?; # Ok::<(), AppError>(()) ``` ### 宏 ``` use dtt::prelude::*; use dtt::{dtt_now, dtt_parse, dtt_add_days, dtt_diff, dtt_diff_seconds}; let now = dtt_now!(); let dt = dtt_parse!("2024-01-15T10:30:00Z")?; let later = dtt_add_days!(dt, 7)?; let secs: Option标签:Rust, 可视化界面, 开发库, 数据解析, 日期时间处理, 时区转换, 时间格式化, 网络流量审计, 通知系统