What's the best practice for getting a random DateTime between two date-times?

24,367

Solution 1

You could try using:

var randomTest = new Random();

TimeSpan timeSpan = endDate - startDate;
TimeSpan newSpan = new TimeSpan(0, randomTest.Next(0, (int)timeSpan.TotalMinutes), 0);
DateTime newDate = startDate + newSpan;

This will give you different times down to the minute. If you want 100 (or any thing more than 1) DateTimes then only create the Random object once. The MSDN page on Random explains in detail why creating several Random objects in quick succession is a bad idea.

Using a different TimeSpan constructor will give you different granularity. From the TimeSpan constructor MSDN:

TimeSpan(Int64) Initializes a new TimeSpan to the specified number of ticks.
TimeSpan(Int32, Int32, Int32) Initializes a new TimeSpan to a specified number of hours, minutes, and seconds.
TimeSpan(Int32, Int32, Int32, Int32) Initializes a new TimeSpan to a specified number of days, hours, minutes, and seconds.
TimeSpan(Int32, Int32, Int32, Int32, Int32) Initializes a new TimeSpan to a specified number of days, hours, minutes, seconds, and milliseconds.

Solution 2

Here's my algorithm and code:

  • find the difference between the two dates
  • for each iteration, create a random number between the two dates
  • create a new date between them. Simply add that random number as minutes to the start datetime.  

    Random randNum = new Random();
    
    DateTime minDt = new DateTime(2000,1,1,10,0,0);
    DateTime maxDt = new DateTime(2000,1,1,17,0,0);
    List<DateTime> myDates = new List<DateTime>();
    //Random.Next in .NET is non-inclusive to the upper bound (@NickLarsen)
    int minutesDiff = Convert.ToInt32(maxDt.Subtract(minDt).TotalMinutes+1);
    
    for (int i = 0; i < 100; i++)
    {
       // some random number that's no larger than minutesDiff, no smaller than 1
       int r=   randNum.Next(1, minutesDiff); 
       myDates.Add(minDt.AddMinutes(r));
    }
    
    foreach (DateTime d in myDates)
    {
      Console.WriteLine(string.Format("{0:dd-MMM-yyyy hh:mm}",d));
    }
    

Solution 3

This is what I'm using:

class RandomDates
{
    private Random random = new Random();

    public DateTime Date(DateTime? start = null, DateTime? end = null)
    {
        if (start.HasValue && end.HasValue && start.Value >= end.Value)
            throw new Exception("start date must be less than end date!");

        DateTime min = start ?? DateTime.MinValue;
        DateTime max = end ?? DateTime.MaxValue;

        // for timespan approach see: http://stackoverflow.com/q/1483670/1698987
        TimeSpan timeSpan = max - min;

        // for random long see: http://stackoverflow.com/a/677384/1698987
        byte[] bytes = new byte[8];
        random.NextBytes(bytes);

        long int64 = Math.Abs(BitConverter.ToInt64(bytes, 0)) % timeSpan.Ticks;

        TimeSpan newSpan = new TimeSpan(int64);

        return min + newSpan;
    }
}

I used the approach in the accepted answer but modified it slightly as I had issues with it.

Solution 4

Really quickly:

  1. convert your dates to TotalHours
  2. Subtract one number from the other and use Abs to make positive
  3. Create a random number within the range of 1 and the result of 2. above
  4. Add the resulting random number of hours back to the earlier of your two dates

Solution 5

First, figure out what the precision is that you want on random DateTime (hours,minutes,seconds,ms,etc).

Then figure out the difference between the two dates in that unit.

Create a random integer between 0 and that difference.

Add the random integer in units to the original date.

Given the use case you stated above, calculate the difference outside in the for loop.

Inside the for loop, get the random int and construct the random date.

Share:
24,367

Related videos on Youtube

Pure.Krome
Author by

Pure.Krome

Just another djork trying to ply his art in this mad mad world. Tech stack I prefer to use: Laguage: C# / .NET Core / ASP.NET Core Editors: Visual Studio / VS Code Persistence: RavenDB, SqlServer (MSSql or Postgres) Source control: Github Containers: Docker &amp; trying to learn K&amp;'s Cloud Platform: Azure Caching/CDN: Cloudflare Finally: A Tauntaun sleeping bag is what i've always wanted spaces &gt; tabs

Updated on May 05, 2022

Comments

  • Pure.Krome
    Pure.Krome about 2 years

    I'm trying to randomize the value for a simple DateTime data field.

    I wish to get a random date/time between two date/times (e.g. min date/time and max date/time).

    So lets imagine I'm after a random date/time between

    1/1/2000 10:00:00am and 1/1/2000 5:00:00pm.

    Also, this code will be used in a for loop, with 100 items ... meaning all 100 items will have random date/times between the min/max date/time period.

    Any ideas?

  • slashmais
    slashmais over 14 years
    I was just giving the same answer when yours popped up ;)
  • Nick Larsen
    Nick Larsen over 14 years
    Was trying to attach this comment to the last post...remember that Random.Next in .NET is non-inclusive to the upper bound.
  • Cymen
    Cymen over 12 years
    The method should probably be named DateTime instead of Date -- I had plain dates on the mind but it does of course return a DateTime.
  • Reitffunk
    Reitffunk over 5 years
    Just want to say, that such one-liners are doing no good to code readability. Please avoid these for production systems.