Skip to content

Commit 47991e8

Browse files
committed
Create UUIDv6.cs
Class Library to generate Universally Unique Identifier (UUID) / Globally Unique Identifier (GUID) based on Version 6 (date-time). Epoch based on Gregorian Calendar. Create UUIDv7.cs Class Library to generate Universally Unique Identifier (UUID) / Globally Unique Identifier (GUID) based on Version 7 (date-time). Epoch based on Unix Epoch.
1 parent 924fbfe commit 47991e8

File tree

11 files changed

+517
-8
lines changed

11 files changed

+517
-8
lines changed

.github/workflows/codeql-analysis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ name: "CodeQL"
1313

1414
on:
1515
push:
16-
branches: [ "master" ]
16+
branches: [ "**" ]
1717
pull_request:
1818
# The branches below must be a subset of the branches above
1919
branches: [ "master" ]

.github/workflows/dotnet.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: .NET
22

33
on:
44
push:
5-
branches: [ "master" ]
5+
branches: [ "**" ]
66
pull_request:
77
branches: [ "master" ]
88

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88

99
## [Unreleased]
1010

11+
## [v1.2.0-alpha] - 2022-12-15
12+
[v1.2.0-alpha](https://github.com/TensionDev/UUIDUtil/releases/tag/v1.2.0-alpha)
13+
14+
### Added
15+
- Added UUID v6 generated based on current system date and time as well as local Network MAC Address.
16+
- Added UUID v6 generated based on current system date and time as well as supplied Network MAC Address.
17+
- Added UUID v6 generated based on supplied system date and time as well as local Network MAC Address.
18+
- Added UUID v6 generated based on supplied system date and time as well as supplied Network MAC Address.
19+
- Added UUID v7 generated based on current system date and time as well as generated random fields.
20+
- Added UUID v7 generated based on supplied system date and time as well as generated random fields.
21+
- Added UUID v7 generated based on supplied system date and time as well as supplied random fields.
22+
23+
1124
## [v1.1.0] - 2022-05-31
1225
[v1.1.0](https://github.com/TensionDev/UUIDUtil/releases/tag/v1.1.0)
1326

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ This project references the following documents for implementation.
99
- [Universally unique identifier - Wikipedia](https://en.wikipedia.org/wiki/Universally_unique_identifier)
1010
- [MySQL :: MySQL 8.0 Reference Manual :: 12.24 Miscellaneous Functions](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid)
1111
- [rfc4122](https://datatracker.ietf.org/doc/html/rfc4122)
12+
- [draft-peabody-dispatch-new-uuid-format-04](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format)

UUIDUtil/UUIDUtil.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
88
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
99
<PackageId>TensionDev.UUID</PackageId>
10-
<Version>1.1.0</Version>
10+
<Version>1.2.0-alpha</Version>
1111
<Authors>TensionDev amsga</Authors>
1212
<Company>TensionDev</Company>
1313
<Product>TensionDev.UUID</Product>
@@ -18,10 +18,10 @@
1818
<RepositoryUrl>https://github.com/TensionDev/UUIDUtil</RepositoryUrl>
1919
<RepositoryType>git</RepositoryType>
2020
<PackageTags>UUID GUID</PackageTags>
21-
<PackageReleaseNotes>Release with UUID / GUID Version 1, Version 3, Version 4 and Version 5.</PackageReleaseNotes>
21+
<PackageReleaseNotes>Release with UUID / GUID Version 1, Version 3, Version 4 and Version 5, and Draft Versions 6 and 7.</PackageReleaseNotes>
2222
<NeutralLanguage>en-SG</NeutralLanguage>
23-
<AssemblyVersion>1.1.0.0</AssemblyVersion>
24-
<FileVersion>1.1.0.0</FileVersion>
23+
<AssemblyVersion>1.2.0.0</AssemblyVersion>
24+
<FileVersion>1.2.0.0</FileVersion>
2525
<IncludeSymbols>true</IncludeSymbols>
2626
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
2727
</PropertyGroup>

UUIDUtil/UUIDv6.cs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
using System;
2+
3+
namespace TensionDev.UUID
4+
{
5+
/// <summary>
6+
/// Class Library to generate Universally Unique Identifier (UUID) / Globally Unique Identifier (GUID) based on Version 6 (date-time).
7+
/// </summary>
8+
public class UUIDv6
9+
{
10+
protected internal static Int32 s_clock = Int32.MinValue;
11+
protected internal static DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc);
12+
13+
protected internal static Object s_initLock = new Object();
14+
protected internal static Object s_clockLock = new Object();
15+
16+
/// <summary>
17+
/// Initialises a new GUID/UUID based on Version 6 (date-time)
18+
/// </summary>
19+
/// <returns>A new Uuid object</returns>
20+
public static Uuid NewUUIDv6()
21+
{
22+
return NewUUIDv6(DateTime.UtcNow);
23+
}
24+
25+
/// <summary>
26+
/// Initialises the 48-bit Node ID and returns it.<br />
27+
/// Returns a randomly genrated 48-bit Node ID.
28+
/// </summary>
29+
/// <returns>A byte-array representing the 48-bit Node ID</returns>
30+
public static Byte[] GetNodeID()
31+
{
32+
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
33+
{
34+
Byte[] fakeNode = new Byte[6];
35+
cryptoServiceProvider.GetBytes(fakeNode);
36+
return fakeNode;
37+
}
38+
}
39+
40+
/// <summary>
41+
/// Intialises the 14-bit Clock Sequence and returns the current value with the Variant.<br />
42+
/// Will return an incremented Clock Sequence on each call, modulo 14-bit.
43+
/// </summary>
44+
/// <returns>A byte-array representing the 14-bit Clock Sequence, together with the Variant</returns>
45+
public static Byte[] GetClockSequence()
46+
{
47+
lock (s_initLock)
48+
{
49+
if (s_clock < 0)
50+
{
51+
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
52+
{
53+
Byte[] clockInit = new Byte[4];
54+
cryptoServiceProvider.GetBytes(clockInit);
55+
s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF;
56+
s_clock |= 0x8000;
57+
}
58+
}
59+
}
60+
61+
Int32 result;
62+
lock (s_clockLock)
63+
{
64+
result = s_clock++;
65+
if (s_clock >= 0xC000)
66+
s_clock = 0x8000;
67+
}
68+
69+
return BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder((Int16)result));
70+
}
71+
72+
/// <summary>
73+
/// Initialises a new GUID/UUID based on Version 6 (date-time), based on the given date and time.
74+
/// </summary>
75+
/// <param name="dateTime">Given Date and Time</param>
76+
/// <returns>A new Uuid object</returns>
77+
public static Uuid NewUUIDv6(DateTime dateTime)
78+
{
79+
return NewUUIDv6(dateTime, GetClockSequence(), GetNodeID());
80+
}
81+
82+
/// <summary>
83+
/// Initialises a new GUID/UUID based on Version 6 (date-time), based on the given Node ID.
84+
/// </summary>
85+
/// <param name="nodeID">Given 48-bit Node ID</param>
86+
/// <returns>A new Uuid object</returns>
87+
/// <exception cref="ArgumentNullException"></exception>
88+
/// <exception cref="ArgumentException"></exception>
89+
public static Uuid NewUUIDv6(Byte[] nodeID)
90+
{
91+
return NewUUIDv6(DateTime.UtcNow, GetClockSequence(), nodeID);
92+
}
93+
94+
/// <summary>
95+
/// Initialises a new GUID/UUID based on Version 6 (date-time), based on the given date and time, Clock Sequence with Variant and Node ID.
96+
/// </summary>
97+
/// <param name="dateTime">Given Date and Time</param>
98+
/// <param name="clockSequence">Given 16-bit Clock Sequence with Variant</param>
99+
/// <param name="nodeID">Given 48-bit Node ID</param>
100+
/// <returns>A new Uuid object</returns>
101+
/// <exception cref="ArgumentNullException"></exception>
102+
/// <exception cref="ArgumentException"></exception>
103+
public static Uuid NewUUIDv6(DateTime dateTime, Byte[] clockSequence, Byte[] nodeID)
104+
{
105+
if (clockSequence == null)
106+
throw new ArgumentNullException(nameof(clockSequence));
107+
108+
if (clockSequence.Length < 2)
109+
throw new ArgumentException(String.Format("Clock Sequence contains less than 16-bit: {0} bytes", clockSequence.Length), nameof(clockSequence));
110+
111+
if (nodeID == null)
112+
throw new ArgumentNullException(nameof(nodeID));
113+
114+
if (nodeID.Length < 6)
115+
throw new ArgumentException(String.Format("Node ID contains less than 48-bit: {0} bytes", nodeID.Length), nameof(nodeID));
116+
117+
TimeSpan timesince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
118+
Int64 timeinterval = timesince.Ticks << 4;
119+
120+
Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeinterval));
121+
122+
Byte[] hex = new Byte[16];
123+
124+
hex[0] = time[0];
125+
hex[1] = time[1];
126+
hex[2] = time[2];
127+
hex[3] = time[3];
128+
129+
hex[4] = time[4];
130+
hex[5] = time[5];
131+
132+
hex[6] = (Byte)(((time[6] >> 4) & 0x0F) + 0x60);
133+
hex[7] = (Byte)((time[6] << 4) + (time[7] >> 4));
134+
135+
hex[8] = clockSequence[0];
136+
hex[9] = clockSequence[1];
137+
138+
hex[10] = nodeID[0];
139+
hex[11] = nodeID[1];
140+
hex[12] = nodeID[2];
141+
hex[13] = nodeID[3];
142+
hex[14] = nodeID[4];
143+
hex[15] = nodeID[5];
144+
145+
Uuid Id = new Uuid(hex);
146+
147+
return Id;
148+
}
149+
}
150+
}

UUIDUtil/UUIDv7.cs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
using System;
2+
3+
namespace TensionDev.UUID
4+
{
5+
/// <summary>
6+
/// Class Library to generate Universally Unique Identifier (UUID) / Globally Unique Identifier (GUID) based on Version 7 (date-time).
7+
/// </summary>
8+
public class UUIDv7
9+
{
10+
protected internal static DateTime s_epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
11+
12+
/// <summary>
13+
/// Initialises a new GUID/UUID based on Version 7 (date-time)
14+
/// </summary>
15+
/// <returns>A new Uuid object</returns>
16+
public static Uuid NewUUIDv7()
17+
{
18+
return NewUUIDv7(DateTime.UtcNow);
19+
}
20+
21+
/// <summary>
22+
/// Initialises the 12-bit rand_a and returns it.<br />
23+
/// Returns a randomly genrated 16-bit rand_a.
24+
/// </summary>
25+
/// <returns>A byte-array representing the 16-bit rand_a</returns>
26+
public static Byte[] GetRandomA()
27+
{
28+
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
29+
{
30+
Byte[] fakeNode = new Byte[2];
31+
cryptoServiceProvider.GetBytes(fakeNode);
32+
return fakeNode;
33+
}
34+
}
35+
36+
/// <summary>
37+
/// Initialises the 62-bit rand_b and returns it.<br />
38+
/// Returns a randomly genrated 64-bit rand_b.
39+
/// </summary>
40+
/// <returns>A byte-array representing the 64-bit rand_b</returns>
41+
public static Byte[] GetRandomB()
42+
{
43+
using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
44+
{
45+
Byte[] fakeNode = new Byte[8];
46+
cryptoServiceProvider.GetBytes(fakeNode);
47+
return fakeNode;
48+
}
49+
}
50+
51+
/// <summary>
52+
/// Initialises a new GUID/UUID based on Version 7 (date-time), based on the given date and time.
53+
/// </summary>
54+
/// <param name="dateTime">Given Date and Time</param>
55+
/// <returns>A new Uuid object</returns>
56+
public static Uuid NewUUIDv7(DateTime dateTime)
57+
{
58+
return NewUUIDv7(dateTime, GetRandomA(), GetRandomB());
59+
}
60+
61+
/// <summary>
62+
/// Initialises a new GUID/UUID based on Version 7 (date-time), based on the given date and time, Clock Sequence with Variant and Node ID.
63+
/// </summary>
64+
/// <param name="dateTime">Given Date and Time</param>
65+
/// <param name="randomA">Given 16-bit rand_a</param>
66+
/// <param name="randomB">Given 64-bit rand_b</param>
67+
/// <returns>A new Uuid object</returns>
68+
/// <exception cref="ArgumentNullException"></exception>
69+
/// <exception cref="ArgumentException"></exception>
70+
public static Uuid NewUUIDv7(DateTime dateTime, Byte[] randomA, Byte[] randomB)
71+
{
72+
if (randomA == null)
73+
throw new ArgumentNullException(nameof(randomA));
74+
75+
if (randomA.Length < 2)
76+
throw new ArgumentException(String.Format("rand_a contains less than 16-bit: {0} bytes", randomA.Length), nameof(randomA));
77+
78+
if (randomB == null)
79+
throw new ArgumentNullException(nameof(randomB));
80+
81+
if (randomB.Length < 8)
82+
throw new ArgumentException(String.Format("rand_b contains less than 64-bit: {0} bytes", randomB.Length), nameof(randomB));
83+
84+
TimeSpan timesince = dateTime.ToUniversalTime() - s_epoch.ToUniversalTime();
85+
Int64 timeinterval = ((Int64)timesince.TotalMilliseconds) << 16;
86+
87+
Byte[] time = BitConverter.GetBytes(System.Net.IPAddress.HostToNetworkOrder(timeinterval));
88+
89+
Byte[] hex = new Byte[16];
90+
91+
hex[0] = time[0];
92+
hex[1] = time[1];
93+
hex[2] = time[2];
94+
hex[3] = time[3];
95+
96+
hex[4] = time[4];
97+
hex[5] = time[5];
98+
99+
hex[6] = (Byte)((randomA[0] & 0x0F) + 0x70);
100+
hex[7] = randomA[1];
101+
102+
hex[8] = (Byte)((randomB[0] & 0x3F) | 0x80);
103+
hex[9] = randomB[1];
104+
hex[10] = randomB[2];
105+
hex[11] = randomB[3];
106+
hex[12] = randomB[4];
107+
hex[13] = randomB[5];
108+
hex[14] = randomB[6];
109+
hex[15] = randomB[7];
110+
111+
Uuid Id = new Uuid(hex);
112+
113+
return Id;
114+
}
115+
}
116+
}

UUIDUtil/Uuid.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public class Uuid : IComparable<Uuid>, IEquatable<Uuid>
1818
/// </summary>
1919
public static readonly Uuid Empty = new Uuid();
2020

21+
/// <summary>
22+
/// A read-only instance of the Uuid object whose value is all ones.
23+
/// </summary>
24+
public static readonly Uuid Max = new Uuid(uint.MaxValue, ushort.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff});
25+
2126
public Uuid()
2227
{
2328
_time_low = 0;

0 commit comments

Comments
 (0)