42 lines
1.2 KiB
C#
42 lines
1.2 KiB
C#
using System.Security.Cryptography;
|
||
|
||
namespace Fleet.Core;
|
||
|
||
/// <summary>26 个字符的 ULID(Crockford base32,前 48 位为毫秒时间戳),按时间可排序。</summary>
|
||
public static class Ulid
|
||
{
|
||
private const string Alphabet = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
||
|
||
public static string New(TimeProvider time)
|
||
{
|
||
long ms = time.GetUtcNow().ToUnixTimeMilliseconds();
|
||
Span<byte> random = stackalloc byte[10];
|
||
RandomNumberGenerator.Fill(random);
|
||
|
||
Span<char> chars = stackalloc char[26];
|
||
for (int i = 9; i >= 0; i--)
|
||
{
|
||
chars[i] = Alphabet[(int)(ms & 31)];
|
||
ms >>= 5;
|
||
}
|
||
|
||
// 80 位随机数 → 16 个 base32 字符
|
||
UInt128 r = 0;
|
||
foreach (byte b in random)
|
||
{
|
||
r = (r << 8) | b;
|
||
}
|
||
|
||
for (int i = 25; i >= 10; i--)
|
||
{
|
||
chars[i] = Alphabet[(int)(r & 31)];
|
||
r >>= 5;
|
||
}
|
||
|
||
return new string(chars);
|
||
}
|
||
|
||
/// <summary>带类型前缀的 ID,例如 <c>agt_01J…</c>。</summary>
|
||
public static string NewPrefixed(string prefix, TimeProvider time) => prefix + "_" + New(time);
|
||
}
|