簡単に言えば ULID(128ビット) の 64 ビット版で同一ファイル内で重複しなければ良い、という時に使うモノ。
Unity で使われる ID は long
である場合が多く、しかし Ulid は long long
。ということで 8 バイトの ULID 的なモノが必要な時もあるでしょう。
構造
YearOffset(7) Month(4) Day(5) Hour(5) Minute(6) Second(6) Millisec(10)
計43ビット
+
乱数か連番
21ビット
タイムスタンプは ULID の 48 ビットより 5 ビット短く、ミリ秒毎に作れる数も必要十分(2,097,152個)。対応年数は最大で基準年から128年間。
ULID 同様に作成順にソートも可能なはず。
実行結果 👉 https://dotnetfiddle.net/pmC9kz
using System;
public class Program
{
const int YEAR_ORIGIN = 2000;
const int ID_MAX = 2097151; // 2 ^ 21 - 1;
public static void Main()
{
var rng = new Random();
var now = DateTime.UtcNow;
// randomize lower bits.
long id = (long)(now.Year - YEAR_ORIGIN) << 57;
id |= (long)now.Month << 53;
id |= (long)now.Day << 48;
//id |= (long)now.DayOfYear << 48;
id |= (long)now.Hour << 43;
id |= (long)now.Minute << 37;
id |= (long)now.Second << 31;
id |= (long)now.Millisecond << 21;
id |= rng.Next(0, ID_MAX);
Console.WriteLine("random lower: " + id.ToString("X2") + ": " + id);
// randomize upper bits.
id = (long)(now.Year - YEAR_ORIGIN) << 36;
id |= (long)now.Month << 32;
id |= (long)now.Day << 27;
//id |= (long)now.DayOfYear << 27;
id |= (long)now.Hour << 22;
id |= (long)now.Minute << 16;
id |= (long)now.Second << 10;
id |= (long)now.Millisecond;
id |= ((long)rng.Next(0, ID_MAX)) << 43;
Console.WriteLine("random upper: " + id.ToString("X2") + ": " + id);
// set sign bit.
id |= long.MinValue; // 0x80L << 56;
Console.WriteLine("set sign bit: " + id.ToString("X2") + ": " + id);
// remove sign bit.
id &= ~long.MinValue;
Console.WriteLine(" no sign bit: " + id.ToString("X2") + ": " + id);
}
}
--
ID の正負で動作を変えるような事をやる場合は相対日時を下位ビットにしたほうが良いんだろうけど、日付順の並び替えが面倒になる。もどかしい。
以上です。お疲れ様でした。