proto_types/timestamp/
mod.rs1#[cfg(feature = "serde")]
2mod serde;
3
4mod timestamp_conversions;
5mod timestamp_impls;
6mod timestamp_operations;
7
8use super::*;
10use crate::{
11 constants::{NANOS_PER_SECOND, PACKAGE_PREFIX},
12 Timestamp,
13};
14
15impl Timestamp {
16 pub fn normalize(&mut self) {
22 if self.nanos <= -NANOS_PER_SECOND || self.nanos >= NANOS_PER_SECOND {
24 if let Some(seconds) = self
25 .seconds
26 .checked_add((self.nanos / NANOS_PER_SECOND) as i64)
27 {
28 self.seconds = seconds;
29
30 self.nanos %= NANOS_PER_SECOND;
31 } else if self.nanos < 0 {
32 self.seconds = i64::MIN;
35
36 self.nanos = 0;
37 } else {
38 self.seconds = i64::MAX;
41
42 self.nanos = 999_999_999;
43 }
44 }
45
46 if self.nanos < 0 {
49 if let Some(seconds) = self.seconds.checked_sub(1) {
50 self.seconds = seconds;
51
52 self.nanos += NANOS_PER_SECOND;
53 } else {
54 debug_assert_eq!(self.seconds, i64::MIN);
57
58 self.nanos = 0;
59 }
60 }
61
62 }
68
69 pub fn try_normalize(mut self) -> Result<Timestamp, Timestamp> {
76 let before = self;
77
78 self.normalize();
79
80 if (self.seconds == i64::MAX || self.seconds == i64::MIN) && self.seconds != before.seconds {
85 Err(before)
86 } else {
87 Ok(self)
88 }
89 }
90
91 pub fn normalized(&self) -> Self {
97 let mut result = *self;
98
99 result.normalize();
100
101 result
102 }
103
104 pub fn date(year: i64, month: u8, day: u8) -> Result<Timestamp, TimestampError> {
106 Timestamp::date_time_nanos(year, month, day, 0, 0, 0, 0)
107 }
108
109 pub fn date_time(
111 year: i64,
112
113 month: u8,
114
115 day: u8,
116
117 hour: u8,
118
119 minute: u8,
120
121 second: u8,
122 ) -> Result<Timestamp, TimestampError> {
123 Timestamp::date_time_nanos(year, month, day, hour, minute, second, 0)
124 }
125
126 pub fn date_time_nanos(
128 year: i64,
129
130 month: u8,
131
132 day: u8,
133
134 hour: u8,
135
136 minute: u8,
137
138 second: u8,
139
140 nanos: u32,
141 ) -> Result<Timestamp, TimestampError> {
142 let date_time = datetime_internal::DateTime {
143 year,
144
145 month,
146
147 day,
148
149 hour,
150
151 minute,
152
153 second,
154
155 nanos,
156 };
157
158 Timestamp::try_from(date_time)
159 }
160}
161
162impl Name for Timestamp {
163 const PACKAGE: &'static str = PACKAGE_PREFIX;
164
165 const NAME: &'static str = "Timestamp";
166
167 fn type_url() -> String {
168 type_url_for::<Self>()
169 }
170}
171
172impl From<std::time::SystemTime> for Timestamp {
173 fn from(system_time: std::time::SystemTime) -> Timestamp {
174 let (seconds, nanos) = match system_time.duration_since(std::time::UNIX_EPOCH) {
175 Ok(duration) => {
176 let seconds = i64::try_from(duration.as_secs()).unwrap();
177
178 (seconds, duration.subsec_nanos() as i32)
179 }
180
181 Err(error) => {
182 let duration = error.duration();
183
184 let seconds = i64::try_from(duration.as_secs()).unwrap();
185
186 let nanos = duration.subsec_nanos() as i32;
187
188 if nanos == 0 {
189 (-seconds, 0)
190 } else {
191 (-seconds - 1, 1_000_000_000 - nanos)
192 }
193 }
194 };
195
196 Timestamp { seconds, nanos }
197 }
198}
199
200#[derive(Debug, PartialEq, Eq, Clone)]
202#[non_exhaustive]
203pub enum TimestampError {
204 OutOfSystemRange(Timestamp),
212 ParseFailure,
214 InvalidDateTime,
216}
217
218impl fmt::Display for TimestampError {
219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 match self {
221 TimestampError::OutOfSystemRange(timestamp) => {
222 write!(
223 f,
224 "{} is not representable as a `SystemTime` because it is out of range",
225 timestamp
226 )
227 }
228
229 TimestampError::ParseFailure => {
230 write!(f, "failed to parse RFC-3339 formatted timestamp")
231 }
232
233 TimestampError::InvalidDateTime => {
234 write!(f, "invalid date or time")
235 }
236 }
237 }
238}
239
240impl std::error::Error for TimestampError {}
241
242impl TryFrom<Timestamp> for std::time::SystemTime {
243 type Error = TimestampError;
244
245 fn try_from(mut timestamp: Timestamp) -> Result<std::time::SystemTime, Self::Error> {
246 let orig_timestamp = timestamp;
247
248 timestamp.normalize();
249
250 let system_time = if timestamp.seconds >= 0 {
251 std::time::UNIX_EPOCH.checked_add(time::Duration::from_secs(timestamp.seconds as u64))
252 } else {
253 std::time::UNIX_EPOCH.checked_sub(time::Duration::from_secs(
254 timestamp
255 .seconds
256 .checked_neg()
257 .ok_or(TimestampError::OutOfSystemRange(timestamp))? as u64,
258 ))
259 };
260
261 let system_time = system_time.and_then(|system_time| {
262 system_time.checked_add(time::Duration::from_nanos(timestamp.nanos as u64))
263 });
264
265 system_time.ok_or(TimestampError::OutOfSystemRange(orig_timestamp))
266 }
267}
268
269impl FromStr for Timestamp {
270 type Err = TimestampError;
271
272 fn from_str(s: &str) -> Result<Timestamp, TimestampError> {
273 datetime_internal::parse_timestamp(s).ok_or(TimestampError::ParseFailure)
274 }
275}
276
277impl fmt::Display for Timestamp {
278 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
279 datetime_internal::DateTime::from(*self).fmt(f)
280 }
281}