swift_mt_message/fields/
field30.rs

1use super::swift_utils::parse_date_yymmdd;
2use crate::traits::SwiftField;
3use chrono::{Datelike, NaiveDate};
4use serde::{Deserialize, Serialize};
5
6/// **Field 30: Date Specifications**
7///
8/// Specifies various types of dates critical to transaction processing.
9///
10/// **Format:** `6!n` (YYMMDD) or `8!n` (YYYYMMDD for variants)
11/// **Constraints:** Valid calendar date, business day conventions
12///
13/// **Example:**
14/// ```text
15/// :30:250719
16/// ```
17#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18pub struct Field30 {
19    /// Execution date (YYMMDD)
20    pub execution_date: NaiveDate,
21}
22
23impl SwiftField for Field30 {
24    fn parse(input: &str) -> crate::Result<Self>
25    where
26        Self: Sized,
27    {
28        let execution_date = parse_date_yymmdd(input)?;
29
30        Ok(Field30 { execution_date })
31    }
32
33    fn to_swift_string(&self) -> String {
34        format!(
35            ":30:{:02}{:02}{:02}",
36            self.execution_date.year() % 100,
37            self.execution_date.month(),
38            self.execution_date.day()
39        )
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use chrono::Datelike;
47
48    #[test]
49    fn test_field30_parse() {
50        let field = Field30::parse("240719").unwrap();
51        assert_eq!(field.execution_date.year(), 2024);
52        assert_eq!(field.execution_date.month(), 7);
53        assert_eq!(field.execution_date.day(), 19);
54
55        // Test century logic (50-99 -> 1950-1999)
56        let field = Field30::parse("991231").unwrap();
57        assert_eq!(field.execution_date.year(), 1999);
58
59        // Test century logic (00-49 -> 2000-2049)
60        let field = Field30::parse("250101").unwrap();
61        assert_eq!(field.execution_date.year(), 2025);
62    }
63
64    #[test]
65    fn test_field30_to_swift_string() {
66        let field = Field30 {
67            execution_date: NaiveDate::from_ymd_opt(2024, 7, 19).unwrap(),
68        };
69        assert_eq!(field.to_swift_string(), ":30:240719");
70
71        let field = Field30 {
72            execution_date: NaiveDate::from_ymd_opt(1999, 12, 31).unwrap(),
73        };
74        assert_eq!(field.to_swift_string(), ":30:991231");
75    }
76
77    #[test]
78    fn test_field30_parse_invalid() {
79        // Invalid length
80        assert!(Field30::parse("12345").is_err());
81        assert!(Field30::parse("1234567").is_err());
82
83        // Invalid date
84        assert!(Field30::parse("240230").is_err()); // Feb 30th
85        assert!(Field30::parse("241301").is_err()); // Month 13
86
87        // Non-numeric
88        assert!(Field30::parse("24071a").is_err());
89    }
90}