prov_cosmwasm_std/
timestamp.rs1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use std::fmt;
4
5use crate::math::Uint64;
6
7#[derive(
26 Serialize, Deserialize, Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, JsonSchema,
27)]
28pub struct Timestamp(Uint64);
29
30impl Timestamp {
31 pub const fn from_nanos(nanos_since_epoch: u64) -> Self {
33 Timestamp(Uint64::new(nanos_since_epoch))
34 }
35
36 pub const fn from_seconds(seconds_since_epoch: u64) -> Self {
38 Timestamp(Uint64::new(seconds_since_epoch * 1_000_000_000))
39 }
40
41 pub const fn plus_seconds(&self, addition: u64) -> Timestamp {
42 self.plus_nanos(addition * 1_000_000_000)
43 }
44
45 pub const fn plus_nanos(&self, addition: u64) -> Timestamp {
46 let nanos = Uint64::new(self.0.u64() + addition);
47 Timestamp(nanos)
48 }
49
50 pub const fn minus_seconds(&self, subtrahend: u64) -> Timestamp {
51 self.minus_nanos(subtrahend * 1_000_000_000)
52 }
53
54 pub const fn minus_nanos(&self, subtrahend: u64) -> Timestamp {
55 let nanos = Uint64::new(self.0.u64() - subtrahend);
56 Timestamp(nanos)
57 }
58
59 #[inline]
61 pub fn nanos(&self) -> u64 {
62 self.0.u64()
63 }
64
65 #[inline]
67 pub fn seconds(&self) -> u64 {
68 self.0.u64() / 1_000_000_000
69 }
70
71 #[inline]
74 pub fn subsec_nanos(&self) -> u64 {
75 self.0.u64() % 1_000_000_000
76 }
77}
78
79impl fmt::Display for Timestamp {
80 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81 let whole = self.seconds();
82 let fractional = self.subsec_nanos();
83 write!(f, "{}.{:09}", whole, fractional)
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn timestamp_from_nanos() {
93 let t = Timestamp::from_nanos(123);
94 assert_eq!(t.0.u64(), 123);
95 let t = Timestamp::from_nanos(0);
96 assert_eq!(t.0.u64(), 0);
97 }
98
99 #[test]
100 fn timestamp_from_seconds() {
101 let t = Timestamp::from_seconds(123);
102 assert_eq!(t.0.u64(), 123_000_000_000);
103 let t = Timestamp::from_seconds(0);
104 assert_eq!(t.0.u64(), 0);
105 }
106
107 #[test]
108 fn timestamp_plus_seconds() {
109 let sum = Timestamp::from_nanos(123).plus_seconds(42);
110 assert_eq!(sum.0.u64(), 42_000_000_123);
111 let sum = Timestamp::from_nanos(123).plus_seconds(0);
112 assert_eq!(sum.0.u64(), 123);
113 }
114
115 #[test]
116 fn timestamp_plus_nanos() {
117 let sum = Timestamp::from_nanos(123).plus_nanos(3);
118 assert_eq!(sum.0.u64(), 126);
119 let sum = Timestamp::from_nanos(123).plus_nanos(0);
120 assert_eq!(sum.0.u64(), 123);
121 }
122
123 #[test]
124 fn timestamp_minus_seconds() {
125 let earlier = Timestamp::from_seconds(123).minus_seconds(0);
126 assert_eq!(earlier.0.u64(), 123_000_000_000);
127 let earlier = Timestamp::from_seconds(123).minus_seconds(3);
128 assert_eq!(earlier.0.u64(), 120_000_000_000);
129 let earlier = Timestamp::from_seconds(123).minus_seconds(123);
130 assert_eq!(earlier.0.u64(), 0);
131 }
132
133 #[test]
134 #[should_panic(expected = "attempt to subtract with overflow")]
135 fn timestamp_minus_seconds_panics_on_overflow() {
136 let _earlier = Timestamp::from_seconds(100).minus_seconds(101);
137 }
138
139 #[test]
140 fn timestamp_minus_nanos() {
141 let earlier = Timestamp::from_seconds(123).minus_nanos(0);
142 assert_eq!(earlier.0.u64(), 123_000_000_000);
143 let earlier = Timestamp::from_seconds(123).minus_nanos(3);
144 assert_eq!(earlier.0.u64(), 122_999_999_997);
145 let earlier = Timestamp::from_seconds(123).minus_nanos(123_000_000_000);
146 assert_eq!(earlier.0.u64(), 0);
147 }
148
149 #[test]
150 #[should_panic(expected = "attempt to subtract with overflow")]
151 fn timestamp_minus_nanos_panics_on_overflow() {
152 let _earlier = Timestamp::from_nanos(100).minus_nanos(101);
153 }
154
155 #[test]
156 fn timestamp_nanos() {
157 let sum = Timestamp::from_nanos(123);
158 assert_eq!(sum.nanos(), 123);
159 let sum = Timestamp::from_nanos(0);
160 assert_eq!(sum.nanos(), 0);
161 let sum = Timestamp::from_nanos(987654321000);
162 assert_eq!(sum.nanos(), 987654321000);
163 }
164
165 #[test]
166 fn timestamp_seconds() {
167 let sum = Timestamp::from_nanos(987654321000);
168 assert_eq!(sum.seconds(), 987);
169 let sum = Timestamp::from_seconds(1234567).plus_nanos(8765436);
170 assert_eq!(sum.seconds(), 1234567);
171 }
172
173 #[test]
174 fn timestamp_subsec_nanos() {
175 let sum = Timestamp::from_nanos(987654321000);
176 assert_eq!(sum.subsec_nanos(), 654321000);
177 let sum = Timestamp::from_seconds(1234567).plus_nanos(8765436);
178 assert_eq!(sum.subsec_nanos(), 8765436);
179 }
180
181 #[test]
182 fn timestamp_implements_display() {
183 let embedded = format!("Time: {}", Timestamp::from_nanos(0));
184 assert_eq!(embedded, "Time: 0.000000000");
185 let embedded = format!("Time: {}", Timestamp::from_nanos(1));
186 assert_eq!(embedded, "Time: 0.000000001");
187 let embedded = format!("Time: {}", Timestamp::from_nanos(10));
188 assert_eq!(embedded, "Time: 0.000000010");
189 let embedded = format!("Time: {}", Timestamp::from_nanos(100));
190 assert_eq!(embedded, "Time: 0.000000100");
191 let embedded = format!("Time: {}", Timestamp::from_nanos(1000));
192 assert_eq!(embedded, "Time: 0.000001000");
193 let embedded = format!("Time: {}", Timestamp::from_nanos(10000));
194 assert_eq!(embedded, "Time: 0.000010000");
195 let embedded = format!("Time: {}", Timestamp::from_nanos(100000));
196 assert_eq!(embedded, "Time: 0.000100000");
197 let embedded = format!("Time: {}", Timestamp::from_nanos(1000000));
198 assert_eq!(embedded, "Time: 0.001000000");
199 let embedded = format!("Time: {}", Timestamp::from_nanos(1000000));
200 assert_eq!(embedded, "Time: 0.001000000");
201 let embedded = format!("Time: {}", Timestamp::from_nanos(10000000));
202 assert_eq!(embedded, "Time: 0.010000000");
203 let embedded = format!("Time: {}", Timestamp::from_nanos(100000000));
204 assert_eq!(embedded, "Time: 0.100000000");
205 let embedded = format!("Time: {}", Timestamp::from_nanos(1000000000));
206 assert_eq!(embedded, "Time: 1.000000000");
207 let embedded = format!("Time: {}", Timestamp::from_nanos(10000000000));
208 assert_eq!(embedded, "Time: 10.000000000");
209 let embedded = format!("Time: {}", Timestamp::from_nanos(100000000000));
210 assert_eq!(embedded, "Time: 100.000000000");
211 }
212}