Rust中DateTime::parse_from_rfc3339解析Bungie API日期报错排查
解析Bungie API返回的RFC3339日期时触发Panic的原因
我尝试通过Bungie API获取数据,返回的JSON中包含格式为"2022-09-18T02:17:59Z"的最后游玩日期,希望将其解析为DateTime对象。
以下是我的代码(个人数据已替换为XXX):
const API_ROOT: &str = "https://www.bungie.net/Platform"; const API_KEY_HEADER: &str = "X-API-Key"; const MY_API_KEY: &str = "XXX"; const MEMBERSHIP_TYPE: &str = "XXX"; const MEMBERSHIP_ID: &str = "XXX"; #[tokio::main] async fn main() -> Result<(), reqwest::Error> { let url = format!("{}/Destiny2/{}/Profile/{}/?components=100", API_ROOT, MEMBERSHIP_TYPE, MEMBERSHIP_ID); let req = reqwest::Client::new() .get(url) .header(API_KEY_HEADER, MY_API_KEY) .send() .await? .text() .await?; let data: JsonValue = serde_json::from_str(&req).expect("Failed to read json from response!"); let name = &data["Response"]["profile"]["data"]["userInfo"]["displayName"].to_string(); println!("Name: {}", name); let last_played_raw = &data["Response"]["profile"]["data"]["dateLastPlayed"].to_string(); println!("{}", last_played_raw); let last_played_raw = last_played_raw.replace("Z", "+00:00"); println!("{}", last_played_raw); let last_played = DateTime::parse_from_rfc3339(&last_played_raw).unwrap(); println!("Last played: {}", last_played); Ok(()) }
问题在于解析last_played_raw字符串时触发了panic:
"2022-09-18T02:17:59Z" "2022-09-18T02:17:59+00:00" thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseError(Invalid)', src\main.rs:37:70
原因与解决方法
核心问题
你调用to_string()获取JSON中的日期字符串时,返回的结果包含了JSON原生的双引号。比如原本的日期值是2022-09-18T02:17:59Z,但to_string()后得到的是"2022-09-18T02:17:59Z"(带首尾双引号)。替换Z为+00:00后变成"2022-09-18T02:17:59+00:00",这种带引号的字符串不符合RFC3339格式,导致解析失败。
解决方式1:使用as_str()获取无引号的字符串切片
直接用as_str()代替to_string(),它会返回JSON字符串的原始内容(不带引号),而且parse_from_rfc3339原生支持Z作为UTC标识,不需要手动替换:
// 替换日期获取与解析的代码 let last_played_raw = data["Response"]["profile"]["data"]["dateLastPlayed"] .as_str() .expect("dateLastPlayed is not a valid string"); let last_played = DateTime::parse_from_rfc3339(last_played_raw).unwrap();
解决方式2:手动去除字符串首尾的引号
如果坚持用to_string(),需要先去掉首尾的双引号:
let last_played_raw = &data["Response"]["profile"]["data"]["dateLastPlayed"].to_string(); // 去除首尾的双引号 let last_played_raw = last_played_raw.trim_matches('"'); let last_played = DateTime::parse_from_rfc3339(last_played_raw).unwrap();
内容的提问来源于stack exchange,提问作者Roman Theuer
相关产品推荐
相关产品推荐

