1use std::borrow::Cow;
2use std::fmt::Debug;
3use std::time::{Duration, SystemTime, UNIX_EPOCH};
4
5use ordered_varint::Variable;
6use serde::{Deserialize, Serialize};
7
8use crate::key::time::limited::{BonsaiEpoch, UnixEpoch};
9use crate::key::{ByteSource, CompositeKind, Key, KeyEncoding, KeyKind, KeyVisitor};
10
11impl<'k> Key<'k> for Duration {
12 const CAN_OWN_BYTES: bool = false;
13
14 fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
15 let merged = u128::decode_variable(bytes.as_ref()).map_err(|_| TimeError::InvalidValue)?;
16 let seconds = u64::try_from(merged >> 30).map_err(|_| TimeError::DeltaNotRepresentable)?;
17 let nanos = u32::try_from(merged & (2_u128.pow(30) - 1)).unwrap();
18 Ok(Self::new(seconds, nanos))
19 }
20}
21
22impl KeyEncoding<Self> for Duration {
23 type Error = TimeError;
24
25 const LENGTH: Option<usize> = None;
26
27 fn describe<Visitor>(visitor: &mut Visitor)
28 where
29 Visitor: KeyVisitor,
30 {
31 visitor.visit_composite(
32 CompositeKind::Struct(Cow::Borrowed("std::time::Duration")),
33 1,
34 );
35 visitor.visit_type(KeyKind::Unsigned);
36 }
37
38 fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
39 let merged = u128::from(self.as_secs()) << 30 | u128::from(self.subsec_nanos());
40 Ok(Cow::Owned(merged.to_variable_vec().unwrap()))
44 }
45}
46
47#[test]
48fn duration_key_tests() {
49 assert_eq!(
50 Duration::ZERO,
51 Duration::from_ord_bytes(ByteSource::Borrowed(
52 &Duration::ZERO.as_ord_bytes().unwrap()
53 ))
54 .unwrap()
55 );
56 assert_eq!(
57 Duration::MAX,
58 Duration::from_ord_bytes(ByteSource::Borrowed(&Duration::MAX.as_ord_bytes().unwrap()))
59 .unwrap()
60 );
61}
62
63impl<'k> Key<'k> for SystemTime {
64 const CAN_OWN_BYTES: bool = false;
65
66 fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
67 let since_epoch = Duration::from_ord_bytes(bytes)?;
68 UNIX_EPOCH
69 .checked_add(since_epoch)
70 .ok_or(TimeError::DeltaNotRepresentable)
71 }
72}
73
74impl KeyEncoding<Self> for SystemTime {
75 type Error = TimeError;
76
77 const LENGTH: Option<usize> = None;
78
79 fn describe<Visitor>(visitor: &mut Visitor)
80 where
81 Visitor: KeyVisitor,
82 {
83 visitor.visit_composite(
84 CompositeKind::Struct(Cow::Borrowed("std::time::SystemTime")),
85 1,
86 );
87 visitor.visit_type(KeyKind::Unsigned);
88 }
89
90 fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
91 let since_epoch = self.duration_since(UNIX_EPOCH).unwrap();
92 match since_epoch.as_ord_bytes()? {
93 Cow::Owned(bytes) => Ok(Cow::Owned(bytes)),
94 Cow::Borrowed(_) => unreachable!(),
95 }
96 }
97}
98
99#[test]
100fn system_time_tests() {
101 assert_eq!(
102 UNIX_EPOCH,
103 SystemTime::from_ord_bytes(ByteSource::Borrowed(&UNIX_EPOCH.as_ord_bytes().unwrap()))
104 .unwrap()
105 );
106 let now = SystemTime::now();
107 assert_eq!(
108 now,
109 SystemTime::from_ord_bytes(ByteSource::Borrowed(&now.as_ord_bytes().unwrap())).unwrap()
110 );
111}
112
113#[derive(thiserror::Error, Debug)]
116#[error("the stored timestamp is outside the allowed range")]
117pub struct DeltaNotRepresentable;
118
119#[derive(thiserror::Error, Debug, Clone, Serialize, Deserialize)]
121pub enum TimeError {
122 #[error("the stored timestamp is outside the allowed range")]
125 DeltaNotRepresentable,
126 #[error("invalid value")]
128 InvalidValue,
129}
130
131impl From<DeltaNotRepresentable> for TimeError {
132 fn from(_: DeltaNotRepresentable) -> Self {
133 Self::DeltaNotRepresentable
134 }
135}
136
137impl From<std::io::Error> for TimeError {
138 fn from(_: std::io::Error) -> Self {
139 Self::InvalidValue
140 }
141}
142
143pub mod limited {
145 use std::borrow::Cow;
146 use std::fmt::{self, Debug, Display, Write};
147 use std::hash::Hash;
148 use std::iter;
149 use std::marker::PhantomData;
150 use std::str::FromStr;
151 use std::time::{Duration, SystemTime, UNIX_EPOCH};
152
153 use derive_where::derive_where;
154 use ordered_varint::Variable;
155 use serde::{Deserialize, Serialize};
156
157 use crate::key::time::TimeError;
158 use crate::key::{ByteSource, CompositeKind, Key, KeyEncoding, KeyVisitor};
159
160 #[derive_where(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
180 pub struct LimitedResolutionDuration<Resolution: TimeResolution> {
181 representation: Resolution::Representation,
182 _resolution: PhantomData<Resolution>,
183 }
184
185 pub trait TimeResolution: Debug + Send + Sync {
187 type Representation: Variable
189 + Serialize
190 + for<'de> Deserialize<'de>
191 + for<'k> Key<'k>
192 + Display
193 + Hash
194 + Eq
195 + PartialEq
196 + Ord
197 + PartialOrd
198 + Clone
199 + Copy
200 + Send
201 + Sync
202 + Debug
203 + Default;
204
205 const FORMAT_SUFFIX: &'static str;
207
208 fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError>;
210
211 fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError>;
213 }
214
215 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
217 pub enum SignedDuration {
218 Positive(Duration),
220 Negative(Duration),
222 }
223
224 impl SignedDuration {
225 #[must_use]
228 pub fn checked_add(self, other: Self) -> Option<Self> {
229 match (self, other) {
230 (SignedDuration::Positive(a), SignedDuration::Positive(b)) => {
231 a.checked_add(b).map(SignedDuration::Positive)
232 }
233 (SignedDuration::Negative(a), SignedDuration::Negative(b)) => {
234 a.checked_add(b).map(SignedDuration::Negative)
235 }
236 (SignedDuration::Positive(a), SignedDuration::Negative(b)) => {
237 if let Some(result) = a.checked_sub(b) {
238 Some(SignedDuration::Positive(result))
239 } else {
240 Some(SignedDuration::Negative(b - a))
241 }
242 }
243 (SignedDuration::Negative(a), SignedDuration::Positive(b)) => {
244 if let Some(result) = a.checked_sub(b) {
245 Some(SignedDuration::Negative(result))
246 } else {
247 Some(SignedDuration::Positive(b - a))
248 }
249 }
250 }
251 }
252 }
253
254 impl<Resolution> LimitedResolutionDuration<Resolution>
255 where
256 Resolution: TimeResolution,
257 {
258 pub const fn new(representation: Resolution::Representation) -> Self {
261 Self {
262 representation,
263 _resolution: PhantomData,
264 }
265 }
266
267 pub const fn representation(&self) -> Resolution::Representation {
269 self.representation
270 }
271 }
272
273 impl<Resolution: TimeResolution> Debug for LimitedResolutionDuration<Resolution> {
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 write!(f, "{:?}{}", self.representation, Resolution::FORMAT_SUFFIX)
276 }
277 }
278
279 impl<Resolution: TimeResolution> Display for LimitedResolutionDuration<Resolution> {
280 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281 write!(f, "{}{}", self.representation, Resolution::FORMAT_SUFFIX)
282 }
283 }
284
285 impl iter::Sum<SignedDuration> for Option<SignedDuration> {
286 fn sum<I: Iterator<Item = SignedDuration>>(mut iter: I) -> Self {
287 let first = iter.next();
288 iter.fold(first, |sum, duration| {
289 sum.and_then(|sum| sum.checked_add(duration))
290 })
291 }
292 }
293
294 impl iter::Sum<Self> for SignedDuration {
295 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
296 iter.sum::<Option<Self>>().expect("operation overflowed")
297 }
298 }
299
300 impl<'k, Resolution> Key<'k> for LimitedResolutionDuration<Resolution>
301 where
302 Resolution: TimeResolution,
303 {
304 const CAN_OWN_BYTES: bool = false;
305
306 fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
307 let representation =
308 <Resolution::Representation as Variable>::decode_variable(bytes.as_ref())
309 .map_err(|_| TimeError::InvalidValue)?;
310
311 Ok(Self {
312 representation,
313 _resolution: PhantomData,
314 })
315 }
316 }
317
318 impl<Resolution> KeyEncoding<Self> for LimitedResolutionDuration<Resolution>
319 where
320 Resolution: TimeResolution,
321 {
322 type Error = TimeError;
323
324 const LENGTH: Option<usize> = None;
325
326 fn describe<Visitor>(visitor: &mut Visitor)
327 where
328 Visitor: KeyVisitor,
329 {
330 visitor.visit_composite(
331 CompositeKind::Struct(Cow::Borrowed(
332 "bonsaidb::core::key::time::LimitedResolutionDuration",
333 )),
334 1,
335 );
336 <Resolution::Representation as KeyEncoding>::describe(visitor);
337 }
338
339 fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
340 self.representation
341 .to_variable_vec()
342 .map(Cow::Owned)
343 .map_err(|_| TimeError::InvalidValue)
344 }
345 }
346
347 impl<Resolution> Default for LimitedResolutionDuration<Resolution>
348 where
349 Resolution: TimeResolution,
350 {
351 fn default() -> Self {
352 Self {
353 representation: <Resolution::Representation as Default>::default(),
354 _resolution: PhantomData,
355 }
356 }
357 }
358
359 impl<Resolution> Serialize for LimitedResolutionDuration<Resolution>
360 where
361 Resolution: TimeResolution,
362 {
363 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
364 where
365 S: serde::Serializer,
366 {
367 self.representation.serialize(serializer)
368 }
369 }
370
371 impl<'de, Resolution> Deserialize<'de> for LimitedResolutionDuration<Resolution>
372 where
373 Resolution: TimeResolution,
374 {
375 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
376 where
377 D: serde::Deserializer<'de>,
378 {
379 <Resolution::Representation as Deserialize<'de>>::deserialize(deserializer)
380 .map(Self::new)
381 }
382 }
383
384 impl<Resolution> TryFrom<SignedDuration> for LimitedResolutionDuration<Resolution>
385 where
386 Resolution: TimeResolution,
387 {
388 type Error = TimeError;
389
390 fn try_from(duration: SignedDuration) -> Result<Self, Self::Error> {
391 Resolution::duration_to_repr(duration).map(|representation| Self {
392 representation,
393 _resolution: PhantomData,
394 })
395 }
396 }
397
398 impl<Resolution> TryFrom<LimitedResolutionDuration<Resolution>> for SignedDuration
399 where
400 Resolution: TimeResolution,
401 {
402 type Error = TimeError;
403
404 fn try_from(value: LimitedResolutionDuration<Resolution>) -> Result<Self, Self::Error> {
405 Resolution::repr_to_duration(value.representation)
406 }
407 }
408
409 impl<Resolution> TryFrom<Duration> for LimitedResolutionDuration<Resolution>
410 where
411 Resolution: TimeResolution,
412 {
413 type Error = TimeError;
414
415 fn try_from(duration: Duration) -> Result<Self, Self::Error> {
416 Self::try_from(SignedDuration::Positive(duration))
417 }
418 }
419
420 impl<Resolution> TryFrom<LimitedResolutionDuration<Resolution>> for Duration
421 where
422 Resolution: TimeResolution,
423 {
424 type Error = TimeError;
425
426 fn try_from(value: LimitedResolutionDuration<Resolution>) -> Result<Self, Self::Error> {
427 match SignedDuration::try_from(value) {
428 Ok(SignedDuration::Positive(value)) => Ok(value),
429 _ => Err(TimeError::DeltaNotRepresentable),
430 }
431 }
432 }
433
434 impl<Resolution> iter::Sum<LimitedResolutionDuration<Resolution>>
435 for Option<LimitedResolutionDuration<Resolution>>
436 where
437 Resolution: TimeResolution,
438 {
439 fn sum<I: Iterator<Item = LimitedResolutionDuration<Resolution>>>(mut iter: I) -> Self {
440 let first = iter
441 .next()
442 .and_then(|dur| Resolution::repr_to_duration(dur.representation).ok());
443 let duration = iter.fold(first, |sum, dur| {
444 sum.and_then(|sum| {
445 Resolution::repr_to_duration(dur.representation)
446 .ok()
447 .and_then(|dur| sum.checked_add(dur))
448 })
449 });
450 duration.and_then(|dur| {
451 Resolution::duration_to_repr(dur)
452 .ok()
453 .map(LimitedResolutionDuration::new)
454 })
455 }
456 }
457
458 impl<Resolution> iter::Sum<Self> for LimitedResolutionDuration<Resolution>
459 where
460 Resolution: TimeResolution,
461 {
462 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
463 iter.sum::<Option<Self>>().expect("operation overflowed")
464 }
465 }
466
467 #[test]
468 fn limited_resolution_duration_sum() {
469 use super::Nanoseconds;
470 assert_eq!(
471 [
472 Nanoseconds::new(1),
473 Nanoseconds::new(2),
474 Nanoseconds::new(3),
475 ]
476 .into_iter()
477 .sum::<Nanoseconds>(),
478 Nanoseconds::new(6)
479 );
480 assert_eq!(
481 [
482 Nanoseconds::new(1),
483 Nanoseconds::new(2),
484 Nanoseconds::new(3),
485 ]
486 .into_iter()
487 .sum::<Option<Nanoseconds>>(),
488 Some(Nanoseconds::new(6))
489 );
490
491 assert_eq!(
492 [Nanoseconds::new(1), Nanoseconds::new(i64::MAX)]
493 .into_iter()
494 .sum::<Option<Nanoseconds>>(),
495 None
496 );
497
498 assert_eq!(
499 [Nanoseconds::new(i64::MAX), Nanoseconds::new(1)]
500 .into_iter()
501 .sum::<Option<Nanoseconds>>(),
502 None
503 );
504
505 assert_eq!(
506 [Nanoseconds::new(i64::MIN), Nanoseconds::new(-11)]
507 .into_iter()
508 .sum::<Option<Nanoseconds>>(),
509 None
510 );
511
512 assert_eq!(
513 [Nanoseconds::new(1), Nanoseconds::new(i64::MIN)]
514 .into_iter()
515 .sum::<Option<Nanoseconds>>(),
516 Some(Nanoseconds::new(i64::MIN + 1))
517 );
518 assert_eq!(
519 [Nanoseconds::new(i64::MIN), Nanoseconds::new(1)]
520 .into_iter()
521 .sum::<Option<Nanoseconds>>(),
522 Some(Nanoseconds::new(i64::MIN + 1))
523 );
524 }
525
526 #[derive(Debug)]
530 pub enum Nanoseconds {}
531
532 const I64_MIN_ABS_AS_U64: u64 = 9_223_372_036_854_775_808;
533
534 impl TimeResolution for Nanoseconds {
535 type Representation = i64;
536
537 const FORMAT_SUFFIX: &'static str = "ns";
538
539 fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
540 if let Ok(unsigned) = u64::try_from(value) {
541 Ok(SignedDuration::Positive(Duration::from_nanos(unsigned)))
542 } else {
543 let positive = value
544 .checked_abs()
545 .and_then(|value| u64::try_from(value).ok())
546 .unwrap_or(I64_MIN_ABS_AS_U64);
547 Ok(SignedDuration::Negative(Duration::from_nanos(positive)))
548 }
549 }
550
551 fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
552 match duration {
553 SignedDuration::Positive(duration) => {
554 i64::try_from(duration.as_nanos()).map_err(|_| TimeError::DeltaNotRepresentable)
555 }
556 SignedDuration::Negative(duration) => {
557 let nanos = duration.as_nanos();
558 if let Ok(nanos) = i64::try_from(nanos) {
559 Ok(-nanos)
560 } else if nanos == u128::from(I64_MIN_ABS_AS_U64) {
561 Ok(i64::MIN)
562 } else {
563 Err(TimeError::DeltaNotRepresentable)
564 }
565 }
566 }
567 }
568 }
569
570 #[derive(Debug)]
574 pub enum Microseconds {}
575
576 impl TimeResolution for Microseconds {
577 type Representation = i64;
578
579 const FORMAT_SUFFIX: &'static str = "us";
580
581 fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
582 if let Ok(unsigned) = u64::try_from(value) {
583 Ok(SignedDuration::Positive(Duration::from_micros(unsigned)))
584 } else {
585 let positive = value
586 .checked_abs()
587 .and_then(|value| u64::try_from(value).ok())
588 .unwrap_or(u64::MAX);
589 Ok(SignedDuration::Negative(Duration::from_micros(positive)))
590 }
591 }
592
593 fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
594 match duration {
595 SignedDuration::Positive(duration) => i64::try_from(duration.as_micros())
596 .map_err(|_| TimeError::DeltaNotRepresentable),
597 SignedDuration::Negative(duration) => {
598 let rounded_up = duration
599 .checked_add(Duration::from_nanos(999))
600 .ok_or(TimeError::DeltaNotRepresentable)?;
601 i64::try_from(rounded_up.as_micros())
602 .map(|repr| -repr)
603 .map_err(|_| TimeError::DeltaNotRepresentable)
604 }
605 }
606 }
607 }
608
609 #[derive(Debug)]
613 pub enum Milliseconds {}
614
615 impl TimeResolution for Milliseconds {
616 type Representation = i64;
617
618 const FORMAT_SUFFIX: &'static str = "ms";
619
620 fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
621 if let Ok(unsigned) = u64::try_from(value) {
622 Ok(SignedDuration::Positive(Duration::from_millis(unsigned)))
623 } else {
624 let positive = value
625 .checked_abs()
626 .and_then(|value| u64::try_from(value).ok())
627 .unwrap_or(u64::MAX);
628 Ok(SignedDuration::Negative(Duration::from_millis(positive)))
629 }
630 }
631
632 fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
633 match duration {
634 SignedDuration::Positive(duration) => i64::try_from(duration.as_millis())
635 .map_err(|_| TimeError::DeltaNotRepresentable),
636 SignedDuration::Negative(duration) => {
637 let rounded_up = duration
638 .checked_add(Duration::from_nanos(999_999))
639 .ok_or(TimeError::DeltaNotRepresentable)?;
640 i64::try_from(rounded_up.as_millis())
641 .map(|repr| -repr)
642 .map_err(|_| TimeError::DeltaNotRepresentable)
643 }
644 }
645 }
646 }
647
648 #[derive(Debug)]
652 pub enum Seconds {}
653
654 impl TimeResolution for Seconds {
655 type Representation = i64;
656
657 const FORMAT_SUFFIX: &'static str = "s";
658
659 fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
660 if let Ok(unsigned) = u64::try_from(value) {
661 Ok(SignedDuration::Positive(Duration::from_secs(unsigned)))
662 } else {
663 let positive = value
664 .checked_abs()
665 .and_then(|value| u64::try_from(value).ok())
666 .unwrap_or(u64::MAX);
667 Ok(SignedDuration::Negative(Duration::from_secs(positive)))
668 }
669 }
670
671 fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
672 match duration {
673 SignedDuration::Positive(duration) => {
674 i64::try_from(duration.as_secs()).map_err(|_| TimeError::DeltaNotRepresentable)
675 }
676 SignedDuration::Negative(duration) => {
677 let rounded_up = duration
678 .checked_add(Duration::from_nanos(999_999_999))
679 .ok_or(TimeError::DeltaNotRepresentable)?;
680 i64::try_from(rounded_up.as_secs())
681 .map(|repr| -repr)
682 .map_err(|_| TimeError::DeltaNotRepresentable)
683 }
684 }
685 }
686 }
687
688 #[derive(Debug)]
692 pub enum Minutes {}
693
694 impl TimeResolution for Minutes {
695 type Representation = i32;
696
697 const FORMAT_SUFFIX: &'static str = "m";
698
699 fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
700 if let Ok(unsigned) = u64::try_from(value) {
701 Ok(SignedDuration::Positive(Duration::from_secs(unsigned * 60)))
702 } else {
703 let positive = u64::try_from(i64::from(value).abs()).unwrap();
704 Ok(SignedDuration::Negative(Duration::from_secs(positive * 60)))
705 }
706 }
707
708 fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
709 match duration {
710 SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / 60)
711 .map_err(|_| TimeError::DeltaNotRepresentable),
712 SignedDuration::Negative(duration) => i32::try_from((duration.as_secs() + 59) / 60)
713 .map(|repr| -repr)
714 .map_err(|_| TimeError::DeltaNotRepresentable),
715 }
716 }
717 }
718
719 #[derive(Debug)]
723 pub enum Hours {}
724
725 impl TimeResolution for Hours {
726 type Representation = i32;
727
728 const FORMAT_SUFFIX: &'static str = "h";
729
730 fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
731 if let Ok(unsigned) = u64::try_from(value) {
732 Ok(SignedDuration::Positive(Duration::from_secs(
733 unsigned * 60 * 60,
734 )))
735 } else {
736 let positive = u64::try_from(i64::from(value).abs()).unwrap();
737 Ok(SignedDuration::Negative(Duration::from_secs(
738 positive * 60 * 60,
739 )))
740 }
741 }
742
743 fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
744 const FACTOR: u64 = 60 * 60;
745 match duration {
746 SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / FACTOR)
747 .map_err(|_| TimeError::DeltaNotRepresentable),
748 SignedDuration::Negative(duration) => {
749 i32::try_from((duration.as_secs() + FACTOR - 1) / FACTOR)
750 .map(|repr| -repr)
751 .map_err(|_| TimeError::DeltaNotRepresentable)
752 }
753 }
754 }
755 }
756
757 #[derive(Debug)]
761 pub enum Days {}
762
763 impl TimeResolution for Days {
764 type Representation = i32;
765
766 const FORMAT_SUFFIX: &'static str = "d";
767
768 fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
769 if let Ok(unsigned) = u64::try_from(value) {
770 Ok(SignedDuration::Positive(Duration::from_secs(
771 unsigned * 24 * 60 * 60,
772 )))
773 } else {
774 let positive = u64::try_from(i64::from(value).abs()).unwrap();
775 Ok(SignedDuration::Negative(Duration::from_secs(
776 positive * 24 * 60 * 60,
777 )))
778 }
779 }
780
781 fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
782 const FACTOR: u64 = 24 * 60 * 60;
783 match duration {
784 SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / FACTOR)
785 .map_err(|_| TimeError::DeltaNotRepresentable),
786 SignedDuration::Negative(duration) => {
787 Ok(i32::try_from((duration.as_secs() + FACTOR - 1) / FACTOR)
788 .map_or(i32::MIN, |repr| -repr))
789 }
790 }
791 }
792 }
793
794 #[derive(Debug)]
798 pub enum Weeks {}
799
800 impl TimeResolution for Weeks {
801 type Representation = i32;
802
803 const FORMAT_SUFFIX: &'static str = "w";
804
805 fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
806 if let Ok(unsigned) = u64::try_from(value) {
807 Ok(SignedDuration::Positive(Duration::from_secs(
808 unsigned * 7 * 24 * 60 * 60,
809 )))
810 } else {
811 let positive = u64::try_from(i64::from(value).abs()).unwrap();
812 Ok(SignedDuration::Negative(Duration::from_secs(
813 positive * 7 * 24 * 60 * 60,
814 )))
815 }
816 }
817
818 fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
819 const FACTOR: u64 = 7 * 24 * 60 * 60;
820 match duration {
821 SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / FACTOR)
822 .map_err(|_| TimeError::DeltaNotRepresentable),
823 SignedDuration::Negative(duration) => {
824 i32::try_from((duration.as_secs() + FACTOR - 1) / FACTOR)
825 .map(|repr| -repr)
826 .map_err(|_| TimeError::DeltaNotRepresentable)
827 }
828 }
829 }
830 }
831
832 #[test]
833 fn limited_resolution_duration_tests() {
834 fn test_limited<Resolution: TimeResolution>(
835 duration: Duration,
836 expected_step: Resolution::Representation,
837 ) {
838 let limited = LimitedResolutionDuration::<Resolution>::try_from(duration).unwrap();
839 assert_eq!(limited.representation, expected_step);
840 let encoded = limited.as_ord_bytes().unwrap();
841 println!("Encoded {limited:?} to {} bytes", encoded.len());
842 let decoded =
843 LimitedResolutionDuration::from_ord_bytes(ByteSource::Borrowed(&encoded)).unwrap();
844 assert_eq!(limited, decoded);
845 }
846
847 fn test_eq_limited<Resolution: TimeResolution>(
848 duration: Duration,
849 expected_step: Resolution::Representation,
850 ) {
851 test_limited::<Resolution>(duration, expected_step);
852 let limited = LimitedResolutionDuration::<Resolution>::try_from(duration).unwrap();
853 assert_eq!(duration, Duration::try_from(limited).unwrap());
854 }
855
856 let truncating_seconds = 7 * 24 * 60 * 60 + 24 * 60 * 60 + 60 * 60 + 60 + 1;
857 let truncating = Duration::new(u64::try_from(truncating_seconds).unwrap(), 987_654_321);
858 test_limited::<Weeks>(truncating, 1);
859 test_limited::<Days>(truncating, 8);
860 test_limited::<Hours>(truncating, 8 * 24 + 1);
861 test_limited::<Minutes>(truncating, 8 * 24 * 60 + 60 + 1);
862 test_limited::<Seconds>(truncating, 8 * 24 * 60 * 60 + 60 * 60 + 60 + 1);
863 test_limited::<Milliseconds>(truncating, truncating_seconds * 1_000 + 987);
864 test_limited::<Microseconds>(truncating, truncating_seconds * 1_000_000 + 987_654);
865
866 let forty_two_days = Duration::from_secs(42 * 24 * 60 * 60);
867 test_eq_limited::<Weeks>(forty_two_days, 6);
868 test_eq_limited::<Days>(forty_two_days, 42);
869 test_eq_limited::<Hours>(forty_two_days, 42 * 24);
870 test_eq_limited::<Minutes>(forty_two_days, 42 * 24 * 60);
871 test_eq_limited::<Seconds>(forty_two_days, 42 * 24 * 60 * 60);
872 test_eq_limited::<Milliseconds>(forty_two_days, 42 * 24 * 60 * 60 * 1_000);
873 test_eq_limited::<Microseconds>(forty_two_days, 42 * 24 * 60 * 60 * 1_000_000);
874 }
875
876 #[derive_where(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
902 pub struct LimitedResolutionTimestamp<Resolution: TimeResolution, Epoch: TimeEpoch>(
903 LimitedResolutionDuration<Resolution>,
904 PhantomData<Epoch>,
905 );
906
907 impl<Resolution, Epoch> Default for LimitedResolutionTimestamp<Resolution, Epoch>
908 where
909 Resolution: TimeResolution,
910 Epoch: TimeEpoch,
911 {
912 fn default() -> Self {
913 Self(LimitedResolutionDuration::default(), PhantomData)
914 }
915 }
916
917 impl<Resolution, Epoch> Serialize for LimitedResolutionTimestamp<Resolution, Epoch>
918 where
919 Resolution: TimeResolution,
920 Epoch: TimeEpoch,
921 {
922 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
923 where
924 S: serde::Serializer,
925 {
926 self.0.serialize(serializer)
927 }
928 }
929
930 impl<'de, Resolution, Epoch> Deserialize<'de> for LimitedResolutionTimestamp<Resolution, Epoch>
931 where
932 Resolution: TimeResolution,
933 Epoch: TimeEpoch,
934 {
935 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
936 where
937 D: serde::Deserializer<'de>,
938 {
939 LimitedResolutionDuration::deserialize(deserializer)
940 .map(|duration| Self(duration, PhantomData))
941 }
942 }
943
944 pub trait TimeEpoch: Sized + Send + Sync {
946 fn name() -> &'static str;
949
950 fn epoch_offset() -> Duration;
952 }
953
954 impl<Resolution, Epoch> LimitedResolutionTimestamp<Resolution, Epoch>
955 where
956 Resolution: TimeResolution,
957 Epoch: TimeEpoch,
958 {
959 #[must_use]
967 pub fn now() -> Self {
968 Self::try_from(SystemTime::now()).expect("now should always be representable")
969 }
970
971 pub fn duration_since(
974 &self,
975 other: &impl AnyTimestamp,
976 ) -> Result<Option<Duration>, TimeError> {
977 let self_delta = self.duration_since_unix_epoch()?;
978 let other_delta = other.duration_since_unix_epoch()?;
979 Ok(self_delta.checked_sub(other_delta))
980 }
981
982 pub fn duration_between(&self, other: &impl AnyTimestamp) -> Result<Duration, TimeError> {
984 let self_delta = self.duration_since_unix_epoch()?;
985 let other_delta = other.duration_since_unix_epoch()?;
986 if self_delta < other_delta {
987 Ok(other_delta - self_delta)
988 } else {
989 Ok(self_delta - other_delta)
990 }
991 }
992
993 pub const fn representation(&self) -> Resolution::Representation {
996 self.0.representation()
997 }
998
999 pub fn from_representation(representation: Resolution::Representation) -> Self {
1001 Self::from(LimitedResolutionDuration::new(representation))
1002 }
1003
1004 pub fn to_timestamp_string(&self) -> Result<String, TimeError> {
1025 let mut string = String::new();
1026 self.display(&mut string).map(|_| string)
1027 }
1028
1029 fn display(&self, f: &mut impl Write) -> Result<(), TimeError> {
1030 let since_epoch = self.duration_since_unix_epoch()?;
1031 write!(f, "{}", since_epoch.as_secs()).map_err(|_| TimeError::InvalidValue)?;
1032 if since_epoch.subsec_nanos() > 0 {
1033 if since_epoch.subsec_nanos() % 1_000_000 == 0 {
1034 write!(f, ".{:03}", since_epoch.subsec_millis())
1036 .map_err(|_| TimeError::InvalidValue)
1037 } else if since_epoch.subsec_nanos() % 1_000 == 0 {
1038 write!(f, ".{:06}", since_epoch.subsec_micros())
1039 .map_err(|_| TimeError::InvalidValue)
1040 } else {
1041 write!(f, ".{:09}", since_epoch.subsec_nanos())
1042 .map_err(|_| TimeError::InvalidValue)
1043 }
1044 } else {
1045 Ok(())
1047 }
1048 }
1049 }
1050
1051 pub trait AnyTimestamp {
1053 fn duration_since_unix_epoch(&self) -> Result<Duration, TimeError>;
1056 }
1057
1058 impl AnyTimestamp for SystemTime {
1059 fn duration_since_unix_epoch(&self) -> Result<Duration, TimeError> {
1060 Ok(self.duration_since(UNIX_EPOCH).unwrap())
1061 }
1062 }
1063
1064 impl<Resolution, Epoch> AnyTimestamp for LimitedResolutionTimestamp<Resolution, Epoch>
1065 where
1066 Resolution: TimeResolution,
1067 Epoch: TimeEpoch,
1068 {
1069 fn duration_since_unix_epoch(&self) -> Result<Duration, TimeError> {
1070 let relative_offset = Resolution::repr_to_duration(self.0.representation)?;
1071 match relative_offset {
1072 SignedDuration::Positive(offset) => Epoch::epoch_offset()
1073 .checked_add(offset)
1074 .ok_or(TimeError::DeltaNotRepresentable),
1075 SignedDuration::Negative(offset) => Epoch::epoch_offset()
1076 .checked_sub(offset)
1077 .ok_or(TimeError::DeltaNotRepresentable),
1078 }
1079 }
1080 }
1081
1082 impl<Resolution, Epoch> Debug for LimitedResolutionTimestamp<Resolution, Epoch>
1083 where
1084 Resolution: TimeResolution,
1085 Epoch: TimeEpoch,
1086 {
1087 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1088 write!(f, "LimitedResolutionTimestamp({self})")
1089 }
1090 }
1091
1092 impl<Resolution, Epoch> Display for LimitedResolutionTimestamp<Resolution, Epoch>
1093 where
1094 Resolution: TimeResolution,
1095 Epoch: TimeEpoch,
1096 {
1097 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1098 self.display(f).or_else(|_| Display::fmt(&self.0, f))
1099 }
1100 }
1101
1102 impl<Resolution, Epoch> FromStr for LimitedResolutionTimestamp<Resolution, Epoch>
1103 where
1104 Resolution: TimeResolution,
1105 Epoch: TimeEpoch,
1106 {
1107 type Err = TimeError;
1108
1109 fn from_str(s: &str) -> Result<Self, Self::Err> {
1110 let mut parts = s.split('.');
1111 let seconds = parts.next().ok_or(TimeError::InvalidValue)?;
1112 let seconds = seconds
1113 .parse::<u64>()
1114 .map_err(|_| TimeError::InvalidValue)?;
1115
1116 let duration = if let Some(subseconds_str) = parts.next() {
1117 if subseconds_str.len() > 9 || parts.next().is_some() {
1118 return Err(TimeError::InvalidValue);
1119 }
1120 let subseconds = subseconds_str
1121 .parse::<u32>()
1122 .map_err(|_| TimeError::InvalidValue)?;
1123
1124 let nanos =
1125 subseconds * 10_u32.pow(u32::try_from(9 - subseconds_str.len()).unwrap());
1126 Duration::new(seconds, nanos)
1127 } else {
1128 Duration::from_secs(seconds)
1129 };
1130
1131 let epoch = Epoch::epoch_offset();
1132 let duration = if duration < epoch {
1133 SignedDuration::Negative(epoch - duration)
1134 } else {
1135 SignedDuration::Positive(duration - epoch)
1136 };
1137 Ok(Self::from(
1138 LimitedResolutionDuration::<Resolution>::try_from(duration)?,
1139 ))
1140 }
1141 }
1142
1143 #[test]
1144 fn timestamp_parse_tests() {
1145 fn test_roundtrip_parsing<Resolution: TimeResolution>() {
1146 let original = LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::now();
1147 let unix_timestamp = original.to_string();
1148 let parsed = unix_timestamp.parse().unwrap();
1149 assert_eq!(
1150 original, parsed,
1151 "{original} produced {unix_timestamp}, but parsed {parsed}"
1152 );
1153 }
1154
1155 test_roundtrip_parsing::<Weeks>();
1156 test_roundtrip_parsing::<Days>();
1157 test_roundtrip_parsing::<Minutes>();
1158 test_roundtrip_parsing::<Seconds>();
1159 test_roundtrip_parsing::<Milliseconds>();
1160 test_roundtrip_parsing::<Microseconds>();
1161 test_roundtrip_parsing::<Nanoseconds>();
1162 }
1163
1164 impl<'k, Resolution, Epoch> Key<'k> for LimitedResolutionTimestamp<Resolution, Epoch>
1165 where
1166 Resolution: TimeResolution,
1167 Epoch: TimeEpoch,
1168 {
1169 const CAN_OWN_BYTES: bool = false;
1170
1171 fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
1172 let duration = LimitedResolutionDuration::<Resolution>::from_ord_bytes(bytes)?;
1173 Ok(Self::from(duration))
1174 }
1175 }
1176
1177 impl<Resolution, Epoch> KeyEncoding<Self> for LimitedResolutionTimestamp<Resolution, Epoch>
1178 where
1179 Resolution: TimeResolution,
1180 Epoch: TimeEpoch,
1181 {
1182 type Error = TimeError;
1183
1184 const LENGTH: Option<usize> = None;
1185
1186 fn describe<Visitor>(visitor: &mut Visitor)
1187 where
1188 Visitor: KeyVisitor,
1189 {
1190 visitor.visit_composite(
1191 CompositeKind::Struct(Cow::Borrowed(
1192 "bonsaidb::core::key::time::LimitedResolutionTimestamp",
1193 )),
1194 1,
1195 );
1196 visitor.visit_composite_attribute("epoch", Epoch::epoch_offset().as_nanos());
1197 <Resolution::Representation as KeyEncoding>::describe(visitor);
1198 }
1199
1200 fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
1201 self.0.as_ord_bytes()
1202 }
1203 }
1204
1205 impl<Resolution, Epoch> From<LimitedResolutionDuration<Resolution>>
1206 for LimitedResolutionTimestamp<Resolution, Epoch>
1207 where
1208 Resolution: TimeResolution,
1209 Epoch: TimeEpoch,
1210 {
1211 fn from(duration: LimitedResolutionDuration<Resolution>) -> Self {
1212 Self(duration, PhantomData)
1213 }
1214 }
1215
1216 impl<Resolution, Epoch> From<LimitedResolutionTimestamp<Resolution, Epoch>>
1217 for LimitedResolutionDuration<Resolution>
1218 where
1219 Resolution: TimeResolution,
1220 Epoch: TimeEpoch,
1221 {
1222 fn from(time: LimitedResolutionTimestamp<Resolution, Epoch>) -> Self {
1223 time.0
1224 }
1225 }
1226
1227 impl<Resolution, Epoch> TryFrom<SystemTime> for LimitedResolutionTimestamp<Resolution, Epoch>
1228 where
1229 Resolution: TimeResolution,
1230 Epoch: TimeEpoch,
1231 {
1232 type Error = TimeError;
1233
1234 fn try_from(time: SystemTime) -> Result<Self, TimeError> {
1235 let epoch = UNIX_EPOCH
1236 .checked_add(Epoch::epoch_offset())
1237 .ok_or(TimeError::DeltaNotRepresentable)?;
1238 match time.duration_since(epoch) {
1239 Ok(duration) => {
1240 LimitedResolutionDuration::try_from(SignedDuration::Positive(duration))
1241 .map(Self::from)
1242 }
1243 Err(_) => match epoch.duration_since(time) {
1244 Ok(duration) => {
1245 LimitedResolutionDuration::try_from(SignedDuration::Negative(duration))
1246 .map(Self::from)
1247 }
1248 Err(_) => Err(TimeError::DeltaNotRepresentable),
1249 },
1250 }
1251 }
1252 }
1253
1254 impl<Resolution, Epoch> TryFrom<LimitedResolutionTimestamp<Resolution, Epoch>> for SystemTime
1255 where
1256 Resolution: TimeResolution,
1257 Epoch: TimeEpoch,
1258 {
1259 type Error = TimeError;
1260
1261 fn try_from(
1262 time: LimitedResolutionTimestamp<Resolution, Epoch>,
1263 ) -> Result<Self, TimeError> {
1264 let since_epoch = SignedDuration::try_from(time.0)?;
1265 let epoch = UNIX_EPOCH
1266 .checked_add(Epoch::epoch_offset())
1267 .ok_or(TimeError::DeltaNotRepresentable)?;
1268 let time = match since_epoch {
1269 SignedDuration::Positive(since_epoch) => epoch.checked_add(since_epoch),
1270 SignedDuration::Negative(since_epoch) => epoch.checked_sub(since_epoch),
1271 };
1272
1273 time.ok_or(TimeError::DeltaNotRepresentable)
1274 }
1275 }
1276
1277 pub struct UnixEpoch;
1281
1282 impl TimeEpoch for UnixEpoch {
1283 fn name() -> &'static str {
1284 "Unix"
1285 }
1286
1287 fn epoch_offset() -> Duration {
1288 Duration::ZERO
1289 }
1290 }
1291
1292 pub struct BonsaiEpoch;
1315
1316 impl BonsaiEpoch {
1317 const EPOCH: Duration = Duration::new(1_931_747_507, 0);
1318 }
1319
1320 impl TimeEpoch for BonsaiEpoch {
1321 fn name() -> &'static str {
1322 "BonsaiDb"
1323 }
1324
1325 fn epoch_offset() -> Duration {
1326 Self::EPOCH
1327 }
1328 }
1329
1330 #[test]
1331 fn limited_resolution_timestamp_tests() {
1332 fn test_resolution<Resolution: TimeResolution>(resolution: Duration) {
1333 let now_in_seconds = LimitedResolutionTimestamp::<Resolution, UnixEpoch>::now();
1334 let as_system = SystemTime::try_from(now_in_seconds).unwrap();
1335 let as_limited =
1336 LimitedResolutionTimestamp::<Resolution, UnixEpoch>::try_from(as_system).unwrap();
1337 assert_eq!(as_limited, now_in_seconds);
1338
1339 let now_in_seconds = LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::now();
1340 let as_system = SystemTime::try_from(now_in_seconds).unwrap();
1341 let as_limited =
1342 LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(as_system).unwrap();
1343 assert_eq!(as_limited, now_in_seconds);
1344
1345 let slightly_before_epoch = UNIX_EPOCH + BonsaiEpoch::EPOCH
1346 - Duration::from_nanos(u64::try_from(resolution.as_nanos() / 2).unwrap());
1347 let unix_epoch_in_recent =
1348 LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(
1349 slightly_before_epoch,
1350 )
1351 .unwrap();
1352 let as_system = SystemTime::try_from(unix_epoch_in_recent).unwrap();
1353 let as_limited =
1354 LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(as_system).unwrap();
1355 assert!(
1356 slightly_before_epoch
1357 .duration_since(as_system)
1358 .expect("timestamp should have been trunctated towards MIN")
1359 < resolution
1360 );
1361 assert_eq!(as_limited, unix_epoch_in_recent);
1362
1363 let slightly_after_epoch = UNIX_EPOCH
1364 + BonsaiEpoch::EPOCH
1365 + Duration::from_nanos(u64::try_from(resolution.as_nanos() / 2).unwrap());
1366 let unix_epoch_in_recent =
1367 LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(
1368 slightly_after_epoch,
1369 )
1370 .unwrap();
1371 let as_system = SystemTime::try_from(unix_epoch_in_recent).unwrap();
1372 println!("{slightly_after_epoch:?} converted to {unix_epoch_in_recent} and back as {as_system:?}");
1373 let as_limited =
1374 LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(as_system).unwrap();
1375 assert!(
1376 slightly_after_epoch
1377 .duration_since(as_system)
1378 .expect("timestamp should have been truncated towards 0")
1379 < resolution
1380 );
1381 assert_eq!(as_limited, unix_epoch_in_recent);
1382 }
1383
1384 test_resolution::<Weeks>(Duration::from_secs(7 * 24 * 60 * 60));
1385 test_resolution::<Days>(Duration::from_secs(24 * 60 * 60));
1386 test_resolution::<Hours>(Duration::from_secs(60 * 60));
1387 test_resolution::<Minutes>(Duration::from_secs(60));
1388 test_resolution::<Seconds>(Duration::from_secs(1));
1389 test_resolution::<Milliseconds>(Duration::from_millis(1));
1390 test_resolution::<Microseconds>(Duration::from_micros(1));
1391 test_resolution::<Nanoseconds>(Duration::from_nanos(1));
1392 }
1393
1394 #[test]
1395 fn serialization_tests() {
1396 fn test_serialization<Resolution: TimeResolution>() {
1397 let original = LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::now();
1398 let serialized = pot::to_vec(&original).unwrap();
1399 let deserialized = pot::from_slice(&serialized).unwrap();
1400 assert_eq!(original, deserialized);
1401 }
1402
1403 test_serialization::<Weeks>();
1404 test_serialization::<Days>();
1405 test_serialization::<Hours>();
1406 test_serialization::<Minutes>();
1407 test_serialization::<Seconds>();
1408 test_serialization::<Milliseconds>();
1409 test_serialization::<Microseconds>();
1410 test_serialization::<Nanoseconds>();
1411 }
1412}
1413
1414pub type Weeks = limited::LimitedResolutionDuration<limited::Weeks>;
1418
1419pub type Days = limited::LimitedResolutionDuration<limited::Days>;
1423
1424pub type Hours = limited::LimitedResolutionDuration<limited::Hours>;
1428
1429pub type Minutes = limited::LimitedResolutionDuration<limited::Minutes>;
1433
1434pub type Seconds = limited::LimitedResolutionDuration<limited::Seconds>;
1438
1439pub type Milliseconds = limited::LimitedResolutionDuration<limited::Milliseconds>;
1443
1444pub type Microseconds = limited::LimitedResolutionDuration<limited::Microseconds>;
1448
1449pub type Nanoseconds = limited::LimitedResolutionDuration<limited::Nanoseconds>;
1453
1454pub type WeeksSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Weeks, UnixEpoch>;
1458
1459pub type DaysSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Days, UnixEpoch>;
1463
1464pub type HoursSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Hours, UnixEpoch>;
1468
1469pub type MinutesSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Minutes, UnixEpoch>;
1473
1474pub type SecondsSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Seconds, UnixEpoch>;
1478
1479pub type MillisecondsSinceUnixEpoch =
1483 limited::LimitedResolutionTimestamp<limited::Milliseconds, UnixEpoch>;
1484
1485pub type MicrosecondsSinceUnixEpoch =
1489 limited::LimitedResolutionTimestamp<limited::Microseconds, UnixEpoch>;
1490
1491pub type NanosecondsSinceUnixEpoch =
1495 limited::LimitedResolutionTimestamp<limited::Nanoseconds, UnixEpoch>;
1496
1497pub type TimestampAsWeeks = limited::LimitedResolutionTimestamp<limited::Weeks, BonsaiEpoch>;
1501
1502pub type TimestampAsDays = limited::LimitedResolutionTimestamp<limited::Days, BonsaiEpoch>;
1506
1507pub type TimestampAsHours = limited::LimitedResolutionTimestamp<limited::Hours, BonsaiEpoch>;
1511
1512pub type TimestampAsMinutes = limited::LimitedResolutionTimestamp<limited::Minutes, BonsaiEpoch>;
1516
1517pub type TimestampAsSeconds = limited::LimitedResolutionTimestamp<limited::Seconds, BonsaiEpoch>;
1521
1522pub type TimestampAsMilliseconds =
1526 limited::LimitedResolutionTimestamp<limited::Milliseconds, BonsaiEpoch>;
1527
1528pub type TimestampAsMicroseconds =
1532 limited::LimitedResolutionTimestamp<limited::Microseconds, BonsaiEpoch>;
1533
1534pub type TimestampAsNanoseconds =
1538 limited::LimitedResolutionTimestamp<limited::Nanoseconds, BonsaiEpoch>;