common_time/
timestamp_millis.rs1use std::cmp::Ordering;
16
17use crate::util::div_ceil;
18use crate::Timestamp;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
24pub struct TimestampMillis(i64);
25
26impl TimestampMillis {
27 pub const INF: TimestampMillis = TimestampMillis::new(i64::MAX);
29 pub const MAX: TimestampMillis = TimestampMillis::new(i64::MAX - 1);
33 pub const MIN: TimestampMillis = TimestampMillis::new(i64::MIN);
35
36 pub const fn new(ms: i64) -> TimestampMillis {
38 TimestampMillis(ms)
39 }
40
41 pub fn as_i64(&self) -> i64 {
43 self.0
44 }
45}
46
47impl From<i64> for TimestampMillis {
48 fn from(ms: i64) -> TimestampMillis {
49 TimestampMillis::new(ms)
50 }
51}
52
53impl From<TimestampMillis> for i64 {
54 fn from(ts: TimestampMillis) -> Self {
55 ts.0
56 }
57}
58
59impl PartialEq<i64> for TimestampMillis {
60 fn eq(&self, other: &i64) -> bool {
61 self.0 == *other
62 }
63}
64
65impl PartialEq<TimestampMillis> for i64 {
66 fn eq(&self, other: &TimestampMillis) -> bool {
67 *self == other.0
68 }
69}
70
71impl PartialOrd<i64> for TimestampMillis {
72 fn partial_cmp(&self, other: &i64) -> Option<Ordering> {
73 Some(self.0.cmp(other))
74 }
75}
76
77impl PartialOrd<TimestampMillis> for i64 {
78 fn partial_cmp(&self, other: &TimestampMillis) -> Option<Ordering> {
79 Some(self.cmp(&other.0))
80 }
81}
82
83pub trait BucketAligned: Sized {
84 fn align_by_bucket(self, bucket_duration: i64) -> Option<Self>;
89
90 fn align_to_ceil_by_bucket(self, bucket_duration: i64) -> Option<Self>;
95}
96
97impl BucketAligned for i64 {
98 fn align_by_bucket(self, bucket_duration: i64) -> Option<Self> {
99 assert!(bucket_duration > 0, "{}", bucket_duration);
100 self.checked_div_euclid(bucket_duration)
101 .and_then(|val| val.checked_mul(bucket_duration))
102 }
103
104 fn align_to_ceil_by_bucket(self, bucket_duration: i64) -> Option<Self> {
105 assert!(bucket_duration > 0, "{}", bucket_duration);
106 div_ceil(self, bucket_duration).checked_mul(bucket_duration)
107 }
108}
109
110impl BucketAligned for Timestamp {
111 fn align_by_bucket(self, bucket_duration: i64) -> Option<Self> {
112 assert!(bucket_duration > 0, "{}", bucket_duration);
113 let unit = self.unit();
114 self.value()
115 .align_by_bucket(bucket_duration)
116 .map(|val| Timestamp::new(val, unit))
117 }
118
119 fn align_to_ceil_by_bucket(self, bucket_duration: i64) -> Option<Self> {
120 assert!(bucket_duration > 0, "{}", bucket_duration);
121 let unit = self.unit();
122 self.value()
123 .align_to_ceil_by_bucket(bucket_duration)
124 .map(|val| Timestamp::new(val, unit))
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn test_timestamp() {
134 let ts = 123456;
135 let timestamp = TimestampMillis::from(ts);
136 assert_eq!(timestamp, ts);
137 assert_eq!(ts, timestamp);
138 assert_eq!(ts, timestamp.as_i64());
139
140 assert_ne!(TimestampMillis::new(0), timestamp);
141 assert!(TimestampMillis::new(-123) < TimestampMillis::new(0));
142 assert!(TimestampMillis::new(10) < 20);
143 assert!(10 < TimestampMillis::new(20));
144
145 assert_eq!(i64::MAX, TimestampMillis::INF);
146 assert_eq!(i64::MAX - 1, TimestampMillis::MAX);
147 assert_eq!(i64::MIN, TimestampMillis::MIN);
148 }
149
150 #[test]
151 fn test_align_by_bucket() {
152 let bucket = 100;
153 assert_eq!(
154 Timestamp::new_millisecond(0),
155 Timestamp::new_millisecond(0)
156 .align_by_bucket(bucket)
157 .unwrap()
158 );
159 assert_eq!(
160 Timestamp::new_millisecond(0),
161 Timestamp::new_millisecond(1)
162 .align_by_bucket(bucket)
163 .unwrap()
164 );
165 assert_eq!(
166 Timestamp::new_millisecond(0),
167 Timestamp::new_millisecond(99)
168 .align_by_bucket(bucket)
169 .unwrap()
170 );
171 assert_eq!(
172 Timestamp::new_millisecond(100),
173 Timestamp::new_millisecond(100)
174 .align_by_bucket(bucket)
175 .unwrap()
176 );
177 assert_eq!(
178 Timestamp::new_millisecond(100),
179 Timestamp::new_millisecond(199)
180 .align_by_bucket(bucket)
181 .unwrap()
182 );
183
184 assert_eq!(
185 Timestamp::new_millisecond(0),
186 Timestamp::new_millisecond(i64::MAX - 1)
187 .align_by_bucket(i64::MAX)
188 .unwrap()
189 );
190
191 assert_eq!(
192 Timestamp::new_millisecond(i64::MAX),
193 Timestamp::new_millisecond(i64::MAX)
194 .align_by_bucket(i64::MAX)
195 .unwrap()
196 );
197
198 assert_eq!(
199 None,
200 Timestamp::new_millisecond(i64::MIN).align_by_bucket(bucket)
201 );
202 }
203
204 #[test]
205 fn test_align_to_ceil() {
206 assert_eq!(None, i64::MAX.align_to_ceil_by_bucket(10));
207 assert_eq!(
208 Some(i64::MAX - (i64::MAX % 10)),
209 (i64::MAX - (i64::MAX % 10)).align_to_ceil_by_bucket(10)
210 );
211 assert_eq!(Some(i64::MAX), i64::MAX.align_to_ceil_by_bucket(1));
212 assert_eq!(Some(i64::MAX), i64::MAX.align_to_ceil_by_bucket(1));
213 assert_eq!(Some(i64::MAX), i64::MAX.align_to_ceil_by_bucket(i64::MAX));
214
215 assert_eq!(
216 Some(i64::MIN - (i64::MIN % 10)),
217 i64::MIN.align_to_ceil_by_bucket(10)
218 );
219 assert_eq!(Some(i64::MIN), i64::MIN.align_to_ceil_by_bucket(1));
220
221 assert_eq!(Some(3), 1i64.align_to_ceil_by_bucket(3));
222 assert_eq!(Some(3), 3i64.align_to_ceil_by_bucket(3));
223 assert_eq!(Some(6), 4i64.align_to_ceil_by_bucket(3));
224 assert_eq!(Some(0), 0i64.align_to_ceil_by_bucket(3));
225 assert_eq!(Some(0), (-1i64).align_to_ceil_by_bucket(3));
226 assert_eq!(Some(0), (-2i64).align_to_ceil_by_bucket(3));
227 assert_eq!(Some(-3), (-3i64).align_to_ceil_by_bucket(3));
228 assert_eq!(Some(-3), (-4i64).align_to_ceil_by_bucket(3));
229 }
230}