How to generate guid from DateTime?

Viewed 8146

I want to generate a Guid v.1 from a DateTime. I try to use the class described here:

https://gist.github.com/nberardi/3759706

But after getting a DateTime from a Guid, I tried to get the same Guid as the original using that DateTime, and it gave me a different Guid. Here's the code I used:

  string uuidString = "9e5713bb-bb4c-11e8-9d6c-12345678df23";
  Guid gui = new Guid(uuidString);
  DateTime dateTimeFromGuid = GuidGenerator.GetDateTime(gui);
  Console.WriteLine(dateTimeFromGuid.ToString("dd/MM/yyyy hh:mm:ss"));
  Guid guidFromDateTime = GuidGenerator.GenerateTimeBasedGuid(dateTimeFromGuid);
  Console.WriteLine(guidFromDateTime); //7909dbbb-bb33-11e8-9f6a-95d8e90ccf10

How can I get the original GUID back from a DateTime?

2 Answers

If you want something simple that can be converted back and forth regardless of what machine you are on. Then, you can convert the date to a byte array and use that to create the Guid. This is non-standard, but will generate the same exact Guid for each DateTime.

var today = new DateTime(2018, 9, 18, 10, 59, 00);

var bytes = BitConverter.GetBytes(today.Ticks);

Array.Resize(ref bytes, 16);

var guid = new Guid(bytes);

Console.WriteLine(guid); //bd02b200-1d55-08d6-0000-000000000000

And back to date.

var dateBytes = guid.ToByteArray();

Array.Resize(ref dateBytes, 8);

var date = new DateTime(BitConverter.ToInt64(dateBytes));

Console.WriteLine(date); //9/18/2018 10:59:00

If you want to use extensions then.

class Program
{
    static void Main(string[] args)
    {
        var date = new DateTime(2018, 09, 18, 12, 00, 00);

        var guid = date.ToGuid();

        Console.WriteLine(guid); // 428a6000-1d5e-08d6-0000-000000000000

        var back2date = guid.ToDateTime();

        Console.WriteLine(back2date); // 9/18/2018 12:00:00
    }
}

public static class DateTimeExtensions
{
    public static Guid ToGuid(this DateTime dt)
    {
        var bytes = BitConverter.GetBytes(dt.Ticks);

        Array.Resize(ref bytes, 16);

        return new Guid(bytes);
    }
}

public static class GuidExtensions
{
    public static DateTime ToDateTime(this Guid guid)
    {
        var bytes = guid.ToByteArray();

        Array.Resize(ref bytes, 8);

        return new DateTime(BitConverter.ToInt64(bytes));
    }
}

If the goal is to get reproducible GUIDs, then you need to disable the random components. These are set when the program starts. After that they no longer change, so the generated GUIDs are stable from then on, but each run of the program will use different random values, so each run will give a different semi-random GUID for a known datetime value.

To disable it, simply do:

//var random = new Random();
//random.NextBytes(DefaultClockSequence);
//random.NextBytes(DefaultNode);

Furthermore when running it locally, you have to force your DateTime value to use UTC, which I did as follows:

DateTime dateTimeFromGuid = GuidGenerator.GetDateTime(gui);
dateTimeFromGuid = new DateTime(dateTimeFromGuid.Ticks, DateTimeKind.Utc);

It would be much better to move this "UTC fix" into the library code.

Fiddle (I also changed the input GUID to a "non-randomized" value):
https://dotnetfiddle.net/niIHlz

Related