common_grpc/
precision.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::Display;
16
17use common_time::timestamp::TimeUnit;
18
19use crate::Error;
20
21/// Precision represents the precision of a timestamp.
22/// It is used to convert timestamps between different precisions.
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum Precision {
25    Nanosecond,
26    Microsecond,
27    Millisecond,
28    Second,
29    Minute,
30    Hour,
31}
32
33impl Precision {
34    pub fn to_nanos(&self, amount: i64) -> Option<i64> {
35        match self {
36            Precision::Nanosecond => Some(amount),
37            Precision::Microsecond => amount.checked_mul(1_000),
38            Precision::Millisecond => amount.checked_mul(1_000_000),
39            Precision::Second => amount.checked_mul(1_000_000_000),
40            Precision::Minute => amount
41                .checked_mul(60)
42                .and_then(|a| a.checked_mul(1_000_000_000)),
43            Precision::Hour => amount
44                .checked_mul(3600)
45                .and_then(|a| a.checked_mul(1_000_000_000)),
46        }
47    }
48
49    pub fn to_millis(&self, amount: i64) -> Option<i64> {
50        match self {
51            Precision::Nanosecond => amount.checked_div(1_000_000),
52            Precision::Microsecond => amount.checked_div(1_000),
53            Precision::Millisecond => Some(amount),
54            Precision::Second => amount.checked_mul(1_000),
55            Precision::Minute => amount.checked_mul(60_000),
56            Precision::Hour => amount.checked_mul(3_600_000),
57        }
58    }
59}
60
61impl Display for Precision {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        match self {
64            Precision::Nanosecond => write!(f, "Precision::Nanosecond"),
65            Precision::Microsecond => write!(f, "Precision::Microsecond"),
66            Precision::Millisecond => write!(f, "Precision::Millisecond"),
67            Precision::Second => write!(f, "Precision::Second"),
68            Precision::Minute => write!(f, "Precision::Minute"),
69            Precision::Hour => write!(f, "Precision::Hour"),
70        }
71    }
72}
73
74impl TryFrom<Precision> for TimeUnit {
75    type Error = Error;
76
77    fn try_from(precision: Precision) -> Result<Self, Self::Error> {
78        Ok(match precision {
79            Precision::Second => TimeUnit::Second,
80            Precision::Millisecond => TimeUnit::Millisecond,
81            Precision::Microsecond => TimeUnit::Microsecond,
82            Precision::Nanosecond => TimeUnit::Nanosecond,
83            _ => {
84                return Err(Error::NotSupported {
85                    feat: format!("convert {precision} into TimeUnit"),
86                })
87            }
88        })
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use crate::precision::Precision;
95
96    #[test]
97    fn test_to_nanos() {
98        assert_eq!(Precision::Nanosecond.to_nanos(1).unwrap(), 1);
99        assert_eq!(Precision::Microsecond.to_nanos(1).unwrap(), 1_000);
100        assert_eq!(Precision::Millisecond.to_nanos(1).unwrap(), 1_000_000);
101        assert_eq!(Precision::Second.to_nanos(1).unwrap(), 1_000_000_000);
102        assert_eq!(Precision::Minute.to_nanos(1).unwrap(), 60 * 1_000_000_000);
103        assert_eq!(
104            Precision::Hour.to_nanos(1).unwrap(),
105            60 * 60 * 1_000_000_000
106        );
107    }
108
109    #[test]
110    fn test_to_millis() {
111        assert_eq!(Precision::Nanosecond.to_millis(1_000_000).unwrap(), 1);
112        assert_eq!(Precision::Microsecond.to_millis(1_000).unwrap(), 1);
113        assert_eq!(Precision::Millisecond.to_millis(1).unwrap(), 1);
114        assert_eq!(Precision::Second.to_millis(1).unwrap(), 1_000);
115        assert_eq!(Precision::Minute.to_millis(1).unwrap(), 60 * 1_000);
116        assert_eq!(Precision::Hour.to_millis(1).unwrap(), 60 * 60 * 1_000);
117    }
118
119    #[test]
120    fn test_to_nanos_basic() {
121        assert_eq!(Precision::Second.to_nanos(1), Some(1_000_000_000));
122        assert_eq!(Precision::Minute.to_nanos(1), Some(60 * 1_000_000_000));
123    }
124
125    #[test]
126    fn test_to_millis_basic() {
127        assert_eq!(Precision::Second.to_millis(1), Some(1_000));
128        assert_eq!(Precision::Minute.to_millis(1), Some(60_000));
129    }
130
131    #[test]
132    fn test_to_nanos_overflow() {
133        assert_eq!(Precision::Hour.to_nanos(i64::MAX / 100), None);
134    }
135
136    #[test]
137    fn test_zero_input() {
138        assert_eq!(Precision::Second.to_nanos(0), Some(0));
139        assert_eq!(Precision::Minute.to_millis(0), Some(0));
140    }
141}