Skip to main content

finance_query/models/corporate/
calendar_events.rs

1use serde::{Deserialize, Serialize};
2
3use crate::models::quote::FormattedValue;
4
5/// Calendar events including earnings and dividend dates
6#[derive(Default, Debug, Clone, Serialize, Deserialize)]
7#[serde(rename_all = "camelCase")]
8#[non_exhaustive]
9pub struct CalendarEvents {
10    /// Maximum age of the data in seconds
11    #[serde(default)]
12    pub max_age: Option<i64>,
13
14    /// Upcoming earnings date(s)
15    #[serde(default)]
16    pub earnings: Option<EarningsCalendar>,
17
18    /// Ex-dividend date (Unix timestamp)
19    #[serde(default)]
20    pub ex_dividend_date: Option<FormattedValue<i64>>,
21
22    /// Dividend date (Unix timestamp)
23    #[serde(default)]
24    pub dividend_date: Option<FormattedValue<i64>>,
25}
26
27/// Earnings calendar information
28#[derive(Debug, Clone, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct EarningsCalendar {
31    /// List of earnings dates (usually contains 1-2 dates)
32    #[serde(default)]
33    pub earnings_date: Option<Vec<FormattedValue<i64>>>,
34
35    /// Average earnings estimate for upcoming quarter
36    #[serde(default)]
37    pub earnings_average: Option<FormattedValue<f64>>,
38
39    /// Low earnings estimate
40    #[serde(default)]
41    pub earnings_low: Option<FormattedValue<f64>>,
42
43    /// High earnings estimate
44    #[serde(default)]
45    pub earnings_high: Option<FormattedValue<f64>>,
46
47    /// Revenue estimate
48    #[serde(default)]
49    pub revenue_average: Option<FormattedValue<i64>>,
50
51    /// Low revenue estimate
52    #[serde(default)]
53    pub revenue_low: Option<FormattedValue<i64>>,
54
55    /// High revenue estimate
56    #[serde(default)]
57    pub revenue_high: Option<FormattedValue<i64>>,
58}
59
60impl CalendarEvents {
61    /// Returns the next earnings date if available
62    pub fn next_earnings_date(&self) -> Option<i64> {
63        self.earnings.as_ref()?.earnings_date.as_ref()?.first()?.raw
64    }
65
66    /// Returns the ex-dividend date as Unix timestamp
67    pub fn ex_dividend_timestamp(&self) -> Option<i64> {
68        self.ex_dividend_date.as_ref()?.raw
69    }
70
71    /// Returns the dividend date as Unix timestamp
72    pub fn dividend_timestamp(&self) -> Option<i64> {
73        self.dividend_date.as_ref()?.raw
74    }
75
76    /// Returns the earnings estimate average
77    pub fn earnings_estimate(&self) -> Option<f64> {
78        self.earnings.as_ref()?.earnings_average.as_ref()?.raw
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use serde_json::json;
86
87    #[test]
88    fn test_calendar_events_deserialize() {
89        let json = json!({
90            "maxAge": 1,
91            "earnings": {
92                "earningsDate": [
93                    {"fmt": "2026-02-25", "raw": 1772053200}
94                ],
95                "earningsAverage": {"fmt": "1.52", "raw": 1.52083}
96            },
97            "exDividendDate": {"fmt": "2025-12-04", "raw": 1764806400},
98            "dividendDate": {"fmt": "2025-12-20", "raw": 1766188800}
99        });
100
101        let events: CalendarEvents = serde_json::from_value(json).unwrap();
102        assert_eq!(events.max_age, Some(1));
103        assert_eq!(events.next_earnings_date(), Some(1772053200));
104        assert_eq!(events.ex_dividend_timestamp(), Some(1764806400));
105        assert_eq!(events.earnings_estimate(), Some(1.52083));
106    }
107
108    #[test]
109    fn test_calendar_events_with_empty_fields() {
110        let json = json!({
111            "maxAge": 1,
112            "earnings": {},
113            "exDividendDate": {},
114            "dividendDate": {}
115        });
116
117        let events: CalendarEvents = serde_json::from_value(json).unwrap();
118        assert_eq!(events.max_age, Some(1));
119        assert_eq!(events.next_earnings_date(), None);
120        assert_eq!(events.ex_dividend_timestamp(), None);
121    }
122}