• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-engine / geoengine / 3929938005

pending completion
3929938005

push

github

GitHub
Merge #713

84930 of 96741 relevant lines covered (87.79%)

79640.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.96
/datatypes/src/primitives/time_instance.rs
1
use super::datetime::DateTimeError;
2
use super::{DateTime, Duration};
3
use crate::primitives::error;
4
use crate::util::Result;
5
#[cfg(feature = "postgres")]
6
use postgres_types::private::BytesMut;
7
#[cfg(feature = "postgres")]
8
use postgres_types::{FromSql, IsNull, ToSql, Type};
9
use serde::{Deserialize, Serialize};
10
use snafu::ensure;
11
#[cfg(feature = "postgres")]
12
use snafu::Error;
13
use std::ops::AddAssign;
14
use std::{
15
    convert::TryFrom,
16
    fmt::Formatter,
17
    ops::{Add, Sub},
18
    str::FromStr,
19
};
20

21
#[derive(Clone, Copy, Serialize, PartialEq, Eq, PartialOrd, Ord, Debug)]
104,551✔
22
#[repr(C)]
23
pub struct TimeInstance(i64);
24

25
impl TimeInstance {
26
    pub fn from_millis(millis: i64) -> Result<Self> {
1,908✔
27
        ensure!(
1,908✔
28
            Self::MIN.inner() <= millis && millis <= Self::MAX.inner(),
1,908✔
29
            error::InvalidTimeInstance {
×
30
                min: Self::MIN,
×
31
                max: Self::MAX,
×
32
                is: millis
×
33
            }
×
34
        );
35

36
        Ok(TimeInstance(millis))
1,908✔
37
    }
1,908✔
38

39
    pub const fn from_millis_unchecked(millis: i64) -> Self {
2,171✔
40
        TimeInstance(millis)
2,171✔
41
    }
2,171✔
42

43
    pub fn as_datetime_string(self) -> String {
92✔
44
        let instance = self.clamp(TimeInstance::MIN, TimeInstance::MAX);
92✔
45

92✔
46
        instance
92✔
47
            .as_date_time()
92✔
48
            .expect("TimeInstance is not valid")
92✔
49
            .to_datetime_string()
92✔
50
    }
92✔
51

52
    pub fn as_datetime_string_with_millis(self) -> String {
159✔
53
        let instance = self.clamp(TimeInstance::MIN, TimeInstance::MAX);
159✔
54

159✔
55
        instance
159✔
56
            .as_date_time()
159✔
57
            .expect("TimeInstance is not valid")
159✔
58
            .to_datetime_string_with_millis()
159✔
59
    }
159✔
60

61
    pub const fn inner(self) -> i64 {
94,603✔
62
        self.0
94,603✔
63
    }
94,603✔
64

65
    pub fn now() -> Self {
×
66
        Self::from(DateTime::now())
×
67
    }
×
68

69
    /// Converts a `TimeInstance` to a `DateTime`.
70
    /// If this would overflow the range of `DateTime`, the result is `None`.
71
    pub fn as_date_time(self) -> Option<DateTime> {
1,877✔
72
        DateTime::try_from(self).ok()
1,877✔
73
    }
1,877✔
74

75
    /// Returns true if this instance equals `Self::MIN`, i.e., represents the start of time.
76
    #[inline]
77
    pub fn is_min(self) -> bool {
1,012✔
78
        self == Self::MIN
1,012✔
79
    }
1,012✔
80

81
    /// Returns true if this instance equals `Self::MAX`, i.e., represents the end of time.
82
    #[inline]
83
    pub fn is_max(self) -> bool {
770✔
84
        self == Self::MAX
770✔
85
    }
770✔
86

87
    pub const MIN: Self = TimeInstance::from_millis_unchecked(-8_334_632_851_200_001 + 1);
88
    pub const MAX: Self = TimeInstance::from_millis_unchecked(8_210_298_412_800_000 - 1);
89

90
    pub const EPOCH_START: Self = TimeInstance::from_millis_unchecked(0);
91
}
92

93
impl std::fmt::Display for TimeInstance {
94
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2✔
95
        let instance = self.clamp(&TimeInstance::MIN, &TimeInstance::MAX);
2✔
96
        let datetime = instance
2✔
97
            .as_date_time()
2✔
98
            .expect("time instance was clamped into valid range");
2✔
99
        write!(f, "{datetime}")
2✔
100
    }
2✔
101
}
102

103
impl TryFrom<i64> for TimeInstance {
104
    type Error = crate::error::Error;
105

106
    fn try_from(milliseconds: i64) -> Result<Self> {
1,796✔
107
        TimeInstance::from_millis(milliseconds)
1,796✔
108
    }
1,796✔
109
}
110

111
impl From<TimeInstance> for i64 {
112
    fn from(time_instance: TimeInstance) -> Self {
81,270✔
113
        time_instance.inner()
81,270✔
114
    }
81,270✔
115
}
116

117
#[cfg(feature = "postgres")]
118
impl ToSql for TimeInstance {
119
    fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>>
56✔
120
    where
56✔
121
        Self: Sized,
56✔
122
    {
56✔
123
        self.as_date_time().to_sql(ty, out)
56✔
124
    }
56✔
125

126
    fn accepts(ty: &Type) -> bool
56✔
127
    where
56✔
128
        Self: Sized,
56✔
129
    {
56✔
130
        <DateTime as ToSql>::accepts(ty)
56✔
131
    }
56✔
132

133
    fn to_sql_checked(
×
134
        &self,
×
135
        ty: &Type,
×
136
        out: &mut BytesMut,
×
137
    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
×
138
        self.as_date_time().to_sql_checked(ty, out)
×
139
    }
×
140
}
141

142
#[cfg(feature = "postgres")]
143
impl<'a> FromSql<'a> for TimeInstance {
144
    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
20✔
145
        DateTime::from_sql(ty, raw).map(Into::into)
20✔
146
    }
20✔
147

148
    fn accepts(ty: &Type) -> bool {
34✔
149
        <DateTime as FromSql>::accepts(ty)
34✔
150
    }
34✔
151
}
152

153
impl Add<i64> for TimeInstance {
154
    type Output = Self;
155

156
    fn add(self, rhs: i64) -> Self::Output {
33✔
157
        if self.is_min() || self.is_max() {
33✔
158
            // begin and end of time are special values, we don't want to do arithmetics on them
159
            return self;
3✔
160
        }
30✔
161
        TimeInstance::from_millis_unchecked(self.0 + rhs)
30✔
162
    }
33✔
163
}
164

165
impl AddAssign<i64> for TimeInstance {
166
    fn add_assign(&mut self, rhs: i64) {
4✔
167
        *self = *self + rhs;
4✔
168
    }
4✔
169
}
170

171
impl Sub<i64> for TimeInstance {
172
    type Output = Self;
173

174
    fn sub(self, rhs: i64) -> Self::Output {
5✔
175
        if self.is_min() || self.is_max() {
5✔
176
            // begin and end of time are special values, we don't want to do arithmetics on them
177
            return self;
3✔
178
        }
2✔
179
        TimeInstance::from_millis_unchecked(self.0 - rhs)
2✔
180
    }
5✔
181
}
182

183
impl Sub<TimeInstance> for TimeInstance {
184
    type Output = Duration;
185

186
    fn sub(self, rhs: Self) -> Self::Output {
263✔
187
        Duration::milliseconds(self.0 - rhs.0)
263✔
188
    }
263✔
189
}
190

191
impl FromStr for TimeInstance {
192
    type Err = DateTimeError;
193

194
    fn from_str(s: &str) -> Result<Self, Self::Err> {
300✔
195
        let date_time = DateTime::from_str(s)?;
300✔
196
        Ok(date_time.into())
300✔
197
    }
300✔
198
}
199

200
impl<'de> Deserialize<'de> for TimeInstance {
201
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
48✔
202
    where
48✔
203
        D: serde::Deserializer<'de>,
48✔
204
    {
48✔
205
        struct IsoStringOrUnixTimestamp;
48✔
206

48✔
207
        impl<'de> serde::de::Visitor<'de> for IsoStringOrUnixTimestamp {
48✔
208
            type Value = TimeInstance;
48✔
209

48✔
210
            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
48✔
211
                formatter.write_str("RFC 3339 timestamp string or Unix timestamp integer")
×
212
            }
×
213

48✔
214
            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
48✔
215
            where
6✔
216
                E: serde::de::Error,
6✔
217
            {
6✔
218
                TimeInstance::from_str(value).map_err(E::custom)
6✔
219
            }
6✔
220

48✔
221
            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
48✔
222
            where
42✔
223
                E: serde::de::Error,
42✔
224
            {
42✔
225
                TimeInstance::from_millis(v).map_err(E::custom)
42✔
226
            }
42✔
227

48✔
228
            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
48✔
229
            where
36✔
230
                E: serde::de::Error,
36✔
231
            {
36✔
232
                Self::visit_i64(self, v as i64)
36✔
233
            }
36✔
234
        }
48✔
235

48✔
236
        deserializer.deserialize_any(IsoStringOrUnixTimestamp)
48✔
237
    }
48✔
238
}
239

240
#[cfg(test)]
241
mod tests {
242
    use super::*;
243

244
    #[test]
1✔
245
    fn bounds_wrt_chrono() {
1✔
246
        assert_eq!(TimeInstance::MIN, TimeInstance::from(DateTime::MIN));
1✔
247
        assert_eq!(TimeInstance::MAX, TimeInstance::from(DateTime::MAX));
1✔
248
    }
1✔
249

250
    #[test]
1✔
251
    fn time_limits() {
1✔
252
        assert_eq!(TimeInstance::MIN + 1, TimeInstance::MIN);
1✔
253
        assert_eq!(TimeInstance::MIN - 1, TimeInstance::MIN);
1✔
254
        assert_eq!(TimeInstance::MAX + 1, TimeInstance::MAX);
1✔
255
        assert_eq!(TimeInstance::MAX - 1, TimeInstance::MAX);
1✔
256
    }
1✔
257
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc