欢迎加入开源鸿蒙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、数据处理项目标配。

核心作用

  1. 支持本地时间、UTC时间、带时区时间,时区计算完善
  2. 日期快速加减:年/月/日/时/分/秒,自动处理月末、闰年边界
  3. 强大格式化 + 字符串解析,自定义格式模板
  4. 获取星期、季度、月初月末、年份首尾、时间戳互转
  5. 时间差值计算(计算相隔几天、几小时)
  6. 支持序列化(搭配 serde 存JSON/数据库)
  7. 兼容时间戳:秒、毫秒、微秒、纳秒互相转换

二、安装依赖

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,
};

先区分核心概念(看懂下面代码的关键)

  1. 带时区时间DateTime<Local> 本地时区、DateTime<Utc> UTC零时区,包含时区信息,可直接格式化、转时间戳
  2. 裸时间(无时区)
    • NaiveDate:只有年月日,无时分秒、无时区
    • NaiveTime:只有时分秒,无年月日、无时区
    • NaiveDateTime:年月日+时分秒,没有时区,仅存储纯时间数字
  3. TimeDelta:时间间隔,用来做时间加减(天/时/分/秒/毫秒)
  4. Months:专门按月偏移(解决2月、大小月天数不一致问题,TimeDelta 只能按固定天数偏移)
  5. Datelike trait:提供年月日、星期、当月第几天等日期取值方法

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>

  1. match 分支:生产环境推荐,优雅处理格式错误
  2. .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);

关键区别(重点)

  1. TimeDelta::days(30):强制固定30天,遇到大小月、2月会出错
    例:1月31日 +30天 = 3月2日,不符合“下个月同一天”业务需求
  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);

方法说明

  1. .timestamp():输出秒级时间戳(i64),后端接口通用
  2. .timestamp_millis():输出毫秒时间戳,前端JS常用
  3. 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());

流程拆解

  1. NaiveDate::from_ymd_opt(年,月,日):安全构造日期,返回Option<NaiveDate>,非法日期(2月30日)返回None
  2. 两个同类型时间相减,得到 TimeDelta 差值对象
  3. 差值取值方法:
    • .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);

逻辑分步拆解

  1. .with_day(1):把当前日期强制改为当月1号,得到本月首日
  2. 本月1号 +1个月 → 下个月1号
  3. 下个月1号 减1天 → 本月最后一天

优势

自动兼容28/29天2月、31天大月、30天小月,不用手动判断月份天数,报表统计、月度筛选高频使用。


关键类型总结 & 使用建议

什么时候用 Naive(裸时间)

  1. 只做本地日期计算、报表统计、不需要跨时区传输
  2. 本地文件存储、仅程序内部计算

什么时候用 DateTime/DateTime

  1. 和前端、数据库交互、生成时间戳
  2. 需要格式化展示本地时间、处理时区转换

加减选择

  • 固定时长(往后推2小时、7天)→ TimeDelta
  • 自然月/年(下个月、去年今日)→ Months

安全编码小提示

  1. 构造日期、月份偏移优先用 xxx_opt + match 处理None,少用unwrap上线
  2. 对外接口时间统一用UTC时间戳,避免时区混乱
  3. 解析用户输入日期必须捕获解析错误,防止非法格式panic

五、核心模块与类型说明

1. 基础时间类型

类型 含义 使用场景
NaiveDate 纯日期,无时间、无时区 生日、订单创建日
NaiveTime 纯时刻,无日期、无时区 固定每日执行时刻
NaiveDateTime 日期+时刻,无时区 数据库不带时区存储
DateTime<Local> 带本地时区完整时间 展示给前端本地时间
DateTime<Utc> UTC零时区时间 服务统一存储、时间戳

2. 关键结构体

  • TimeDelta:时间差值,days/hours/minutes/seconds
  • Months:按月偏移,自动适配大小月、闰年

3. 格式化模板常用占位符

  • %Y 4位年份 2026
  • %m 两位月份 01~12
  • %d 两位日期 01~31
  • %H 24小时制 00~23
  • %M 分钟 00~59
  • %S
  • %A 完整星期名称 Monday
  • %w 数字星期 0=周日

六、常用Feature功能说明

  1. clock(默认开启)
    Local::now() / Utc::now() 获取系统当前时间,关闭则无法获取实时时间。
  2. timezone
    拓展时区库,支持Asia/Shanghai等完整IANA时区,用于跨国系统。
  3. serde
    实现Serialize/Deserialize,时间结构体直接转JSON,Web后端必备。
  4. rkyv / sqlx
    额外feature适配数据库ORM(sqlx、diesel)直接存取时间字段。

七、典型业务开发场景

  1. Web后端接口
    UTC时间存库,本地时区格式化返回前端,JSON序列化时间
  2. 定时任务计算
    计算下月执行日、每月1号、距离过期剩余天数
  3. 日志系统
    日志打印格式化时间、计算请求耗时(两个时间差值)
  4. 数据库业务
    生日、订单创建时间、活动起止时间校验
  5. 爬虫/数据同步
    时间戳转换、按日期分段拉取历史数据

八、优势对比标准库std::time

  1. 标准库 SystemTime 只支持时间戳,无日期、月份、星期操作;
  2. chrono自动处理闰年、2月、月末边界,不用手动判断;
  3. 统一格式化/解析模板,不用手写复杂转换;
  4. 原生支持时区,解决前后端时区错乱问题;
  5. 生态兼容serde、sqlx、axum、rocket等主流框架。
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐