bebop/types/
date.rs

1use std::time::Duration;
2use std::cmp::Ordering;
3use std::hash::{Hash, Hasher};
4
5/// The number of ticks between 1/1/0001 and 1/1/1970.
6const TICKS_BETWEEN_EPOCHS: u64 = 621355968000000000;
7
8/// A date is stored as a 64-bit integer amount of “ticks” since 00:00:00 UTC on January 1 of year
9/// 1 A.D. in the Gregorian calendar, where a “tick” is 100 nanoseconds.
10///
11/// The top two bits of this value are ignored by Bebop. In .NET, they are used to specify whether a
12/// date is in UTC or local to the current time zone. But in Bebop, all date-times on the wire are
13/// in UTC.
14#[derive(Clone, Copy, Debug)]
15#[repr(transparent)]
16pub struct Date(u64);
17
18impl From<Date> for Duration {
19    fn from(d: Date) -> Self {
20        // 1 tick is 100ns
21        let micros = d.0 / 10;
22        let remaining_ticks = d.0 - (micros * 10);
23        let nanos = remaining_ticks * 100;
24        Duration::from_micros(micros) + Duration::from_nanos(nanos)
25    }
26}
27
28impl PartialEq for Date {
29    fn eq(&self, other: &Self) -> bool {
30        self.to_ticks() == other.to_ticks()
31    }
32}
33impl Eq for Date {}
34impl PartialOrd for Date {
35    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
36        Some(self.to_ticks().cmp(&other.to_ticks()))
37    }
38}
39impl Ord for Date {
40    fn cmp(&self, other: &Self) -> Ordering {
41        self.to_ticks().cmp(&other.to_ticks())
42    }
43}
44impl Hash for Date {
45    fn hash<H: Hasher>(&self, state: &mut H) {
46        self.to_ticks().hash(state)
47    }
48}
49
50impl Date {
51    #[inline]
52    pub const fn from_ticks(t: u64) -> Self {
53        Self(t)
54    }
55
56    #[inline]
57    pub const fn from_ticks_since_unix_epoch(t: u64) -> Self {
58        Self(t + TICKS_BETWEEN_EPOCHS)
59    }
60
61    #[inline]
62    pub const fn to_ticks(self) -> u64 {
63        // because .NET is weird we have to remove top bits
64        self.0 & 0x3fffffffffffffff
65    }
66
67    #[inline]
68    pub const fn to_ticks_since_unix_epoch(self) -> u64 {
69        self.to_ticks() - TICKS_BETWEEN_EPOCHS
70    }
71
72    #[inline]
73    pub const fn from_micros(t: u64) -> Self {
74        Self(t * 10)
75    }
76
77    #[inline]
78    pub const fn from_micros_since_unix_epoch(t: u64) -> Self {
79        Self::from_ticks_since_unix_epoch(t * 10)
80    }
81
82    #[inline]
83    pub const fn to_micros(self) -> u64 {
84        self.to_ticks() / 10
85    }
86
87    #[inline]
88    pub const fn to_micros_since_unix_epoch(self) -> u64 {
89        self.to_ticks_since_unix_epoch() / 10
90    }
91
92    #[inline]
93    pub const fn from_millis(t: u64) -> Self {
94        Date::from_micros(t * 1000)
95    }
96
97    #[inline]
98    pub const fn from_millis_since_unix_epoch(t: u64) -> Self {
99        Date::from_micros_since_unix_epoch(t * 1000)
100    }
101
102    #[inline]
103    pub const fn to_millis(self) -> u64 {
104        self.to_micros() / 1000
105    }
106
107    #[inline]
108    pub const fn to_millis_since_unix_epoch(self) -> u64 {
109        self.to_micros_since_unix_epoch() / 1000
110    }
111
112    #[inline]
113    pub const fn from_secs(t: u64) -> Self {
114        Date::from_millis(t * 1000)
115    }
116
117    #[inline]
118    pub const fn from_secs_since_unix_epoch(t: u64) -> Self {
119        Date::from_millis_since_unix_epoch(t * 1000)
120    }
121
122    #[inline]
123    pub const fn to_secs(self) -> u64 {
124        self.to_millis() / 1000
125    }
126
127    #[inline]
128    pub const fn to_secs_since_unix_epoch(self) -> u64 {
129        self.to_millis_since_unix_epoch() / 1000
130    }
131
132    #[inline]
133    pub fn to_micros_f(self) -> f64 {
134        self.0 as f64 / 10.
135    }
136
137    #[inline]
138    pub fn to_micros_since_unix_epoch_f(self) -> f64 {
139        self.to_ticks_since_unix_epoch() as f64 / 10.
140    }
141
142    #[inline]
143    pub fn to_millis_f(self) -> f64 {
144        self.to_micros_f() / 1000.
145    }
146
147    #[inline]
148    pub fn to_millis_since_unix_epoch_f(self) -> f64 {
149        self.to_micros_since_unix_epoch_f() / 1000.
150    }
151
152    #[inline]
153    pub fn to_secs_f(self) -> f64 {
154        self.to_millis_f() / 1000.
155    }
156
157    #[inline]
158    pub fn to_secs_since_unix_epoch_f(self) -> f64 {
159        self.to_millis_since_unix_epoch_f() / 1000.
160    }
161}