To decode a ULID timestamp, take the first 10 of its 26 Crockford Base32 characters as a 48-bit Unix millisecond value; the final 16 characters carry 80 bits of randomness and do not affect the time. A ULID is designed for lexical sorting because that timestamp occupies the leftmost part of the identifier, so a correctly stored canonical string can also reveal approximate creation time. The ULID Generator handles the exact job: choose Generate to create 1 to 100 monotonic IDs, or choose Decode, paste a canonical ULID, and read its millisecond value and ISO UTC instant. Generation and decoding happen locally in the browser, so the identifier and timestamp are not uploaded. This guide doubles as a decode cheat sheet: it maps every character, explains the 48-bit and 80-bit boundaries, shows how to store generated values without weakening ordering, and calls out the cases that require rejection rather than a guessed date.

decode ulid timestamp cheat sheet
Decode ULID Timestamp Cheat Sheet: Fields and Limits

Why the ULID Generator fits the task

The ULID Generator handles both generation and timestamp decoding in one browser-based workflow. It creates canonical 26-character sortable identifiers with a 48-bit time field and an 80-bit random field. Generate mode produces a batch of monotonic IDs, while Decode mode reads the millisecond timestamp from an existing canonical string. The tool is useful when you need to inspect a ULID, create identifiers for an application test, or verify that stored values still have the expected format. Generation, decoding, formatting, and copying remain in the browser, so the identifier and decoded timestamp are not uploaded.

The ULID field map

A ULID’s sortable behavior comes from the position of its fields. The timestamp comes first, which allows ordinary lexical comparison to group identifiers by time. The random component follows the timestamp and supplies uniqueness support, but it has no role in calculating the embedded date.

ComponentPosition or formatMeaning
Timestamp fieldFirst 10 characters48-bit Unix timestamp in milliseconds
Random fieldFinal 16 characters80 bits of randomness
Canonical representation26 Crockford Base32 charactersFixed-width sortable identifier
Canonical alphabet32 possible symbolsI, L, O, and U are excluded
Timestamp range48-bit unsigned value0 through 281474976710655 milliseconds
Ordering assumptionComplete 26-character stringBytewise or ASCII-compatible lexical collation

Manual decode rule: the millisecond value is the unsigned integer represented by characters 1 through 10 in Crockford Base32. The final 16 characters do not change that calculation. The decoder accepts input case-insensitively after normalization, but it accepts only characters from the canonical alphabet after normalization. Keep the stored form uppercase because case-folding can interfere with lexical ordering. The Canonical ULID specification provides the authoritative field layout and encoding rules.

Decode a ULID timestamp in three steps

The following workflow covers generation, durable storage, and decoding without requiring you to inspect characters by eye.

  1. Choose Generate and set the quantity. Select a quantity from 1 through 100 and create a monotonic batch of identifiers.
  2. Copy the complete identifiers into storage. Preserve all 26 characters in a case-preserving field and enforce uniqueness with a database constraint.
  3. Choose Decode and read the embedded time. Paste a canonical ULID, then read the displayed millisecond value and UTC timestamp.

The Decode control is scoped to canonical 26-character values. Its output includes both the underlying millisecond value and the UTC instant, with the displayed ISO time representing UTC. A local calendar presentation can show a different date because of the time zone, even though the millisecond value has not changed. When validating an identifier received from another system, check its length, canonical alphabet, case policy, and timestamp range before treating the decoded result as valid application data.

Monotonic batches and their exact boundary

Each Generate click captures one integer millisecond and uses that same value for every ID in the clicked batch. The browser cryptographic random source supplies the initial 80-bit random value. The generator then increments the random region by one for each subsequent identifier, including carry, so the returned strings are strictly increasing in normal ASCII lexical order.

That ordering guarantee applies inside the batch. The tool does not retain identifiers or hidden state across separate clicks, and it cannot coordinate with other tabs, devices, services, or previously generated values. If incrementing the random region would overflow its 80-bit field, generation fails instead of wrapping. Use the generated order for its stated purpose, but do not treat a monotonic batch as a global uniqueness mechanism across independent systems.

Reading the timestamp without overinterpreting it

The millisecond value was captured when the identifier’s batch was generated; decoding only recovers that embedded value. It is useful metadata for ordered indexes, log correlation, and understanding the sequence of records. It is not an authenticated fact about when a trusted event occurred. Anyone who understands the format can derive the approximate creation time from the identifier, so a decoded timestamp should not be used as proof that a record or event is genuine.

The time field must fit the 48-bit unsigned range from zero through 281474976710655 milliseconds. The maximum canonical string therefore begins with 7. A 26-character Base32 value beginning with 8 or above contains more than 128 bits and is rejected. This is a representation boundary rather than a reason to guess or adjust the date. Use the decoder’s millisecond value and UTC instant as the result, while remembering that a local calendar view can differ by time zone.

Store the full ULID in an order-safe schema

Keep the full uppercase 26-character value in a case-preserving database column. Intended lexical ordering assumes the canonical representation and ordinary bytewise or ASCII-compatible collation. Case-folding, locale-sensitive collation, truncation, padding, or an undersized column can break the expected order. Test the exact database collation and schema rather than assuming that two technically case-preserving fields will sort identically.

A durable database should enforce a unique constraint and handle a conflict atomically. Randomness reduces collision probability, but it does not create an absolute uniqueness guarantee. A check-then-insert workflow leaves a race window, so it must not be the final uniqueness control. The generator checks batch construction and monotonic overflow, yet it cannot detect a conflict with a value created elsewhere.

Storage or control choicePossible consequenceSafer approach
Case-folding or locale-sensitive collationLexical order can differ from canonical orderPreserve case and test the exact collation
Truncation, padding, or an undersized columnThe full identifier or its intended order can be lostAllow all 26 canonical characters
Check-then-insert without atomic conflict handlingConcurrent requests can raceUse a unique constraint and handle the conflict atomically
Randomness without database enforcementCollisions are not absolutely preventedKeep uniqueness control at the durable data layer

Limits and security boundaries to remember

A ULID is an identifier, not a password, API key, bearer token, authorization rule, or encryption key. Its visible timestamp and random suffix do not protect a record from enumeration or disclosure when access control is missing. Generate credentials with the target platform’s dedicated mechanism and keep those credentials in a secret manager rather than repurposing a ULID.

Do not use a ULID when approximate creation time must remain hidden. Avoid logging ULIDs associated with personal or confidential records because a log can become another disclosure path. The fact that generation and decoding happen locally reduces data-transfer exposure, but it does not replace application access controls or careful logging policies.

The practical cheat-sheet rule is simple: preserve the canonical 26 characters, keep the timestamp within its defined range, enforce uniqueness in the database, and treat the decoded time as visible metadata rather than authenticated truth.