//! Generating UUIDs from timestamps. //! //! Timestamps are used in a few UUID versions as a source of decentralized //! uniqueness (as in versions 1 and 6), and as a way to enable sorting (as //! in versions 6 and 7). Timestamps aren't encoded the same way by all UUID //! versions so this module provides a single [`Timestamp`] type that can //! convert between them. //! //! # Timestamp representations in UUIDs //! //! Versions 1 and 6 UUIDs use a bespoke timestamp that consists of the //! number of 100ns ticks since `1582-10-15 00:00:00`, along with //! a counter value to avoid duplicates. //! //! Version 7 UUIDs use a more standard timestamp that consists of the //! number of millisecond ticks since the Unix epoch (`1970-01-01 00:00:00`). //! //! # References //! //! * [Timestamp in RFC4122](https://www.rfc-editor.org/rfc/rfc4122#section-4.1.4) //! * [Timestamp in Draft RFC: New UUID Formats, Version 4](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04#section-6.1)
usecrate::Uuid;
/// The number of 100 nanosecond ticks between the RFC4122 epoch /// (`1582-10-15 00:00:00`) and the Unix epoch (`1970-01-01 00:00:00`). pubconst UUID_TICKS_BETWEEN_EPOCHS: u64 = 0x01B2_1DD2_1381_4000;
impl Timestamp { /// Get a timestamp representing the current system time. /// /// This method defers to the standard library's `SystemTime` type. /// /// # Panics /// /// This method will panic if calculating the elapsed time since the Unix epoch fails. #[cfg(feature = "std")] pubfn now(context: impl ClockSequence<Output = u16>) -> Self { #[cfg(not(any(feature = "v1", feature = "v6")))]
{ let _ = context;
}
/// Construct a `Timestamp` from an RFC4122 timestamp and counter, as used /// in versions 1 and 6 UUIDs. pubconstfn from_rfc4122(ticks: u64, counter: u16) -> Self { #[cfg(not(any(feature = "v1", feature = "v6")))]
{ let _ = counter;
}
let (seconds, nanos) = Self::rfc4122_to_unix(ticks);
/// Construct a `Timestamp` from a Unix timestamp, as used in version 7 UUIDs. pubfn from_unix(context: impl ClockSequence<Output = u16>, seconds: u64, nanos: u32) -> Self { #[cfg(not(any(feature = "v1", feature = "v6")))]
{ let _ = context;
/// Get the value of the timestamp as an RFC4122 timestamp and counter, /// as used in versions 1 and 6 UUIDs. #[cfg(any(feature = "v1", feature = "v6"))] pubconstfn to_rfc4122(&self) -> (u64, u16) {
( Self::unix_to_rfc4122_ticks(self.seconds, self.nanos), self.counter,
)
}
/// Get the value of the timestamp as a Unix timestamp, as used in version 7 UUIDs. pubconstfn to_unix(&self) -> (u64, u32) {
(self.seconds, self.nanos)
}
#[deprecated(note = "use `to_unix` instead")] /// Get the number of fractional nanoseconds in the Unix timestamp. /// /// This method is deprecated and probably doesn't do what you're expecting it to. /// It doesn't return the timestamp as nanoseconds since the Unix epoch, it returns /// the fractional seconds of the timestamp. pubconstfn to_unix_nanos(&self) -> u32 { // NOTE: This method never did what it said on the tin: instead of // converting the timestamp into nanos it simply returned the nanoseconds // part of the timestamp. // // We can't fix the behavior because the return type is too small to fit // a useful value for nanoseconds since the epoch. self.nanos
}
}
pub(crate) constfn encode_rfc4122_timestamp(ticks: u64, counter: u16, node_id: &[u8; 6]) -> Uuid { let time_low = (ticks & 0xFFFF_FFFF) as u32; let time_mid = ((ticks >> 32) & 0xFFFF) as u16; let time_high_and_version = (((ticks >> 48) & 0x0FFF) as u16) | (1 << 12);
let secs = (now / 1_000.0) as u64; let nanos = ((now % 1_000.0) * 1_000_000.0) as u32;
dbg!((secs, nanos))
}
#[cfg(all(feature = "std", any(not(feature = "js"), not(target_arch = "wasm32"))))] fn now() -> (u64, u32) { let dur = std::time::SystemTime::UNIX_EPOCH
.elapsed()
.expect("Getting elapsed time since UNIX_EPOCH. If this fails, we've somehow violated causality");
(dur.as_secs(), dur.subsec_nanos())
}
/// A counter that can be used by version 1 and version 6 UUIDs to support /// the uniqueness of timestamps. /// /// # References /// /// * [Clock Sequence in RFC4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.5) pubtrait ClockSequence { /// The type of sequence returned by this counter. type Output;
/// Get the next value in the sequence to feed into a timestamp. /// /// This method will be called each time a [`Timestamp`] is constructed. fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output;
}
impl<'a, T: ClockSequence + ?Sized> ClockSequence for &'a T { type Output = T::Output; fn generate_sequence(&self, seconds: u64, subsec_nanos: u32) -> Self::Output {
(**self).generate_sequence(seconds, subsec_nanos)
}
}
/// Default implementations for the [`ClockSequence`] trait. pubmod context { usesuper::ClockSequence;
#[cfg(any(feature = "v1", feature = "v6"))] use atomic::{Atomic, Ordering};
/// An empty counter that will always return the value `0`. /// /// This type should be used when constructing timestamps for version 7 UUIDs, /// since they don't need a counter for uniqueness. #[derive(Debug, Clone, Copy, Default)] pubstruct NoContext;
impl ClockSequence for NoContext { type Output = u16;
#[cfg(all(any(feature = "v1", feature = "v6"), feature = "std", feature = "rng"))] pub(crate) fn shared_context() -> &'static Context { // If the context is in its initial state then assign it to a random value // It doesn't matter if multiple threads observe `false` here and initialize the context if CONTEXT_INITIALIZED
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
{
CONTEXT.count.store(crate::rng::u16(), Ordering::Release);
}
&CONTEXT
}
/// A thread-safe, wrapping counter that produces 14-bit numbers. /// /// This type should be used when constructing version 1 and version 6 UUIDs. #[derive(Debug)] #[cfg(any(feature = "v1", feature = "v6"))] pubstruct Context {
count: Atomic<u16>,
}
#[cfg(any(feature = "v1", feature = "v6"))] impl Context { /// Construct a new context that's initialized with the given value. /// /// The starting value should be a random number, so that UUIDs from /// different systems with the same timestamps are less likely to collide. /// When the `rng` feature is enabled, prefer the [`Context::new_random`] method. pubconstfn new(count: u16) -> Self { Self {
count: Atomic::<u16>::new(count),
}
}
/// Construct a new context that's initialized with a random value. #[cfg(feature = "rng")] pubfn new_random() -> Self { Self {
count: Atomic::<u16>::new(crate::rng::u16()),
}
}
}
#[cfg(any(feature = "v1", feature = "v6"))] impl ClockSequence for Context { type Output = u16;
fn generate_sequence(&self, _seconds: u64, _nanos: u32) -> Self::Output { // RFC4122 reserves 2 bits of the clock sequence so the actual // maximum value is smaller than `u16::MAX`. Since we unconditionally // increment the clock sequence we want to wrap once it becomes larger // than what we can represent in a "u14". Otherwise there'd be patches // where the clock sequence doesn't change regardless of the timestamp self.count.fetch_add(1, Ordering::AcqRel) % (u16::MAX >> 2)
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.