uuid_timestamp/
lib.rs

1use chrono::NaiveDateTime;
2
3//
4pub fn timestamp(bytes: &[u8; 16]) -> Option<NaiveDateTime> {
5    // https://github.com/uuid-rs/uuid/blob/1.2.2/src/lib.rs#L521
6    let version_num = bytes[6] >> 4;
7
8    //
9    match version_num {
10        // https://github.com/uuid-rs/uuid/blob/1.2.2/src/lib.rs#L930
11        7 => {
12            let millis = u64::from_be_bytes([
13                0, 0, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5],
14            ]);
15
16            Some(
17                NaiveDateTime::from_timestamp_millis(millis as i64)
18                    .expect("invalid or out-of-range datetime"),
19            )
20        }
21        _ => None,
22    }
23}
24
25#[cfg(test)]
26mod tests {
27    use super::*;
28
29    use chrono::Utc;
30
31    #[test]
32    fn test_for_crate_uuid7() {
33        //
34        let v = "0184e596-ec2c-77a8-b4a9-9be4d1dcdb47"
35            .parse::<uuid7::Uuid>()
36            .unwrap();
37        assert!(timestamp(v.as_bytes()).is_some());
38
39        //
40        let dt_start = Utc::now().naive_utc();
41        let dt = timestamp(uuid7::uuid7().as_bytes()).unwrap();
42        let dt_end = Utc::now().naive_utc();
43        assert!(dt_start.timestamp_millis() <= dt.timestamp_millis());
44        assert!(dt.timestamp_millis() <= dt_end.timestamp_millis());
45    }
46
47    #[cfg(uuid_unstable)]
48    #[test]
49    fn test_for_crate_uuid_v7() {
50        //
51        let v = "0184e596-ec2c-77a8-b4a9-9be4d1dcdb47"
52            .parse::<uuid::Uuid>()
53            .unwrap();
54        assert!(timestamp(v.as_bytes()).is_some());
55
56        //
57        let dt_start = Utc::now().naive_utc();
58        let dt = timestamp(uuid::Uuid::now_v7().as_bytes()).unwrap();
59        let dt_end = Utc::now().naive_utc();
60        assert!(dt_start.timestamp_millis() <= dt.timestamp_millis());
61        assert!(dt.timestamp_millis() <= dt_end.timestamp_millis());
62    }
63}