public
Last active

TimeUUID Generator for .NET

  • Download Gist
GuidGenerator.cs
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
using System;
 
namespace FluentCassandra
{
/// <summary>
/// Used for generating UUID based on RFC 4122.
/// </summary>
/// <seealso href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122 - A Universally Unique IDentifier (UUID) URN Namespace</seealso>
public static partial class GuidGenerator
{
// number of bytes in guid
public const int ByteArraySize = 16;
 
// multiplex variant info
public const int VariantByte = 8;
public const int VariantByteMask = 0x3f;
public const int VariantByteShift = 0x80;
 
// multiplex version info
public const int VersionByte = 7;
public const int VersionByteMask = 0x0f;
public const int VersionByteShift = 4;
 
// indexes within the uuid array for certain boundaries
private const byte TimestampByte = 0;
private const byte GuidClockSequenceByte = 8;
private const byte NodeByte = 10;
 
// offset to move from 1/1/0001, which is 0-time for .NET, to gregorian 0-time of 10/15/1582
private static readonly DateTimeOffset GregorianCalendarStart = new DateTimeOffset(1582, 10, 15, 0, 0, 0, TimeSpan.Zero);
 
// random clock sequence and node
public static byte[] DefaultClockSequence { get; set; }
public static byte[] DefaultNode { get; set; }
 
static GuidGenerator()
{
DefaultClockSequence = new byte[2];
DefaultNode = new byte[6];
 
var random = new Random();
random.NextBytes(DefaultClockSequence);
random.NextBytes(DefaultNode);
}
 
public static GuidVersion GetVersion(this Guid guid)
{
byte[] bytes = guid.ToByteArray();
return (GuidVersion)((bytes[VersionByte] & 0xFF) >> VersionByteShift);
}
 
public static DateTimeOffset GetDateTimeOffset(Guid guid)
{
byte[] bytes = guid.ToByteArray();
 
// reverse the version
bytes[VersionByte] &= (byte)VersionByteMask;
bytes[VersionByte] |= (byte)((byte)GuidVersion.TimeBased >> VersionByteShift);
 
byte[] timestampBytes = new byte[8];
Array.Copy(bytes, TimestampByte, timestampBytes, 0, 8);
 
long timestamp = BitConverter.ToInt64(timestampBytes, 0);
long ticks = timestamp + GregorianCalendarStart.Ticks;
 
return new DateTimeOffset(ticks, TimeSpan.Zero);
}
 
public static DateTime GetDateTime(Guid guid)
{
return GetDateTimeOffset(guid).DateTime;
}
 
public static DateTime GetLocalDateTime(Guid guid)
{
return GetDateTimeOffset(guid).LocalDateTime;
}
 
public static DateTime GetUtcDateTime(Guid guid)
{
return GetDateTimeOffset(guid).UtcDateTime;
}
 
public static Guid GenerateTimeBasedGuid()
{
return GenerateTimeBasedGuid(DateTimeOffset.UtcNow, DefaultClockSequence, DefaultNode);
}
 
public static Guid GenerateTimeBasedGuid(DateTime dateTime)
{
return GenerateTimeBasedGuid(dateTime, DefaultClockSequence, DefaultNode);
}
 
public static Guid GenerateTimeBasedGuid(DateTimeOffset dateTime)
{
return GenerateTimeBasedGuid(dateTime, DefaultClockSequence, DefaultNode);
}
 
public static Guid GenerateTimeBasedGuid(DateTime dateTime, byte[] clockSequence, byte[] node)
{
return GenerateTimeBasedGuid(new DateTimeOffset(dateTime), clockSequence, node);
}
 
public static Guid GenerateTimeBasedGuid(DateTimeOffset dateTime, byte[] clockSequence, byte[] node)
{
if (clockSequence == null)
throw new ArgumentNullException("clockSequence");
 
if (node == null)
throw new ArgumentNullException("node");
 
if (clockSequence.Length != 2)
throw new ArgumentOutOfRangeException("clockSequence", "The clockSequence must be 2 bytes.");
 
if (node.Length != 6)
throw new ArgumentOutOfRangeException("node", "The node must be 6 bytes.");
 
long ticks = (dateTime - GregorianCalendarStart).Ticks;
byte[] guid = new byte[ByteArraySize];
byte[] timestamp = BitConverter.GetBytes(ticks);
 
// copy node
Array.Copy(node, 0, guid, NodeByte, Math.Min(6, node.Length));
 
// copy clock sequence
Array.Copy(clockSequence, 0, guid, GuidClockSequenceByte, Math.Min(2, clockSequence.Length));
 
// copy timestamp
Array.Copy(timestamp, 0, guid, TimestampByte, Math.Min(8, timestamp.Length));
 
// set the variant
guid[VariantByte] &= (byte)VariantByteMask;
guid[VariantByte] |= (byte)VariantByteShift;
 
// set the version
guid[VersionByte] &= (byte)VersionByteMask;
guid[VersionByte] |= (byte)((byte)GuidVersion.TimeBased << VersionByteShift);
 
return new Guid(guid);
}
}
}
GuidVersion.cs
C#
1 2 3 4 5 6 7 8 9 10 11 12 13
using System;
 
namespace FluentCassandra
{
// guid version types
public enum GuidVersion
{
TimeBased = 0x01,
Reserved = 0x02,
NameBased = 0x03,
Random = 0x04
}
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.