Skip to main content

tdm_server_rust/utils/
shanghai_time.rs

1//! 东八区时间工具 (Shanghai Time)
2//!
3//! UTC+8 (Asia/Shanghai) 时区的时间获取与格式化。
4//! 对齐 Java `ZoneId.of("Asia/Shanghai")` 行为。
5//!
6//! ## 使用场景
7//!
8//! - RSS 发布时间格式化(中文年月日格式)
9//! - 统计查询的时间范围计算
10//! - 日志时间戳格式化
11
12use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, Utc};
13
14/// 获取上海时区固定偏移量 UTC+8
15///
16/// # 返回值
17///
18/// 返回 [`FixedOffset`] `+08:00`,用于将 UTC 时间转换为上海本地时间。
19pub fn shanghai_offset() -> FixedOffset {
20    FixedOffset::east_opt(8 * 3600).expect("valid offset")
21}
22
23/// 获取当前上海本地时间
24///
25/// # 返回值
26///
27/// 返回当前 UTC 时间在上海时区下的本地时间(不含时区信息)。
28///
29/// # 使用示例
30///
31/// ```rust,ignore
32/// let now = shanghai_now();
33/// // 可用于数据库查询的起止范围 calc
34/// ```
35pub fn shanghai_now() -> NaiveDateTime {
36    Utc::now()
37        .with_timezone(&shanghai_offset())
38        .naive_local()
39}
40
41/// 将 ISO 8601 / RFC 3339 字符串解析为上海本地时间
42///
43/// # 参数
44///
45/// - `s`: ISO 8601 或 RFC 3339 格式的时间字符串,如 `"2024-01-15T20:30:00+00:00"`
46///
47/// # 返回值
48///
49/// 成功返回转换到 UTC+8 的本地时间,失败返回 `chrono::ParseError`。
50///
51/// # Errors
52///
53/// 当输入字符串不符合 ISO 8601 / RFC 3339 格式时返回解析错误。
54pub fn parse_shanghai_iso(s: &str) -> Result<NaiveDateTime, chrono::ParseError> {
55    Ok(DateTime::parse_from_rfc3339(s)?
56        .with_timezone(&shanghai_offset())
57        .naive_local())
58}
59
60/// 获取指定日期在上海时区的 `00:00:00` 时刻
61///
62/// # 参数
63///
64/// - `year`: 年份
65/// - `month`: 月份 (1-12)
66/// - `day`: 日期 (1-31)
67///
68/// # 返回值
69///
70/// 返回指定日期零点的 [`NaiveDateTime`]。
71///
72/// # Panics
73///
74/// 当传入无效日期(如 `month=13`)时 panic。
75pub fn shanghai_day_start(year: i32, month: u32, day: u32) -> NaiveDateTime {
76    NaiveDate::from_ymd_opt(year, month, day)
77        .and_then(|d| d.and_hms_opt(0, 0, 0))
78        .expect("invalid date")
79}