proof_of_sql_parser/posql_time/
unit.rs1use super::PoSQLTimestampError;
2use core::fmt;
3use serde::{Deserialize, Serialize};
4
5#[allow(clippy::module_name_repetitions)]
7#[derive(Debug, Clone, Copy, Hash, Serialize, Deserialize, PartialEq, Eq)]
8pub enum PoSQLTimeUnit {
9 Second,
11 Millisecond,
13 Microsecond,
15 Nanosecond,
17}
18
19impl From<PoSQLTimeUnit> for u64 {
20 fn from(value: PoSQLTimeUnit) -> u64 {
21 match value {
22 PoSQLTimeUnit::Second => 0,
23 PoSQLTimeUnit::Millisecond => 3,
24 PoSQLTimeUnit::Microsecond => 6,
25 PoSQLTimeUnit::Nanosecond => 9,
26 }
27 }
28}
29
30impl TryFrom<&str> for PoSQLTimeUnit {
31 type Error = PoSQLTimestampError;
32 fn try_from(value: &str) -> Result<Self, PoSQLTimestampError> {
33 match value {
34 "0" => Ok(PoSQLTimeUnit::Second),
35 "3" => Ok(PoSQLTimeUnit::Millisecond),
36 "6" => Ok(PoSQLTimeUnit::Microsecond),
37 "9" => Ok(PoSQLTimeUnit::Nanosecond),
38 _ => Err(PoSQLTimestampError::UnsupportedPrecision {
39 error: value.into(),
40 }),
41 }
42 }
43}
44
45impl fmt::Display for PoSQLTimeUnit {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 match self {
48 PoSQLTimeUnit::Second => write!(f, "seconds (precision: 0)"),
49 PoSQLTimeUnit::Millisecond => write!(f, "milliseconds (precision: 3)"),
50 PoSQLTimeUnit::Microsecond => write!(f, "microseconds (precision: 6)"),
51 PoSQLTimeUnit::Nanosecond => write!(f, "nanoseconds (precision: 9)"),
52 }
53 }
54}
55
56#[cfg(test)]
59#[allow(deprecated, clippy::missing_panics_doc)]
60mod time_unit_tests {
61 use super::*;
62 use crate::posql_time::{PoSQLTimestamp, PoSQLTimestampError};
63 use alloc::string::ToString;
64 use chrono::{TimeZone, Utc};
65
66 #[test]
67 #[allow(clippy::unnecessary_fallible_conversions)]
68 fn test_u64_conversion() {
69 assert_eq!(PoSQLTimeUnit::Second.try_into(), Ok(0));
70 assert_eq!(PoSQLTimeUnit::Millisecond.try_into(), Ok(3));
71 assert_eq!(PoSQLTimeUnit::Microsecond.try_into(), Ok(6));
72 assert_eq!(PoSQLTimeUnit::Nanosecond.try_into(), Ok(9));
73 }
74
75 #[test]
76 fn test_precision_display() {
77 let input = "2023-06-26T12:34:56Z";
78 let result = PoSQLTimestamp::try_from(input).unwrap();
79 assert_eq!(result.timeunit().to_string(), "seconds (precision: 0)");
80 let input = "2023-06-26T12:34:56.123456Z";
81 let result = PoSQLTimestamp::try_from(input).unwrap();
82 assert_eq!(result.timeunit().to_string(), "microseconds (precision: 6)");
83 let input = "2023-06-26T12:34:56.123Z";
84 let result = PoSQLTimestamp::try_from(input).unwrap();
85 assert_eq!(result.timeunit().to_string(), "milliseconds (precision: 3)");
86
87 let input = "2023-06-26T12:34:56.123456789Z";
88 let result = PoSQLTimestamp::try_from(input).unwrap();
89 assert_eq!(result.timeunit().to_string(), "nanoseconds (precision: 9)");
90 }
91
92 #[test]
93 fn test_valid_precisions() {
94 assert_eq!(PoSQLTimeUnit::try_from("0"), Ok(PoSQLTimeUnit::Second));
95 assert_eq!(PoSQLTimeUnit::try_from("3"), Ok(PoSQLTimeUnit::Millisecond));
96 assert_eq!(PoSQLTimeUnit::try_from("6"), Ok(PoSQLTimeUnit::Microsecond));
97 assert_eq!(PoSQLTimeUnit::try_from("9"), Ok(PoSQLTimeUnit::Nanosecond));
98 }
99
100 #[test]
101 fn test_invalid_precision() {
102 let invalid_precisions = [
103 "1", "2", "4", "5", "7", "8", "10", "zero", "three", "cat", "-1", "-2",
104 ]; for &value in &invalid_precisions {
106 let result = PoSQLTimeUnit::try_from(value);
107 assert!(matches!(
108 result,
109 Err(PoSQLTimestampError::UnsupportedPrecision { .. })
110 ));
111 }
112 }
113
114 #[test]
115 fn test_rfc3339_timestamp_with_milliseconds() {
116 let input = "2023-06-26T12:34:56.123Z";
117 let expected = Utc.ymd(2023, 6, 26).and_hms_milli(12, 34, 56, 123);
118 let result = PoSQLTimestamp::try_from(input).unwrap();
119 assert_eq!(result.timeunit(), PoSQLTimeUnit::Millisecond);
120 assert_eq!(
121 result.timestamp().timestamp_millis(),
122 expected.timestamp_millis()
123 );
124 }
125
126 #[test]
127 fn test_rfc3339_timestamp_with_microseconds() {
128 let input = "2023-06-26T12:34:56.123456Z";
129 let expected = Utc.ymd(2023, 6, 26).and_hms_micro(12, 34, 56, 123_456);
130 let result = PoSQLTimestamp::try_from(input).unwrap();
131 assert_eq!(result.timeunit(), PoSQLTimeUnit::Microsecond);
132 assert_eq!(
133 result.timestamp().timestamp_micros(),
134 expected.timestamp_micros()
135 );
136 }
137 #[test]
138 fn test_rfc3339_timestamp_with_nanoseconds() {
139 let input = "2023-06-26T12:34:56.123456789Z";
140 let expected = Utc.ymd(2023, 6, 26).and_hms_nano(12, 34, 56, 123_456_789);
141 let result = PoSQLTimestamp::try_from(input).unwrap();
142 assert_eq!(result.timeunit(), PoSQLTimeUnit::Nanosecond);
143 assert_eq!(
144 result.timestamp().timestamp_nanos_opt().unwrap(),
145 expected.timestamp_nanos_opt().unwrap()
146 );
147 }
148}