tushare_api/
custom_date_format.rs

1//! Custom date format implementations for FromTushareValueWithFormat trait
2//!
3//! This module provides implementations for chrono date/time types that support
4//! custom date format parsing through the `#[tushare(date_format = "...")]` attribute.
5
6#[cfg(feature = "chrono")]
7use crate::traits::FromTushareValueWithFormat;
8#[cfg(feature = "chrono")]
9use crate::error::TushareError;
10
11#[cfg(feature = "chrono")]
12impl FromTushareValueWithFormat for chrono::NaiveDate {
13    fn from_tushare_value_with_format(
14        value: &serde_json::Value,
15        format: &str,
16    ) -> Result<Self, TushareError> {
17        match value {
18            serde_json::Value::String(s) => {
19                // Try parsing with the custom format
20                chrono::NaiveDate::parse_from_str(s, format)
21                    .map_err(|e| TushareError::ParseError(
22                        format!("Failed to parse date '{}' with format '{}': {}", s, format, e)
23                    ))
24            }
25            serde_json::Value::Number(n) => {
26                // For numeric values, try to parse as YYYYMMDD first, then use custom format
27                if let Some(i) = n.as_i64() {
28                    let date_str = i.to_string();
29                    
30                    // Try YYYYMMDD format first for numeric values
31                    if date_str.len() == 8 {
32                        if let Ok(date) = chrono::NaiveDate::parse_from_str(&date_str, "%Y%m%d") {
33                            return Ok(date);
34                        }
35                    }
36                    
37                    // Fall back to custom format
38                    chrono::NaiveDate::parse_from_str(&date_str, format)
39                        .map_err(|e| TushareError::ParseError(
40                            format!("Failed to parse numeric date '{}' with format '{}': {}", date_str, format, e)
41                        ))
42                } else {
43                    Err(TushareError::ParseError(
44                        format!("Invalid numeric date value: {}", n)
45                    ))
46                }
47            }
48            _ => Err(TushareError::ParseError(
49                format!("Expected string or number for date parsing, got: {:?}", value)
50            )),
51        }
52    }
53}
54
55#[cfg(feature = "chrono")]
56impl FromTushareValueWithFormat for chrono::NaiveDateTime {
57    fn from_tushare_value_with_format(
58        value: &serde_json::Value,
59        format: &str,
60    ) -> Result<Self, TushareError> {
61        match value {
62            serde_json::Value::String(s) => {
63                // Try parsing with the custom format
64                chrono::NaiveDateTime::parse_from_str(s, format)
65                    .map_err(|e| TushareError::ParseError(
66                        format!("Failed to parse datetime '{}' with format '{}': {}", s, format, e)
67                    ))
68            }
69            serde_json::Value::Number(n) => {
70                // For numeric values, convert to string and try parsing
71                let datetime_str = n.to_string();
72                chrono::NaiveDateTime::parse_from_str(&datetime_str, format)
73                    .map_err(|e| TushareError::ParseError(
74                        format!("Failed to parse numeric datetime '{}' with format '{}': {}", datetime_str, format, e)
75                    ))
76            }
77            _ => Err(TushareError::ParseError(
78                format!("Expected string or number for datetime parsing, got: {:?}", value)
79            )),
80        }
81    }
82}
83
84#[cfg(feature = "chrono")]
85impl FromTushareValueWithFormat for chrono::DateTime<chrono::Utc> {
86    fn from_tushare_value_with_format(
87        value: &serde_json::Value,
88        format: &str,
89    ) -> Result<Self, TushareError> {
90        match value {
91            serde_json::Value::String(s) => {
92                // Try parsing with the custom format
93                chrono::DateTime::parse_from_str(s, format)
94                    .map(|dt| dt.with_timezone(&chrono::Utc))
95                    .map_err(|e| TushareError::ParseError(
96                        format!("Failed to parse UTC datetime '{}' with format '{}': {}", s, format, e)
97                    ))
98            }
99            serde_json::Value::Number(n) => {
100                // For numeric values, convert to string and try parsing
101                let datetime_str = n.to_string();
102                chrono::DateTime::parse_from_str(&datetime_str, format)
103                    .map(|dt| dt.with_timezone(&chrono::Utc))
104                    .map_err(|e| TushareError::ParseError(
105                        format!("Failed to parse numeric UTC datetime '{}' with format '{}': {}", datetime_str, format, e)
106                    ))
107            }
108            _ => Err(TushareError::ParseError(
109                format!("Expected string or number for UTC datetime parsing, got: {:?}", value)
110            )),
111        }
112    }
113}