Vai al contenuto

Generatore ULID - Crea ID Unici e Ordinabili Online Gratuitamente

Strumento gratuito per generare ULID che crea identificatori unici e ordinabili istantaneamente. Genera ULID crittograficamente sicuri per database, API e sistemi distribuiti online.

Generatore ULID

Inserisci un valore per visualizzare i risultati
Calcolatore di caricamento...
📚

Documentazione

Che cos'è un ULID?

Un ULID (identificatore universalmente univoco e ordinabile lessicograficamente) è un codice di 26 caratteri usato per identificare i record in un database o un evento in un sistema distribuito. Combina l'ora corrente con dati casuali, perciò un elenco di ULID ordinato alfabeticamente finisce per essere ordinato in base all'ora di creazione di ciascuno. Un generatore di ULID è uno strumento che produce questi codici.

Struttura di un ULID

Un ULID ha due parti, scritte una dopo l'altra senza separatore:

  • Marca temporale (10 caratteri): il numero di millisecondi trascorsi dal 1 gennaio 1970 (l'epoca Unix), rappresentato su un massimo di 48 bit.
  • Casualità (16 caratteri): 80 bit di dati casuali, aggiunti in modo che due ULID creati nello stesso millisecondo siano comunque quasi certamente diversi.

Entrambe le parti sono scritte utilizzando l'alfabeto Base32 di Crockford: le cifre 0–9 e le lettere dalla A alla Z, escluse I, L, O e U. Queste quattro lettere sono omesse perché possono essere confuse con le cifre 0 e 1 oppure tra loro. Il risultato è una stringa breve, facile da leggere ad alta voce e sicura da inserire direttamente in un URL.

Come calcolare un ULID

Un generatore di ULID costruisce un identificatore in tre passaggi.

  1. Leggere l'ora corrente in millisecondi dall'epoca Unix. È un numero di 48 bit.
  2. Generare 80 bit di dati casuali, normalmente tramite un generatore di numeri casuali crittograficamente sicuro, ottenendo 10 byte casuali.
  3. Codificare separatamente entrambe le parti utilizzando l'alfabeto Base32 di Crockford: la marca temporale di 48 bit diventa 10 caratteri, mentre il valore casuale di 80 bit diventa 16 caratteri. Le due stringhe codificate vengono unite per formare l'ULID finale di 26 caratteri.

La codifica funziona leggendo il numero 5 bit alla volta, perché ogni carattere Base32 rappresenta uno dei 32 valori possibili (2^5 = 32). Dieci caratteri contengono fino a 50 bit, una quantità sufficiente per la marca temporale di 48 bit. Sedici caratteri contengono esattamente 80 bit, in corrispondenza della parte casuale senza bit residui.

Esempio di calcolo

Supponiamo che un generatore di ULID venga eseguito alla marca temporale 1712345678901 (millisecondi dall'epoca) e generi i byte casuali [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].

Passaggio 1 – codificare la marca temporale. Dividere ripetutamente 1712345678901 per 32, prendendo ogni volta il resto e leggendo le cifre dall'ultima alla prima (questa è la conversione standard di base). Si ottiene la stringa di 10 caratteri 01HTQW311N.

Passaggio 2 – codificare la casualità. Impacchettare i 10 byte casuali in un flusso di 80 bit, quindi leggere 5 bit alla volta, convertendo ogni blocco di 5 bit in un carattere Base32. Si ottiene la stringa di 16 caratteri 1KR5G0Y75M3EF00H.

Passaggio 3 – unire le parti. L'ULID finale è:

101HTQW311N 1KR5G0Y75M3EF00H
2

scritto senza lo spazio: 01HTQW311N1KR5G0Y75M3EF00H, per un totale di 26 caratteri.

Utilizzo di questo generatore

Il generatore viene eseguito nel browser. Ogni ULID viene costruito utilizzando l'orologio del browser e 80 nuovi bit casuali prelevati dal generatore di numeri casuali crittografici del browser, quindi nessun identificatore viene inviato a un server o recuperato da esso.

  • Numero di ULID accetta un numero intero da 1 a 50. Il valore predefinito è 1.
  • Genera ULID produce un nuovo gruppo. Anche modificando il numero viene prodotto un nuovo gruppo.
  • Copia su un risultato copia quell'unico ULID. Quando ne viene mostrato più di uno, Copia tutto copia l'intero elenco, con un ULID per riga.
  • Reimposta riporta il numero a 1 e genera un nuovo ULID.

Sotto i risultati, il pannello Struttura ULID divide il primo ULID del gruppo nelle sue due parti: i primi 10 caratteri (la marca temporale) e gli ultimi 16 (la casualità).

ULID e UUID a confronto

CaratteristicaULIDUUID (versione 4)
Lunghezza26 caratteri36 caratteri (con trattini)
Ordinabile in base all'ora di creazioneSìNo
CodificaBase32 di CrockfordEsadecimale
Contiene una marca temporaleSì (48 bit)No
Sicuro per gli URL senza codificaSìSì

Entrambi i formati mirano a produrre identificatori univoci tra sistemi senza che un'autorità centrale assegni i numeri. La principale differenza pratica riguarda l'ordinamento: poiché un ULID inizia con una marca temporale, ordinare gli ULID come semplice testo li ordina anche in base all'ora. Un UUID casuale non possiede questa proprietà, perché ogni sua parte è casuale.

Usi comuni

  • Chiavi primarie dei database: gli ULID consentono a un database di indicizzare le nuove righe approssimativamente nell'ordine in cui sono state inserite, cosa che molti motori di database gestiscono in modo più efficiente rispetto a chiavi completamente casuali.
  • Sistemi distribuiti: server separati possono generare ULID autonomamente, senza coordinarsi con un contatore centrale, e i risultati sono comunque quasi certamente univoci.
  • Registri degli eventi: poiché gli ULID vengono ordinati in base all'ora, un elenco di ID degli eventi può fungere anche da cronologia approssimativa.
  • Identificatori per API e file: il formato fisso di 26 caratteri, sicuro per gli URL, funziona correttamente negli indirizzi web e nei nomi dei file.

Tra i formati di identificatori correlati figurano KSUID, che codifica anch'esso una marca temporale per l'ordinamento, e gli ID Snowflake, utilizzati da Twitter e altri, che combinano una marca temporale, un identificatore della macchina e un contatore.

Esempi di codice

Ogni esempio seguente costruisce un ULID nello stesso modo descritto dalla specifica ULID: codifica la marca temporale di 48 bit in 10 caratteri Base32 di Crockford, codifica 80 bit di casualità in altri 16 caratteri e li unisce.

JavaScript

1const ENCODING_CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
2
3function encodeULID(time, randomBytes) {
4  // Timestamp: 48 bits -> 10 characters
5  let timestampStr = '';
6  let t = time;
7  for (let i = 0; i < 10; i++) {
8    timestampStr = ENCODING_CHARS[t % 32] + timestampStr;
9    t = Math.floor(t / 32);
10  }
11
12  // Randomness: 80 bits -> 16 characters
13  let result = timestampStr;
14  let bits = 0;
15  let bitCount = 0;
16  for (let i = 0; i < 10; i++) {
17    bits = (bits << 8) | randomBytes[i];
18    bitCount += 8;
19    while (bitCount >= 5) {
20      bitCount -= 5;
21      result += ENCODING_CHARS[(bits >> bitCount) & 0x1f];
22    }
23  }
24  return result;
25}
26
27function generateULID() {
28  const randomBytes = crypto.getRandomValues(new Uint8Array(10));
29  return encodeULID(Date.now(), randomBytes);
30}
31
32console.log(generateULID());
33

Python

1import os
2import time
3
4ENCODING_CHARS = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
5
6def encode_ulid(time_ms, random_bytes):
7    # Timestamp: 48 bits -> 10 characters
8    chars = []
9    t = time_ms
10    for _ in range(10):
11        chars.append(ENCODING_CHARS[t % 32])
12        t //= 32
13    timestamp_part = "".join(reversed(chars))
14
15    # Randomness: 80 bits -> 16 characters
16    bits = 0
17    bit_count = 0
18    random_part = []
19    for byte in random_bytes:
20        bits = (bits << 8) | byte
21        bit_count += 8
22        while bit_count >= 5:
23            bit_count -= 5
24            random_part.append(ENCODING_CHARS[(bits >> bit_count) & 0x1F])
25
26    return timestamp_part + "".join(random_part)
27
28def generate_ulid():
29    return encode_ulid(int(time.time() * 1000), os.urandom(10))
30
31print(generate_ulid())
32

Java

1import java.security.SecureRandom;
2import java.time.Instant;
3
4public class ULIDGenerator {
5    private static final SecureRandom random = new SecureRandom();
6    private static final char[] ENCODING_CHARS =
7        "0123456789ABCDEFGHJKMNPQRSTVWXYZ".toCharArray();
8
9    public static String generateULID() {
10        long timestamp = Instant.now().toEpochMilli();
11        byte[] randomBytes = new byte[10];
12        random.nextBytes(randomBytes);
13
14        // Timestamp: 48 bits -> 10 characters
15        char[] timestampChars = new char[10];
16        long t = timestamp;
17        for (int i = 9; i >= 0; i--) {
18            timestampChars[i] = ENCODING_CHARS[(int) (t % 32)];
19            t /= 32;
20        }
21
22        // Randomness: 80 bits -> 16 characters
23        StringBuilder result = new StringBuilder(new String(timestampChars));
24        long bits = 0;
25        int bitCount = 0;
26        for (byte b : randomBytes) {
27            bits = (bits << 8) | (b & 0xFF);
28            bitCount += 8;
29            while (bitCount >= 5) {
30                bitCount -= 5;
31                result.append(ENCODING_CHARS[(int) ((bits >> bitCount) & 0x1F)]);
32            }
33        }
34        return result.toString();
35    }
36
37    public static void main(String[] args) {
38        System.out.println(generateULID());
39    }
40}
41

Domande frequenti

A cosa serve un ULID? Un ULID viene utilizzato come identificatore univoco per una riga di database, una risorsa API o un evento registrato, nei casi in cui sia utile anche ordinare in base all'ora di creazione.

Quanto è lungo un ULID? Un ULID è sempre lungo 26 caratteri: 10 caratteri per la marca temporale e 16 per la parte casuale.

Quale codifica utilizza un ULID? Un ULID utilizza l'alfabeto Base32 di Crockford, composto dalle cifre 0–9 e dalle lettere dalla A alla Z, con I, L, O e U rimosse per evitare confusione con altri caratteri.

In che modo un ULID differisce da un UUID? Un ULID viene ordinato in base all'ora di creazione ed è lungo 26 caratteri. Un UUID casuale (versione 4) non viene ordinato in base all'ora ed è lungo 36 caratteri, inclusi i trattini.

Quanto è probabile una collisione tra due ULID? Gli 80 bit di casualità rendono le collisioni estremamente improbabili. Sarebbe necessario generare circa 1,3 trilioni di ULID nello stesso millisecondo per raggiungere una probabilità del 50% che due qualsiasi coincidano.

È possibile generare ULID senza una connessione Internet? Sì. Un ULID richiede soltanto l'orologio locale e un generatore di numeri casuali, quindi può essere creato interamente offline.

Riferimenti

  1. "ULID Specification." GitHub, https://github.com/ulid/spec.
  2. "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.