I'm looking for some succinct, modern C# code to generate a random date between Jan 1 1995 and the current date.
I'm thinking some solution that utilizes Enumerable.Range somehow may make this more succinct.
I'm looking for some succinct, modern C# code to generate a random date between Jan 1 1995 and the current date.
I'm thinking some solution that utilizes Enumerable.Range somehow may make this more succinct.
 
    
    private Random gen = new Random();
DateTime RandomDay()
{
    DateTime start = new DateTime(1995, 1, 1);
    int range = (DateTime.Today - start).Days;           
    return start.AddDays(gen.Next(range));
}
For better performance if this will be called repeatedly, create the start and gen (and maybe even range) variables outside of the function.
 
    
     
    
    This is in slight response to Joel's comment about making a slighly more optimized version. Instead of returning a random date directly, why not return a generator function which can be called repeatedly to create a random date.
Func<DateTime> RandomDayFunc()
{
    DateTime start = new DateTime(1995, 1, 1); 
    Random gen = new Random(); 
    int range = ((TimeSpan)(DateTime.Today - start)).Days; 
    return () => start.AddDays(gen.Next(range));
}
 
    
     
    
    I have taken @Joel Coehoorn answer and made the changes he adviced - put the variable out of the method and put all in class. Plus now the time is random too. Here is the result.
class RandomDateTime
{
    DateTime start;
    Random gen;
    int range;
    public RandomDateTime()
    {
        start = new DateTime(1995, 1, 1);
        gen = new Random();
        range = (DateTime.Today - start).Days;
    }
    public DateTime Next()
    {
        return start.AddDays(gen.Next(range)).AddHours(gen.Next(0,24)).AddMinutes(gen.Next(0,60)).AddSeconds(gen.Next(0,60));
    }
}
And example how to use to write 100 random DateTimes to console:
RandomDateTime date = new RandomDateTime();
for (int i = 0; i < 100; i++)
{
    Console.WriteLine(date.Next());
}
 
    
    Well, if you gonna present alternate optimization, we can also go for an iterator:
 static IEnumerable<DateTime> RandomDay()
 {
    DateTime start = new DateTime(1995, 1, 1);
    Random gen = new Random();
    int range = ((TimeSpan)(DateTime.Today - start)).Days;
    while (true)
        yield return  start.AddDays(gen.Next(range));        
}
you could use it like this:
int i=0;
foreach(DateTime dt in RandomDay())
{
    Console.WriteLine(dt);
    if (++i == 10)
        break;
}
 
    
    Start with a fixed date object (Jan 1, 1995), and add a random number of days with AddDays (obviusly, pay attention not surpassing the current date).
 
    
    Random rnd = new Random();
DateTime datetoday = DateTime.Now;
int rndYear = rnd.Next(1995, datetoday.Year);
int rndMonth = rnd.Next(1, 12);
int rndDay = rnd.Next(1, 31);
DateTime generateDate = new DateTime(rndYear, rndMonth, rndDay);
Console.WriteLine(generateDate);
//this maybe is not the best method but is fast and easy to understand
 
    
    One more solution to the problem, this time a class to which you provide a range you want the dates in. Its down to random minutes in the results.
/// <summary>
/// A random date/time class that provides random dates within a given range
/// </summary>
public class RandomDateTime
{
    private readonly Random rng = new Random();
    private readonly int totalMinutes;
    private readonly DateTime startDateTime;
    /// <summary>
    /// Initializes a new instance of the <see cref="RandomDateTime"/> class.
    /// </summary>
    /// <param name="startDate">The start date.</param>
    /// <param name="endDate">The end date.</param>
    public RandomDateTime(DateTime startDate, DateTime endDate)
    {
        this.startDateTime = startDate;
        TimeSpan timeSpan = endDate - startDate;
        this.totalMinutes = (int)timeSpan.TotalMinutes;
    }
    /// <summary>
    /// Gets the next random datetime object within the range of startDate and endDate provided in the ctor
    /// </summary>
    /// <returns>A DateTime.</returns>
    public DateTime NextDateTime
    {
        get
        {
            TimeSpan newSpan = new TimeSpan(0, rng.Next(0, this.totalMinutes), 0);
            return this.startDateTime + newSpan;
        }
    }
}
Use it like this to spit out 5 random dates between january 1st 2020 and december 31 2022:
RandomDateTime rdt = new RandomDateTime(DateTime.Parse("01/01/2020"), DateTime.Parse("31/12/2022"));
for (int i = 0; i < 5; i++)
    Debug.WriteLine(rdt.NextDateTime);
 
    
    I am a bit late in to the game, but here is one solution which works fine:
    void Main()
    {
        var dateResult = GetRandomDates(new DateTime(1995, 1, 1), DateTime.UtcNow, 100);
        foreach (var r in dateResult)
            Console.WriteLine(r);
    }
    public static IList<DateTime> GetRandomDates(DateTime startDate, DateTime maxDate, int range)
    {
        var randomResult = GetRandomNumbers(range).ToArray();
        var calculationValue = maxDate.Subtract(startDate).TotalMinutes / int.MaxValue;
        var dateResults = randomResult.Select(s => startDate.AddMinutes(s * calculationValue)).ToList();
        return dateResults;
    }
    public static IEnumerable<int> GetRandomNumbers(int size)
    {
        var data = new byte[4];
        using (var rng = new System.Security.Cryptography.RNGCryptoServiceProvider(data))
        {
            for (int i = 0; i < size; i++)
            {
                rng.GetBytes(data);
                var value = BitConverter.ToInt32(data, 0);
                yield return value < 0 ? value * -1 : value;
            }
        }
    }
 
    
    Small method that returns a random date as string, based on some simple input parameters. Built based on variations from the above answers:
public string RandomDate(int startYear = 1960, string outputDateFormat = "yyyy-MM-dd")
{
   DateTime start = new DateTime(startYear, 1, 1);
   Random gen = new Random(Guid.NewGuid().GetHashCode());
   int range = (DateTime.Today - start).Days;
   return start.AddDays(gen.Next(range)).ToString(outputDateFormat);
}
 
    
    Useful extension based of @Jeremy Thompson's solution
public static class RandomExtensions
{
    public static DateTime Next(this Random random, DateTime start, DateTime? end = null)
    {
        end ??= new DateTime();
        int range = (end.Value - start).Days;
        return start.AddDays(random.Next(range));
    }
}
