Skip to content

Commit ef1e82a

Browse files
author
Ashley Huxley
committed
Improves the precision of the GUID Comb generator.
By dividing by 3.333333 but casting to a long, the apparent increase in precision was lost due to truncation. The improved code creates a 4 byte number representing the time of day at the maximum possible precision.
1 parent f938239 commit ef1e82a

File tree

1 file changed

+11
-10
lines changed

1 file changed

+11
-10
lines changed

src/NHibernate/Id/GuidCombGenerator.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public partial class GuidCombGenerator : IIdentifierGenerator
2626
{
2727
private static readonly long BaseDateTicks = new DateTime(1900, 1, 1).Ticks;
2828

29+
private static readonly double TickResolution = TimeSpan.FromDays(1).Ticks / (double) uint.MaxValue;
30+
2931
#region IIdentifierGenerator Members
3032

3133
/// <summary>
@@ -48,20 +50,19 @@ private Guid GenerateComb()
4850

4951
DateTime now = DateTime.UtcNow;
5052

51-
// Get the days and milliseconds which will be used to build the byte string
52-
TimeSpan days = new TimeSpan(now.Ticks - BaseDateTicks);
53-
TimeSpan msecs = now.TimeOfDay;
53+
// We use 2 bytes for the day (65,535 possible values) so we're good until 6/6/2079.
54+
var days = new TimeSpan(now.Ticks - BaseDateTicks);
55+
var daysArray = BitConverter.GetBytes(days.Days);
5456

55-
// Convert to a byte array
56-
// Note that SQL Server is accurate to 1/300th of a millisecond so we divide by 3.333333
57-
byte[] daysArray = BitConverter.GetBytes(days.Days);
58-
byte[] msecsArray = BitConverter.GetBytes((long) (msecs.TotalMilliseconds / 3.333333));
57+
// Get the ticks for the time of day
58+
// Divide the ticks by TickResolution to produce a number relating to the time of day that will exactly fit into 4 bytes
59+
var msecsArray = BitConverter.GetBytes((long) (now.TimeOfDay.Ticks / TickResolution));
5960

60-
// Reverse the bytes to match SQL Servers ordering
61+
// Reverse the bytes to match SQL Servers ordering
6162
Array.Reverse(daysArray);
6263
Array.Reverse(msecsArray);
6364

64-
// Copy the bytes into the guid
65+
// Copy the bytes into the guid
6566
Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2);
6667
Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4);
6768

@@ -70,4 +71,4 @@ private Guid GenerateComb()
7071

7172
#endregion
7273
}
73-
}
74+
}

0 commit comments

Comments
 (0)