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