Coverage Report

Created: 2025-02-21 07:11

/rust/registry/src/index.crates.io-6f17d22bba15001f/ulid-1.1.4/src/time.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::{bitmask, Ulid};
2
use std::time::{Duration, SystemTime};
3
4
impl Ulid {
5
    /// Creates a new Ulid with the current time (UTC)
6
    ///
7
    /// Using this function to generate Ulids will not guarantee monotonic sort order.
8
    /// See [ulid::Generator] for a monotonic sort order.
9
    /// # Example
10
    /// ```rust
11
    /// use ulid::Ulid;
12
    ///
13
    /// let my_ulid = Ulid::new();
14
    /// ```
15
0
    pub fn new() -> Ulid {
16
0
        Ulid::from_datetime(crate::time_utils::now())
17
0
    }
18
19
    /// Creates a new Ulid using data from the given random number generator
20
    ///
21
    /// # Example
22
    /// ```rust
23
    /// use rand::prelude::*;
24
    /// use ulid::Ulid;
25
    ///
26
    /// let mut rng = StdRng::from_entropy();
27
    /// let ulid = Ulid::with_source(&mut rng);
28
    /// ```
29
0
    pub fn with_source<R: rand::Rng>(source: &mut R) -> Ulid {
30
0
        Ulid::from_datetime_with_source(crate::time_utils::now(), source)
31
0
    }
32
33
    /// Creates a new Ulid with the given datetime
34
    ///
35
    /// This can be useful when migrating data to use Ulid identifiers.
36
    ///
37
    /// This will take the maximum of the `[SystemTime]` argument and `[SystemTime::UNIX_EPOCH]`
38
    /// as earlier times are not valid for a Ulid timestamp
39
    ///
40
    /// # Example
41
    /// ```rust
42
    /// use std::time::{SystemTime, Duration};
43
    /// use ulid::Ulid;
44
    ///
45
    /// let ulid = Ulid::from_datetime(SystemTime::now());
46
    /// ```
47
0
    pub fn from_datetime(datetime: SystemTime) -> Ulid {
48
0
        Ulid::from_datetime_with_source(datetime, &mut rand::thread_rng())
49
0
    }
50
51
    /// Creates a new Ulid with the given datetime and random number generator
52
    ///
53
    /// This will take the maximum of the `[SystemTime]` argument and `[SystemTime::UNIX_EPOCH]`
54
    /// as earlier times are not valid for a Ulid timestamp
55
    ///
56
    /// # Example
57
    /// ```rust
58
    /// use std::time::{SystemTime, Duration};
59
    /// use rand::prelude::*;
60
    /// use ulid::Ulid;
61
    ///
62
    /// let mut rng = StdRng::from_entropy();
63
    /// let ulid = Ulid::from_datetime_with_source(SystemTime::now(), &mut rng);
64
    /// ```
65
0
    pub fn from_datetime_with_source<R>(datetime: SystemTime, source: &mut R) -> Ulid
66
0
    where
67
0
        R: rand::Rng + ?Sized,
68
0
    {
69
0
        let timestamp = datetime
70
0
            .duration_since(SystemTime::UNIX_EPOCH)
71
0
            .unwrap_or(Duration::ZERO)
72
0
            .as_millis();
73
0
        let timebits = (timestamp & bitmask!(Self::TIME_BITS)) as u64;
74
0
75
0
        let msb = timebits << 16 | u64::from(source.gen::<u16>());
76
0
        let lsb = source.gen::<u64>();
77
0
        Ulid::from((msb, lsb))
78
0
    }
79
80
    /// Gets the datetime of when this Ulid was created accurate to 1ms
81
    ///
82
    /// # Example
83
    /// ```rust
84
    /// use std::time::{SystemTime, Duration};
85
    /// use ulid::Ulid;
86
    ///
87
    /// let dt = SystemTime::now();
88
    /// let ulid = Ulid::from_datetime(dt);
89
    ///
90
    /// assert!(
91
    ///     dt + Duration::from_millis(1) >= ulid.datetime()
92
    ///     && dt - Duration::from_millis(1) <= ulid.datetime()
93
    /// );
94
    /// ```
95
0
    pub fn datetime(&self) -> SystemTime {
96
0
        let stamp = self.timestamp_ms();
97
0
        SystemTime::UNIX_EPOCH + Duration::from_millis(stamp)
98
0
    }
99
}
100
101
#[cfg(test)]
102
mod tests {
103
    use super::*;
104
105
    #[test]
106
    fn test_dynamic() {
107
        let ulid = Ulid::new();
108
        let encoded = ulid.to_string();
109
        let ulid2 = Ulid::from_string(&encoded).expect("failed to deserialize");
110
111
        println!("{}", encoded);
112
        println!("{:?}", ulid);
113
        println!("{:?}", ulid2);
114
        assert_eq!(ulid, ulid2);
115
    }
116
117
    #[test]
118
    fn test_source() {
119
        use rand::rngs::mock::StepRng;
120
        let mut source = StepRng::new(123, 0);
121
122
        let u1 = Ulid::with_source(&mut source);
123
        let dt = SystemTime::now() + Duration::from_millis(1);
124
        let u2 = Ulid::from_datetime_with_source(dt, &mut source);
125
        let u3 = Ulid::from_datetime_with_source(dt, &mut source);
126
127
        assert!(u1 < u2);
128
        assert_eq!(u2, u3);
129
    }
130
131
    #[test]
132
    fn test_order() {
133
        let dt = SystemTime::now();
134
        let ulid1 = Ulid::from_datetime(dt);
135
        let ulid2 = Ulid::from_datetime(dt + Duration::from_millis(1));
136
        assert!(ulid1 < ulid2);
137
    }
138
139
    #[test]
140
    fn test_datetime() {
141
        let dt = SystemTime::now();
142
        let ulid = Ulid::from_datetime(dt);
143
144
        println!("{:?}, {:?}", dt, ulid.datetime());
145
        assert!(ulid.datetime() <= dt);
146
        assert!(ulid.datetime() + Duration::from_millis(1) >= dt);
147
    }
148
149
    #[test]
150
    fn test_timestamp() {
151
        let dt = SystemTime::now();
152
        let ulid = Ulid::from_datetime(dt);
153
        let ts = dt
154
            .duration_since(SystemTime::UNIX_EPOCH)
155
            .unwrap()
156
            .as_millis();
157
158
        assert_eq!(u128::from(ulid.timestamp_ms()), ts);
159
    }
160
161
    #[test]
162
    fn default_is_nil() {
163
        assert_eq!(Ulid::default(), Ulid::nil());
164
    }
165
166
    #[test]
167
    fn nil_is_at_unix_epoch() {
168
        assert_eq!(Ulid::nil().datetime(), SystemTime::UNIX_EPOCH);
169
    }
170
171
    #[test]
172
    fn truncates_at_unix_epoch() {
173
        if let Some(before_epoch) = SystemTime::UNIX_EPOCH.checked_sub(Duration::from_secs(100)) {
174
            assert!(before_epoch < SystemTime::UNIX_EPOCH);
175
            assert_eq!(
176
                Ulid::from_datetime(before_epoch).datetime(),
177
                SystemTime::UNIX_EPOCH
178
            );
179
        } else {
180
            // Prior dates are not representable (e.g. wasm32-wasi)
181
        }
182
    }
183
}