From 8a41507b1542c4c195a68f2ff427871ac223f293 Mon Sep 17 00:00:00 2001 From: Andrei Zisu Date: Mon, 10 Feb 2025 23:59:45 +0100 Subject: [PATCH] Add support for ddd KVN dates --- crates/lox-io/src/ndm.rs | 3 +- crates/lox-io/src/ndm/kvn/parser.rs | 90 ++++++++++++++++++++--------- 2 files changed, 64 insertions(+), 29 deletions(-) diff --git a/crates/lox-io/src/ndm.rs b/crates/lox-io/src/ndm.rs index bae1033f..f3fef237 100644 --- a/crates/lox-io/src/ndm.rs +++ b/crates/lox-io/src/ndm.rs @@ -31,8 +31,7 @@ //! covariance matrix section. But this will cause the comments for the //! following section, the maneuver parameters list, to be discarded. //! -//! The KVN parsing currently does not support user-defined fields and ddd date -//! format types. +//! The KVN parsing currently does not support user-defined fields. //! //! Check the respective submodules for more information. diff --git a/crates/lox-io/src/ndm/kvn/parser.rs b/crates/lox-io/src/ndm/kvn/parser.rs index f53a3808..23359647 100644 --- a/crates/lox-io/src/ndm/kvn/parser.rs +++ b/crates/lox-io/src/ndm/kvn/parser.rs @@ -153,11 +153,23 @@ pub struct KvnValue { pub unit: Option, } +#[derive(PartialEq, Debug)] +pub enum DateOfYear { + DayOfMonth { month: u8, day: u8 }, + DayOfYear { day: u16 }, +} + +impl Default for DateOfYear { + fn default() -> Self { + DateOfYear::DayOfMonth { month: 0, day: 0 } + } +} + #[derive(PartialEq, Debug, Default)] pub struct KvnDateTimeValue { pub year: u16, - pub month: u8, - pub day: u8, + pub date_in_year: DateOfYear, + pub hour: u8, pub minute: u8, pub second: u8, @@ -580,13 +592,21 @@ pub fn handle_datetime_capture(captures: ®ex::Captures) -> KvnDateTimeValue { // We don't do full validation of the date values. We only care if they // have the expected number of digits - // mo is a mandatory decimal in the regex so we expect the capture to be - // always there and unwrap is fine - let month = captures.name("mo").unwrap().as_str().parse::().unwrap(); + let date_in_year = if let Some(day) = captures.name("ddd") { + let day = day.as_str().parse::().unwrap(); - // day is a mandatory decimal in the regex so we expect the capture to be - // always there and unwrap is fine - let day = captures.name("dy").unwrap().as_str().parse::().unwrap(); + DateOfYear::DayOfYear { day } + } else { + // mo is a mandatory decimal in the regex so we expect the capture to be + // always there and unwrap is fine + let month = captures.name("mo").unwrap().as_str().parse::().unwrap(); + + // day is a mandatory decimal in the regex so we expect the capture to be + // always there and unwrap is fine + let day = captures.name("dy").unwrap().as_str().parse::().unwrap(); + + DateOfYear::DayOfMonth { month, day } + }; // hr is a mandatory decimal in the regex so we expect the capture to be // always there and unwrap is fine @@ -617,8 +637,7 @@ pub fn handle_datetime_capture(captures: ®ex::Captures) -> KvnDateTimeValue { KvnDateTimeValue { year, - month, - day, + date_in_year, hour, minute, second, @@ -634,8 +653,8 @@ pub fn parse_kvn_datetime_line( Err(KvnDateTimeParserErr::EmptyValue { input })? }; - // Modified from Figure F-5: CCSDS 502.0-B-3 - let re = Regex::new(r"^(?:\s*)?(?[0-9A-Z_]*)(?:\s*)?=(?:\s*)?(?(?(?:\d{4}))-(?(?:\d{1,2}))-(?(?:\d{1,2}))T(?
(?:\d{1,2})):(?(?:\d{1,2})):(?(?:\d{0,2}(?:\.\d*)?)))(?:\s*)?$").unwrap(); + // Modified from Figure F-5: CCSDS 502.0-B-3 with extension for ddd + let re = Regex::new(r"^(?:\s*)?(?[0-9A-Z_]*)(?:\s*)?=(?:\s*)?(?(?(?:\d{4}))-((?(?:\d{1,2}))-(?(?:\d{1,2})))?(?(?:\d{3}))?T(?
(?:\d{1,2})):(?(?:\d{1,2})):(?(?:\d{0,2}(?:\.\d*)?)))(?:\s*)?$").unwrap(); let captures = re .captures(input) @@ -974,8 +993,7 @@ mod test { parse_kvn_datetime_line("CREATION_DATE = 2021-06-03T05:33:00.123"), Ok(KvnDateTimeValue { year: 2021, - month: 6, - day: 3, + date_in_year: DateOfYear::DayOfMonth { month: 6, day: 3 }, hour: 5, minute: 33, second: 0, @@ -988,8 +1006,7 @@ mod test { parse_kvn_datetime_line("CREATION_DATE = 2021-06-03T05:33:01"), Ok(KvnDateTimeValue { year: 2021, - month: 6, - day: 3, + date_in_year: DateOfYear::DayOfMonth { month: 6, day: 3 }, hour: 5, minute: 33, second: 1, @@ -1004,8 +1021,7 @@ mod test { parse_kvn_datetime_line("CREATION_DATE = 2021-06-03T05:33:01 "), Ok(KvnDateTimeValue { year: 2021, - month: 6, - day: 3, + date_in_year: DateOfYear::DayOfMonth { month: 6, day: 3 }, hour: 5, minute: 33, second: 1, @@ -1020,8 +1036,7 @@ mod test { parse_kvn_datetime_line(" CREATION_DATE = 2021-06-03T05:33:01"), Ok(KvnDateTimeValue { year: 2021, - month: 6, - day: 3, + date_in_year: DateOfYear::DayOfMonth { month: 6, day: 3 }, hour: 5, minute: 33, second: 1, @@ -1030,7 +1045,31 @@ mod test { }) ); - // @TODO add support for ddd format + assert_eq!( + parse_kvn_datetime_line("CREATION_DATE = 2021-090T05:33:01"), + Ok(KvnDateTimeValue { + year: 2021, + date_in_year: DateOfYear::DayOfYear { day: 90 }, + hour: 5, + minute: 33, + second: 1, + fractional_second: 0.0, + full_value: "2021-090T05:33:01".to_string(), + }) + ); + + assert_eq!( + parse_kvn_datetime_line("CREATION_DATE = 2021-366T05:33:01"), + Ok(KvnDateTimeValue { + year: 2021, + date_in_year: DateOfYear::DayOfYear { day: 366 }, + hour: 5, + minute: 33, + second: 1, + fractional_second: 0.0, + full_value: "2021-090T05:33:01".to_string(), + }) + ); assert_eq!( parse_kvn_datetime_line("CREATION_DATE = 2021,06,03Q05!33!00-123"), @@ -1130,8 +1169,7 @@ mod test { Ok(KvnStateVectorValue { epoch: KvnDateTimeValue { year: 1996, - month: 12, - day: 28, + date_in_year: DateOfYear::DayOfMonth { month: 12, day: 28 }, hour: 21, minute: 29, second: 7, @@ -1160,8 +1198,7 @@ mod test { Ok(KvnStateVectorValue { epoch: KvnDateTimeValue { year: 1996, - month: 12, - day: 28, + date_in_year: DateOfYear::DayOfMonth { month: 12, day: 28 }, hour: 21, minute: 29, second: 7, @@ -1190,8 +1227,7 @@ mod test { Ok(KvnStateVectorValue { epoch: KvnDateTimeValue { year: 1996, - month: 12, - day: 28, + date_in_year: DateOfYear::DayOfMonth { month: 12, day: 28 }, hour: 21, minute: 29, second: 7,