Какая наилучшая практика для получения случайного DateTime между двумя датами?

Я пытаюсь рандомизировать значение для простого поля данных DateTime.

Я хочу получить случайную дату/время между двумя датами/временем (например, min date/time и max date/time).

Итак, представьте себе, что я после случайной даты/времени между

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

Кроме того, этот код будет использоваться в цикле for, с 100 элементами... что означает, что все 100 элементов будут иметь случайную дату/время между минимальным/максимальным периодом даты/времени.

Любые идеи?

Ответ 1

Вы можете попробовать:

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

Это даст вам разное время до минуты. Если вам нужно 100 (или любая вещь более 1) DateTime, то только создайте объект Random один раз. Страница конструктор MSDN времени TimeSpan:

TimeSpan (Int64). Инициализирует новый TimeSpan для указанного количества тиков.
TimeSpan (Int32, Int32, Int32). Инициализирует новый TimeSpan до заданного количества часов, минут и секунд.
TimeSpan (Int32, Int32, Int32, Int32) Инициализирует новый TimeSpan до указанного количества дней, часов, минут и секунд.
TimeSpan (Int32, Int32, Int32, Int32, Int32). Инициализирует новый TimeSpan до заданного количества дней, часов, минут, секунд и миллисекунд.

Ответ 2

Здесь мой алгоритм и код:

  • найдите разницу между двумя датами
  • для каждой итерации создайте случайное число между двумя датами
  • создать новую дату между ними. Просто добавьте это случайное число как минут в начало 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 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));
    }
    

Ответ 3

Действительно быстро:

  • конвертировать ваши даты в TotalHours
  • Вычтите одно число из другого и используйте Abs, чтобы сделать положительный
  • Создайте случайное число в диапазоне 1 и результат 2. выше
  • Добавьте полученное случайное число часов назад к более ранним из двух дат.

Ответ 4

Сначала выясните, какая точность вы хотите в случайном DateTime (часы, минуты, секунды, мс и т.д.).

Затем определите разницу между двумя датами в этом блоке.

Создайте случайное целое число от 0 до этой разницы.

Добавьте случайное целое число в единицы к исходной дате.

Учитывая используемый вами вариант использования, вы указали выше, вычислите разницу вне в цикле for.

Внутри цикла for получить случайный int и построить случайную дату.

Ответ 5

Это то, что я использую:

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;
    }
}

Я использовал подход в принятом ответе, но немного изменил его, поскольку у меня были проблемы с ним.

Ответ 6

Однострочный фильтр на основе решения ChrisF

var newDate = startDate.AddHours(new Random(Convert.ToInt32(DateTime.Now.Ticks / int.MaxValue)).Next(0, (int)(endDate - startDate).TotalHours));

Ответ 7

Здесь используется метод с использованием случайного числа тиков:

Random r= new Random(); 
    //for better randomness don't recreate a new Random() too frequently.
long rand62bit = (((long)r.Next())<<31) + r.Next(); 
    // 62bits suffices for random datetimes, 31 does not!
DateTime newDate = startDate + new TimeSpan(rand62bit % (endDate - startDate).Ticks); 

Этот метод является исключительной последней датой и включает первый. Вы можете легко включить последнюю дату, добавив по одному тику к базовому количеству (endDate - startDate).Ticks.