namespace DodoSSH.Client.Domain; /// /// Reads the moment a version 7 identifier was created back out of it. /// /// /// /// Why this exists. No vault item carries a timestamp. VaultItem is an id, a secret, a version /// and three sync flags, and the server's created_at is deliberately not handed back — so a screen /// that wants to say when something was added has nothing to read. Every id this client mints goes through /// , which is banned-symbol policy rather than preference (see /// BannedSymbols.txt), and RFC 9562 puts 48 bits of Unix milliseconds in the first six bytes of one. /// That is a real creation time, already stored, costing nothing. /// /// /// What it is not. It is when the item was created, never when it was last changed — an /// update keeps the id. A screen showing this has to say so, or it is quietly presenting a creation date as /// a modification date. And an id minted anywhere else, by an older client or another implementation, is not /// a v7 at all; that case answers null rather than a number derived from bytes that mean something else. /// /// public static class Uuid7Timestamp { /// Where the version nibble lives in the RFC byte order. private const int VersionByte = 6; /// /// The creation time recorded in a version 7 identifier, or null if it is not one. /// public static DateTimeOffset? Of(Guid id) { Span bytes = stackalloc byte[16]; // Big-endian, which is the whole reason this is not two lines of shifting. Guid's own layout stores // its first three fields in the host's byte order, so the little-endian overload scrambles exactly // the six bytes being read here — and does it silently, producing dates in the year 30000 rather // than an error. if (!id.TryWriteBytes(bytes, bigEndian: true, out _)) { return null; } if ((bytes[VersionByte] & 0xF0) != 0x70) { return null; } long milliseconds = 0; for (var i = 0; i < 6; i++) { milliseconds = (milliseconds << 8) | bytes[i]; } return DateTimeOffset.FromUnixTimeMilliseconds(milliseconds); } }