如何将Excel日期浮点数转换为Rust的chrono::NaiveDate或年月日组件
在Rust中把Excel浮点数日期转换为chrono::NaiveDate
核心逻辑说明
Excel的日期数值是从1900年1月1日开始计数的天数,但存在1900年闰年bug(Excel错误认为1900是闰年,多算了一天),所以需要先修正这个问题,再转成NaiveDate:
- 当日期数值≥60时,实际天数需要减1(跳过不存在的1900-02-29)
- 日期数值<60时直接使用原整数天数
- 基于修正后的天数,从基准日期
1900-01-01累加得到目标日期
补充后的Float分支代码
把你原有代码中的Float分支替换为以下逻辑:
Ok(DataType::Float(dt)) => { println!("this is float!!!"); println!("dt: {}", dt); // 提取整数天数部分,Excel日期的小数是时间,这里只取日期部分 let mut days = dt.floor() as i64; // 修正Excel的1900闰年bug if days >= 60 { days -= 1; } // Excel基准日期是1900-01-01,对应天数1,所以要减1才能用chrono的add_days let base_date = NaiveDate::from_ymd_opt(1900, 1, 1).unwrap(); // 计算目标日期,用checked_add_days避免溢出 let val = base_date.checked_add_days(Duration::days(days - 1)); Ok(val) }
完整代码示例(整合后)
use chrono::{NaiveDate, Duration}; use calamine::DataType; // 假设你定义了DATE_FORMAT和Error类型 const DATE_FORMAT: &str = "%d-%m-%Y"; // 替换成你的Error类型定义 type Error = Box<dyn std::error::Error>; // 你的反序列化逻辑函数 fn deserialize_date<'de, D>(deserializer: D) -> Result<Option<NaiveDate>, Error> where D: serde::Deserializer<'de>, { let data_type = DataType::deserialize(deserializer); match data_type { Ok(DataType::Error(_)) => Ok(None), Ok(DataType::String(date_str)) => { let msg = "Failed to convert Date. Wrong format or empty."; let val = NaiveDate::parse_from_str(&date_str, DATE_FORMAT) .map_err(|_| Error::custom(msg))?; Ok(Some(val)) } Ok(DataType::Float(dt)) => { println!("this is float!!!"); println!("dt: {}", dt); let mut days = dt.floor() as i64; if days >= 60 { days -= 1; } let base_date = NaiveDate::from_ymd_opt(1900, 1, 1).unwrap(); let val = base_date.checked_add_days(Duration::days(days - 1)); Ok(val) } _ => Ok(None), } }
关键细节解释
- 取整数天数:用
floor()提取浮点数的整数部分,因为Excel的小数部分代表一天中的时间,我们只需要日期部分。 - 闰年bug修正:Excel中数值60对应不存在的1900-02-29,所以所有≥60的数值都要减1,才能对应真实的公历日期。
- 基准日期计算:Excel的数值1对应1900-01-01,而
checked_add_days是从基准日期往后加N天,所以需要用days - 1来匹配。 - 安全处理:用
checked_add_days替代直接加法,避免因过大的日期数值导致溢出 panic。
内容的提问来源于stack exchange,提问作者DennyHiu
相关产品推荐
相关产品推荐

