Générateur ULID - Créez des ID Uniques et Triables en Ligne Gratuitement
Outil gratuit de génération ULID qui crée instantanément des identifiants uniques et triables. Générez des ULID cryptographiquement sécurisés pour bases de données, API et systèmes distribués en ligne.
Générateur ULID
Documentation
Qu’est-ce qu’un ULID ?
Un ULID (Universally Unique Lexicographically Sortable Identifier, identifiant unique universel triable lexicographiquement) est un code de 26 caractères servant à étiqueter des enregistrements dans une base de données ou un événement dans un système distribué. Il combine l’heure actuelle avec des données aléatoires ; une liste de ULID triée par ordre alphabétique se retrouve donc triée selon l’heure de création de chacun. Un générateur de ULID est un outil qui produit ces codes.
Structure d’un ULID
Un ULID comporte deux parties, écrites l’une après l’autre sans séparateur :
- Horodatage (10 caractères) : le nombre de millisecondes écoulées depuis le 1 janvier 1970 (l’époque Unix), stocké sous la forme d’un entier de 48 bits.
- Aléa (16 caractères) : 80 bits de données aléatoires, ajoutés pour que deux ULID créés dans la même milliseconde soient quand même presque certainement différents.
Les deux parties sont écrites avec l’alphabet Base32 de Crockford : les chiffres 0-9 et les lettres A à Z, moins les lettres I, L, O et U. I et L peuvent être confondus avec le chiffre 1, et O avec le chiffre 0. U est exclu pour éviter les mots obscènes accidentels. Le résultat est une chaîne courte, facile à lire à voix haute et qui peut être placée sans risque directement dans une URL.
Comment calculer un ULID
Un générateur de ULID construit un identifiant en trois étapes.
- Lisez l’heure actuelle en millisecondes depuis l’époque Unix. Il s’agit d’un nombre de 48 bits.
- Générez 80 bits de données aléatoires, normalement à l’aide d’un générateur de nombres aléatoires cryptographiquement sûr, ce qui donne 10 octets aléatoires.
- Encodez les deux parties séparément avec l’alphabet Base32 de Crockford : l’horodatage de 48 bits devient 10 caractères, et la valeur aléatoire de 80 bits devient 16 caractères. Les deux chaînes encodées sont assemblées pour former le ULID final de 26 caractères.
L’encodage consiste à lire le nombre par groupes de 5 bits, car chaque caractère Base32 représente l’une des 32 valeurs possibles (2^5 = 32). Dix caractères contiennent jusqu’à 50 bits, ce qui laisse assez de place pour l’horodatage de 48 bits. Seize caractères contiennent exactement 80 bits, ce qui correspond à la partie aléatoire sans aucun reste.
Exemple détaillé
Supposons qu’un générateur de ULID s’exécute à l’horodatage 1712345678901 (millisecondes depuis l’époque) et tire les octets aléatoires [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].
Étape 1 – encodez l’horodatage. Divisez 1712345678901 à plusieurs reprises par 32, en gardant le reste à chaque fois, puis lisez les chiffres du dernier au premier (c’est la conversion de base habituelle). Vous obtenez la chaîne de 10 caractères 01HTQW311N.
Étape 2 – encodez l’aléa. Regroupez les 10 octets aléatoires en un flux de 80 bits, puis lisez-les par groupes de 5 bits, en convertissant chaque bloc de 5 bits en un caractère Base32. Vous obtenez la chaîne de 16 caractères 1KR5G0Y75M3EF00H.
Étape 3 – assemblez les parties. Le ULID final est :
101HTQW311N 1KR5G0Y75M3EF00H
2écrit sans l’espace : 01HTQW311N1KR5G0Y75M3EF00H, soit 26 caractères au total.
ULID et UUID
| Caractéristique | ULID | UUID (version 4) |
|---|---|---|
| Longueur | 26 caractères | 36 caractères (avec tirets) |
| Triable par date de création | Oui | Non |
| Encodage | Base32 de Crockford | Hexadécimal |
| Contient un horodatage | Oui (48 bits) | Non |
| Compatible avec les URL sans échappement | Oui | Oui |
Les deux formats visent à produire des identifiants uniques entre systèmes sans qu’une autorité centrale distribue les numéros. La principale différence pratique concerne le tri : comme un ULID commence par un horodatage, trier des ULID comme du texte brut les trie aussi par date. Un UUID aléatoire n’a pas cette propriété, puisque chacune de ses parties est aléatoire.
Utilisations courantes
- Clés primaires de base de données : les ULID permettent à une base de données d’indexer les nouvelles lignes à peu près dans l’ordre de leur insertion, ce que de nombreux moteurs de base de données gèrent plus efficacement que des clés entièrement aléatoires.
- Systèmes distribués : des serveurs distincts peuvent chacun générer des ULID de façon indépendante, sans se coordonner avec un compteur central, et les résultats restent presque certainement uniques.
- Journaux d’événements : comme les ULID se trient par date, une liste d’identifiants d’événements peut servir de chronologie approximative.
- Identifiants d’API et de fichiers : le format fixe de 26 caractères, compatible avec les URL, s’intègre sans difficulté dans les adresses web et les noms de fichiers.
Parmi les formats d’identifiants apparentés figurent KSUID, qui encode lui aussi un horodatage pour le tri, et les identifiants Snowflake, utilisés par Twitter et d’autres, qui combinent un horodatage, un identifiant de machine et un compteur.
Exemples de code
Chaque exemple ci-dessous construit un ULID comme le décrit la spécification ULID : encoder l’horodatage de 48 bits en 10 caractères Base32 de Crockford, encoder 80 bits d’aléa en 16 autres caractères, puis les assembler.
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());
33Python
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())
32Java
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}
41Questions fréquentes
À quoi sert un ULID ? Un ULID sert d’identifiant unique pour une ligne de base de données, une ressource d’API ou un événement journalisé, lorsque le tri par date de création est aussi utile.
Quelle est la longueur d’un ULID ? Un ULID fait toujours 26 caractères : 10 pour l’horodatage et 16 pour la partie aléatoire.
Quel encodage un ULID utilise-t-il ? Un ULID utilise l’alphabet Base32 de Crockford, composé des chiffres 0-9 et des lettres A à Z, sans I, L, O ni U, afin d’éviter les erreurs de lecture et les mots accidentels.
En quoi un ULID diffère-t-il d’un UUID ? Un ULID se trie par date de création et fait 26 caractères. Un UUID aléatoire (version 4) ne se trie pas par date et fait 36 caractères, tirets compris.
Quelle est la probabilité d’une collision entre deux ULID ? Les 80 bits d’aléa rendent les collisions extrêmement improbables. Il faudrait générer environ 1,3 billion de ULID dans la même milliseconde pour atteindre 50 % de chances que deux d’entre eux soient identiques.
Peut-on générer des ULID sans connexion Internet ? Oui. Un ULID n’a besoin que de l’horloge locale et d’un générateur de nombres aléatoires ; il peut donc être créé entièrement hors ligne.
Références
- ULID project. Universally Unique Lexicographically Sortable Identifier. ULID specification — horodatage en millisecondes sur 48 bits, 80 bits d’aléa, forme canonique de 10 + 16 caractères, alphabet Base32 de Crockford.
- Douglas Crockford. Base 32. Crockford's Base32 — l’alphabet de 32 symboles et la raison pour laquelle I, L, O et U sont exclus.