Случайная дата в C#

Я ищу краткий современный код C# для генерации случайной даты между 1 января 1995 года и текущей датой.

Я думаю, что какое-то решение, использующее Enumerable.Range, каким-то образом может сделать это более лаконичным.

Ответ в Случайная дата и время между диапазоном - не унифицированный вывод имеет вспомогательный метод с параметрами From / To date

Michael Freidgeim 10.06.2016 06:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
144
1
102 029
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Начните с объекта с фиксированной датой (1 января 1995 г.) и добавьте случайное количество дней с помощью AddDays (очевидно, обратите внимание, не превышайте текущую дату).

Спасибо, Фриоль. Я собирался спросить, как ограничить число, переданное в случайное. Джоэл опубликовал пример с образцом кода, поэтому я отмечу его ответ как ответ.

Judah Gabriel Himango 12.10.2008 04:18
Ответ принят как подходящий

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

Для повышения производительности, если это будет вызываться повторно, создайте переменные вне функции start и gen (и, возможно, даже range).

Случайное - только псевдослучайное. Если вам нужен действительно случайный, попробуйте использовать RNGCryptoServiceProvider из пространства имен System.Security.Cryptography.

tvanfosson 12.10.2008 04:37

Спасибо tvanfosson. Для этой задачи достаточно псевдослучайной последовательности.

Judah Gabriel Himango 12.10.2008 05:26

На самом деле Random даже не является особенно псевдослучайным, если вы не держите экземпляр какое-то время и продолжаете получать из него значения.

David Mitchell 15.10.2008 18:23

+1 за комментарий Дэвида. Если вы вызовете вышеуказанный метод дважды в быстрой последовательности, он с большей вероятностью вернет одно и то же значение. Конструктор Random выше использует текущее время в качестве начального числа, которым является DateTime.Now. Это значение увеличивается каждые 15 миллисекунд. Поле было бы лучше.

Drew Noakes 23.10.2008 12:13

Вот почему это всего лишь образец, а не производственный код.

Joel Coehoorn 23.10.2008 17:10

Да, это работает для меня; мой реальный код будет иметь экземпляр Random вне самого метода.

Judah Gabriel Himango 02.06.2009 02:03

@Ronnie, ваше редактирование вызвало ошибку компиляции (невозможно неявно преобразовать тип double в int), пожалуйста, не меняйте код других людей, и если вы это сделаете, будьте особенно осторожны и проверьте, прежде чем делать это. Спасибо.

Shadow Wizard is Vaccinating 13.05.2013 12:38

@ShadowWizard Мое плохое. Я думал, что дни не являются самой важной частью TimeSpan, и поэтому разница между днями и полными днями будет очень заметной, как и в случае с минутами.

Ronnie Overby 13.05.2013 17:13

Включает ли результат сегодня?

Salman A 10.11.2018 17:46

@SalmanA Вы можете быстро это узнать, если в качестве эпохи использовать вчерашний день, а не 1995 год. Похоже на ответ - нет".

Joel Coehoorn 11.11.2018 04:11

@Joel Просто добавьте 1 к диапазону. OP не ясно, нужно ли включать сегодня, но вы всегда можете дать четкий ответ о крайнем случае.

Salman A 11.11.2018 12:09

Это небольшой ответ на комментарий Джоэла о создании немного более оптимизированной версии. Вместо того, чтобы напрямую возвращать случайную дату, почему бы не вернуть функцию генератора, которую можно вызывать повторно для создания случайной даты.

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

Вы можете объяснить, чем это выгодно? Не могли бы вместо этого быть членами класса start, gen и range?

Mark A. Nicolosi 12.10.2008 07:51

Могли, и в данном случае они есть. Под капотом это сгенерирует лексическое замыкание, которое является классом, содержащим start, gen и range в качестве членов. Это просто более кратко.

JaredPar 12.10.2008 20:32

Хорошая функция, я просто надеюсь, что никто не будет использовать ее как: for (int i = 0; i < 100; i++) { array[i].DateProp = RandomDayFunc()(); }

Aidiakapi 29.03.2014 15:54

Как эта функция используется, кто-нибудь может объяснить? Я имею в виду, как я могу это назвать?

Burak Karakuş 01.01.2016 16:19

@ BurakKarakuş: Сначала вы получаете фабрику: var getRandomDate = RandomDayFunc();, затем вызываете ее, чтобы получить случайные даты: var randomDate = getRandomDate(); Имейте в виду, что вам нужно повторно использовать getRandomDate, чтобы это было более полезным, чем ответ Джоэла.

Şafak Gür 08.02.2018 11:43

Что ж, если вы собираетесь представить альтернативную оптимизацию, мы также можем использовать итератор:

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

вы можете использовать это так:

int i=0;
foreach(DateTime dt in RandomDay())
{
    Console.WriteLine(dt);
    if (++i == 10)
        break;
}

При выборе между итератором и функцией-генератором следует учитывать, что решение итератора будет выдавать значение IDisposable. Это вынуждает вызывающую программу избавиться от нее или заплатить цену за то, чтобы финализатор находился в GC. Генератор не требует утилизации

JaredPar 13.10.2008 01:05

@JaredPar, это не совсем так. Тот факт, что тип реализует IDisposable, не означает, что его можно завершить.

Drew Noakes 23.10.2008 12:10

Я взял ответ @Joel Coehoorn и внес изменения, которые он посоветовал - убрать переменную из метода и поместить все в класс. Плюс теперь время тоже случайное. Вот результат.

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

И пример того, как использовать для записи 100 случайных значений DateTime на консоль:

RandomDateTime date = new RandomDateTime();
for (int i = 0; i < 100; i++)
{
    Console.WriteLine(date.Next());
}

Почему вы создаете Random () дважды? Один раз в объявлении переменной класса gen, а другой раз в c-tor?

pixel 15.08.2017 02:15

Да, одного раза достаточно. Я починил это.

prespic 15.08.2017 09:30

Примерно в четыре раза быстрее сгенерировать всего одно случайное число секунд и добавить его к дате начала: range = (int)(DateTime.Today - start).TotalSeconds; и return start.AddSeconds(gen.Next(range));.

Jurgy 10.01.2019 16:47

Я немного опоздал в игру, но вот одно решение, которое отлично работает:

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

Небольшой метод, который возвращает случайную дату в виде строки на основе некоторых простых входных параметров. Построен на основе вариантов из приведенных выше ответов:

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

Полезное расширение на основе решения @Jeremy Thompson

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

new DateTime() - это 01/01/0001 00:00:00. Вы уверены, что?

Theodor Zoulias 19.01.2021 05:01

Другие вопросы по теме