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