鸿蒙PC适配llvm-gcc-compat编译安装第三方库chrono,打造Rust 第三方日期时间处理库
欢迎加入开源鸿蒙PC社区: https://harmonypc.csdn.net/
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
AtomGit 仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_rust_cargo
本文讲解鸿蒙 PC 端 Rust 开发环境搭建,鸿蒙基于 musl 库、强制二进制签名,无法直接使用通用 Linux 编译产物。需借助鸿蒙专属包管理器 Harmonybrew,提供两套编译方案:方案一安装 llvm-gcc-compat,零配置开箱即用;方案二仅安装 ohos-sdk,需手动配置 Cargo 链接器,二者都依托 ohos-sdk 完成自动签名编译。
可以来参考一下这个文章搭建环境OpenHarmony 鸿蒙 PC + CodeArts IDE 实现 Rust开发完整开发环境搭建指南
一、chrono 是什么
chrono 是 Rust 生态最主流、功能完整的日期时间处理库,替代标准库单薄的 std::time / SystemTime。
标准库时间缺陷:时区支持差、格式化繁琐、缺少日期加减、星期/月份便捷方法、无法简单解析日期字符串;
chrono 完整补齐所有时间业务需求,是 Rust 后端、CLI、数据处理项目标配。
核心作用
- 支持本地时间、UTC时间、带时区时间,时区计算完善
- 日期快速加减:年/月/日/时/分/秒,自动处理月末、闰年边界
- 强大格式化 + 字符串解析,自定义格式模板
- 获取星期、季度、月初月末、年份首尾、时间戳互转
- 时间差值计算(计算相隔几天、几小时)
- 支持序列化(搭配 serde 存JSON/数据库)
- 兼容时间戳:秒、毫秒、微秒、纳秒互相转换
二、安装依赖
1. 新建项目(已有项目跳过)
cargo new chrono_demo
cd chrono_demo
2. 添加 chrono 依赖
# 基础版本(本地/UTC时间,格式化)
cargo add chrono
# 如果需要时区支持(拓展)
cargo add chrono --features clock,timezone
# 如果需要serde序列化(接口/数据库必用)
cargo add chrono --features serde
打开 Cargo.toml 自动生成依赖:
[dependencies]
chrono = { version = "0.4", features = ["clock", "timezone", "serde"] }


三、完整无报错 main.rs 示例
覆盖绝大多数业务场景:当前时间、格式化、解析字符串、日期偏移、时间戳、差值、月初月末、时区、serde序列化
use chrono::{
DateTime, Datelike, Local, Months, NaiveDate, NaiveDateTime, NaiveTime, TimeDelta, Utc,
};
fn main() {
// ===================== 1. 获取当前时间 =====================
println!("===== 1. 当前本地时间 / UTC 时间 =====");
let now_local: DateTime<Local> = Local::now();
let now_utc: DateTime<Utc> = Utc::now();
println!("本地完整时间: {}", now_local);
println!("UTC 标准时间: {}", now_utc);
// 只获取日期/只获取时间(无时区裸时间)
let today: NaiveDate = Local::now().date_naive();
let now_time: NaiveTime = Local::now().time();
println!("今日日期: {}", today);
println!("当前时刻: {}", now_time);
// ===================== 2. 时间格式化 =====================
println!("\n===== 2. 自定义格式化输出 =====");
let fmt_str = "%Y-%m-%d %H:%M:%S";
println!("标准格式: {}", now_local.format(fmt_str));
println!("仅年月日: {}", now_local.format("%Y-%m-%d"));
println!("中文格式: {}", now_local.format("%Y年%m月%d日 %H:%M:%S"));
println!("星期: {}", now_local.format("%A"));
// ===================== 3. 字符串解析成时间 =====================
println!("\n===== 3. 字符串解析为日期时间 =====");
let date_text = "2026-08-15 14:30:00";
match NaiveDateTime::parse_from_str(date_text, fmt_str) {
Ok(dt) => println!("解析成功: {}", dt),
Err(e) => eprintln!("解析失败: {}", e),
}
let day_text = "2026-10-01";
let holiday = NaiveDate::parse_from_str(day_text, "%Y-%m-%d").unwrap();
println!("解析纯日期: {}", holiday);
// ===================== 4. 日期加减 =====================
println!("\n===== 4. 日期偏移 加减年/月/日/时/分 =====");
let tomorrow = today + TimeDelta::days(1);
let last_month = today - TimeDelta::days(30);
let after_2_hour = Local::now() + TimeDelta::hours(2);
println!("明天: {}", tomorrow);
println!("30天前: {}", last_month);
println!("2小时后: {}", after_2_hour.format(fmt_str));
// 按月偏移
let next_month = today.checked_add_months(Months::new(1)).unwrap();
println!("下个月今日: {}", next_month);
// ===================== 5. 时间戳互转 =====================
println!("\n===== 5. 时间戳转换 =====");
let now = Utc::now();
let ts_sec = now.timestamp();
let ts_ms = now.timestamp_millis();
println!("UTC 秒级时间戳: {}", ts_sec);
println!("UTC 毫秒时间戳: {}", ts_ms);
let from_sec = DateTime::from_timestamp(ts_sec, 0).unwrap();
println!("时间戳还原UTC时间: {}", from_sec);
// ===================== 6. 计算两个时间差值 =====================
println!("\n===== 6. 计算时间间隔 =====");
let start = NaiveDate::from_ymd_opt(2026, 1, 1).unwrap();
let end = NaiveDate::from_ymd_opt(2026, 12, 31).unwrap();
let diff = end - start;
println!("2026全年相差天数: {} 天", diff.num_days());
println!("相差小时数: {} h", diff.num_hours());
// ===================== 7. 获取月初、月末 =====================
println!("\n===== 7. 当月第一天 / 当月最后一天 =====");
let current_month_first = today.with_day(1).unwrap();
let next_month_first = current_month_first.checked_add_months(Months::new(1)).unwrap();
let current_month_last = next_month_first - TimeDelta::days(1);
println!("本月一号: {}", current_month_first);
println!("本月最后一天: {}", current_month_last);
}


四、运行
cargo run
chrono 是 Rust 生态最主流、功能最全的日期时间处理库,替代标准库简陋的时间工具,支持时区、格式化、解析、时间偏移、时间戳、日期差值、月初月末等业务常用能力。
前置配置
先在 Cargo.toml 引入依赖(推荐开启本地时区、月份运算功能)
[dependencies]
chrono = { version = "0.4", features = ["local", "months"] }
导入包中核心类型:
use chrono::{
DateTime, Datelike, Local, Months, NaiveDate, NaiveDateTime, NaiveTime, TimeDelta, Utc,
};
先区分核心概念(看懂下面代码的关键)
- 带时区时间:
DateTime<Local>本地时区、DateTime<Utc>UTC零时区,包含时区信息,可直接格式化、转时间戳 - 裸时间(无时区):
NaiveDate:只有年月日,无时分秒、无时区NaiveTime:只有时分秒,无年月日、无时区NaiveDateTime:年月日+时分秒,没有时区,仅存储纯时间数字
TimeDelta:时间间隔,用来做时间加减(天/时/分/秒/毫秒)Months:专门按月偏移(解决2月、大小月天数不一致问题,TimeDelta只能按固定天数偏移)Dateliketrait:提供年月日、星期、当月第几天等日期取值方法
1. 获取当前时间
let now_local: DateTime<Local> = Local::now();
let now_utc: DateTime<Utc> = Utc::now();
println!("本地完整时间: {}", now_local);
println!("UTC 标准时间: {}", now_utc);
// 只提取裸日期 / 裸时刻
let today: NaiveDate = Local::now().date_naive();
let now_time: NaiveTime = Local::now().time();
println!("今日日期: {}", today);
println!("当前时刻: {}", now_time);
详解
Local::now():获取操作系统本地时区当前完整时间(东八区北京时间)Utc::now():获取零时区标准时间,服务器存储时间戳优先用UTC,避免时区混乱.date_naive():从带时区时间中剥离时区,只保留年月日NaiveDate.time():剥离日期,只保留时分秒NaiveTime
输出示例
本地完整时间: 2026-06-18 15:20:30.123456 +08:00
UTC 标准时间: 2026-06-18 07:20:30.123456 UTC
今日日期: 2026-06-18
当前时刻: 15:20:30.123456
2. 时间格式化输出
let fmt_str = "%Y-%m-%d %H:%M:%S";
println!("标准格式: {}", now_local.format(fmt_str));
println!("仅年月日: {}", now_local.format("%Y-%m-%d"));
println!("中文格式: {}", now_local.format("%Y年%m月%d日 %H:%M:%S"));
println!("星期: {}", now_local.format("%A"));
格式化占位符常用对照表
| 占位符 | 含义 | 示例 |
|---|---|---|
%Y |
4位年份 | 2026 |
%m |
两位月份 | 06 |
%d |
两位日期 | 18 |
%H |
24小时制小时 | 15 |
%M |
分钟 | 20 |
%S |
秒 | 30 |
%A |
完整英文星期 | Thursday |
%w |
数字星期(0=周日) | 4 |
说明
.format(模板字符串) 支持带时区 DateTime 和裸时间 NaiveDateTime;可以自由拼接中文,非常适合前端展示、日志打印。
3. 字符串解析成时间
let date_text = "2026-08-15 14:30:00";
match NaiveDateTime::parse_from_str(date_text, fmt_str) {
Ok(dt) => println!("解析成功: {}", dt),
Err(e) => eprintln!("解析失败: {}", e),
}
let day_text = "2026-10-01";
let holiday = NaiveDate::parse_from_str(day_text, "%Y-%m-%d").unwrap();
println!("解析纯日期: {}", holiday);
核心逻辑
parse_from_str(待解析字符串, 格式化模板):模板必须和字符串格式完全匹配,否则返回解析错误。
NaiveDateTime::parse_from_str:解析「年月日 时分秒」完整字符串NaiveDate::parse_from_str:只解析纯日期,不带时分秒
错误处理
返回 Result<T, ParseError>:
match分支:生产环境推荐,优雅处理格式错误.unwrap():测试、确定字符串格式合法时快速取值,格式不对程序直接panic
4. 日期时间加减偏移
4.1 TimeDelta 固定时长偏移(天/时/分/秒)
let tomorrow = today + TimeDelta::days(1);
let last_month = today - TimeDelta::days(30);
let after_2_hour = Local::now() + TimeDelta::hours(2);
println!("明天: {}", tomorrow);
println!("30天前: {}", last_month);
println!("2小时后: {}", after_2_hour.format(fmt_str));
TimeDelta 代表固定时长,支持:
TimeDelta::days(n)天TimeDelta::hours(n)小时TimeDelta::minutes(n)分钟TimeDelta::seconds(n)秒
4.2 Months 按月自然偏移(推荐处理月份)
let next_month = today.checked_add_months(Months::new(1)).unwrap();
println!("下个月今日: {}", next_month);
关键区别(重点)
TimeDelta::days(30):强制固定30天,遇到大小月、2月会出错
例:1月31日 +30天 = 3月2日,不符合“下个月同一天”业务需求checked_add_months(Months::new(1)):自然按月跳转
1月31日 → 2月28/29日,3月31日→4月30日,完美适配日历逻辑
checked_add_months返回Option:月末跨月无对应日期返回None,.unwrap()适合确定合法场景
5. 时间戳互转(前后端交互核心)
let now = Utc::now();
let ts_sec = now.timestamp();
let ts_ms = now.timestamp_millis();
println!("UTC 秒级时间戳: {}", ts_sec);
println!("UTC 毫秒时间戳: {}", ts_ms);
let from_sec = DateTime::from_timestamp(ts_sec, 0).unwrap();
println!("时间戳还原UTC时间: {}", from_sec);
方法说明
.timestamp():输出秒级时间戳(i64),后端接口通用.timestamp_millis():输出毫秒时间戳,前端JS常用DateTime::from_timestamp(秒, 纳秒):秒级时间戳转回带时区UTC时间
第二个参数是纳秒补充,不需要填0即可
最佳实践
数据库存储、接口传输一律使用 UTC时间戳,避免本地时区导致的时差bug。
6. 计算两个时间差值
let start = NaiveDate::from_ymd_opt(2026, 1, 1).unwrap();
let end = NaiveDate::from_ymd_opt(2026, 12, 31).unwrap();
let diff = end - start;
println!("2026全年相差天数: {} 天", diff.num_days());
println!("相差小时数: {} h", diff.num_hours());
流程拆解
NaiveDate::from_ymd_opt(年,月,日):安全构造日期,返回Option<NaiveDate>,非法日期(2月30日)返回None- 两个同类型时间相减,得到
TimeDelta差值对象 - 差值取值方法:
.num_days():总相差天数.num_hours():总相差小时.num_minutes()/.num_seconds():总分钟、总秒数
适用场景
倒计时、活动剩余时长、计算年龄、统计间隔天数。
7. 获取当月第一天、当月最后一天
let current_month_first = today.with_day(1).unwrap();
let next_month_first = current_month_first.checked_add_months(Months::new(1)).unwrap();
let current_month_last = next_month_first - TimeDelta::days(1);
println!("本月一号: {}", current_month_first);
println!("本月最后一天: {}", current_month_last);
逻辑分步拆解
.with_day(1):把当前日期强制改为当月1号,得到本月首日- 本月1号 +1个月 → 下个月1号
- 下个月1号 减1天 → 本月最后一天
优势
自动兼容28/29天2月、31天大月、30天小月,不用手动判断月份天数,报表统计、月度筛选高频使用。
关键类型总结 & 使用建议
什么时候用 Naive(裸时间)
- 只做本地日期计算、报表统计、不需要跨时区传输
- 本地文件存储、仅程序内部计算
什么时候用 DateTime/DateTime
- 和前端、数据库交互、生成时间戳
- 需要格式化展示本地时间、处理时区转换
加减选择
- 固定时长(往后推2小时、7天)→
TimeDelta - 自然月/年(下个月、去年今日)→
Months
安全编码小提示
- 构造日期、月份偏移优先用
xxx_opt+ match 处理None,少用unwrap上线 - 对外接口时间统一用UTC时间戳,避免时区混乱
- 解析用户输入日期必须捕获解析错误,防止非法格式panic
五、核心模块与类型说明
1. 基础时间类型
| 类型 | 含义 | 使用场景 |
|---|---|---|
NaiveDate |
纯日期,无时间、无时区 | 生日、订单创建日 |
NaiveTime |
纯时刻,无日期、无时区 | 固定每日执行时刻 |
NaiveDateTime |
日期+时刻,无时区 | 数据库不带时区存储 |
DateTime<Local> |
带本地时区完整时间 | 展示给前端本地时间 |
DateTime<Utc> |
UTC零时区时间 | 服务统一存储、时间戳 |
2. 关键结构体
TimeDelta:时间差值,days/hours/minutes/secondsMonths:按月偏移,自动适配大小月、闰年
3. 格式化模板常用占位符
%Y4位年份2026%m两位月份01~12%d两位日期01~31%H24小时制00~23%M分钟00~59%S秒%A完整星期名称 Monday%w数字星期 0=周日
六、常用Feature功能说明
- clock(默认开启)
Local::now()/Utc::now()获取系统当前时间,关闭则无法获取实时时间。 - timezone
拓展时区库,支持Asia/Shanghai等完整IANA时区,用于跨国系统。 - serde
实现Serialize/Deserialize,时间结构体直接转JSON,Web后端必备。 - rkyv / sqlx
额外feature适配数据库ORM(sqlx、diesel)直接存取时间字段。
七、典型业务开发场景
- Web后端接口
UTC时间存库,本地时区格式化返回前端,JSON序列化时间 - 定时任务计算
计算下月执行日、每月1号、距离过期剩余天数 - 日志系统
日志打印格式化时间、计算请求耗时(两个时间差值) - 数据库业务
生日、订单创建时间、活动起止时间校验 - 爬虫/数据同步
时间戳转换、按日期分段拉取历史数据
八、优势对比标准库std::time
- 标准库
SystemTime只支持时间戳,无日期、月份、星期操作; - chrono自动处理闰年、2月、月末边界,不用手动判断;
- 统一格式化/解析模板,不用手写复杂转换;
- 原生支持时区,解决前后端时区错乱问题;
- 生态兼容serde、sqlx、axum、rocket等主流框架。
更多推荐

所有评论(0)