Data aleatória em c #

141

Estou procurando por um código C # moderno e sucinto para gerar uma data aleatória entre 1º de janeiro de 1995 e a data atual.

Estou pensando em alguma solução que utiliza Enumerable.Range de alguma forma pode tornar isso mais sucinto.

Judah Gabriel Himango
fonte
Resposta em Aleatório DateTime entre gama - não unificado de saída tem ajudante método com De parâmetros de data / TO
Michael Freidgeim

Respostas:

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

Para um melhor desempenho, se isso for chamado repetidamente, crie as variáveis starte gen(e talvez até range) fora da função.

Joel Coehoorn
fonte
1
Aleatório é apenas pseudo-aleatório. Se você precisar realmente aleatório, tente usar RNGCryptoServiceProvider no espaço para nome System.Security.Cryptography.
Tbf # 02:
Obrigado tvanfosson. Pseudo-aleatório é suficiente para esse problema.
Judah Gabriel Himango
5
Na verdade, o Random não é nem particularmente pseudo-aleatório, a menos que você mantenha a instância por um tempo e continue obtendo valores dela.
David Mitchell
2
É por isso que isso é apenas uma amostra, e não um código de produção.
Joel Coehoorn
1
Sim, isso funciona para mim; meu código do mundo real terá a instância Random fora do próprio método.
Judah Gabriel Himango 01/06/09
25

Isso é uma leve resposta ao comentário de Joel sobre como criar uma versão ligeiramente mais otimizada. Em vez de retornar uma data aleatória diretamente, por que não retornar uma função geradora que pode ser chamada repetidamente para criar uma data aleatória?

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));
}
JaredPar
fonte
Você pode explicar como isso é benéfico? Não foi possível iniciar, geração e intervalo como membros da classe?
Mark A. Nicolosi
Eles poderiam e, neste caso, são. Sob o capô, isso gerará um fechamento lexical que é um clrass que contém início, gen e intervalo como membros. Isso é apenas mais conciso.
JaredPar 12/10/08
Bom função, eu estou apenas esperando que ninguém vai usá-lo como:for (int i = 0; i < 100; i++) { array[i].DateProp = RandomDayFunc()(); }
Aidiakapi
2
Como essa função é usada, alguém pode explicar? Quero dizer, como posso chamá-lo?
Burak Karakuş 01/01
2
@ BurakKarakuş: Você obtém uma fábrica primeiro: var getRandomDate = RandomDayFunc();depois a chama para obter datas aleatórias: var randomDate = getRandomDate();lembre-se de que você precisa reutilizar getRandomDate para que isso seja mais útil do que a resposta de Joel.
Şafak Gür
8

Peguei a resposta de @Joel Coehoorn e fiz as alterações que ele recomendou - coloque a variável fora do método e coloque tudo na classe. Além disso, agora o tempo também é aleatório. Aqui está o resultado.

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

E exemplo como usar para escrever 100 DateTimes aleatórios no console:

RandomDateTime date = new RandomDateTime();
for (int i = 0; i < 100; i++)
{
    Console.WriteLine(date.Next());
}
prespic
fonte
Por que você cria Random () duas vezes? Uma vez na classe, declaração de variável gen e outra hora no c-tor?
pixel
Sim, uma vez é o suficiente. Eu consertei isso.
prespic 15/08/17
1
É cerca de quatro vezes mais rápido gerar apenas um número aleatório de segundos e adicioná-lo à sua data de início: range = (int)(DateTime.Today - start).TotalSeconds;e return start.AddSeconds(gen.Next(range));.
Jurgy
5

Bem, se você apresentar otimização alternativa, também podemos optar por um iterador:

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

você poderia usá-lo assim:

int i=0;
foreach(DateTime dt in RandomDay())
{
    Console.WriteLine(dt);
    if (++i == 10)
        break;
}
James Curran
fonte
1
Uma coisa a considerar entre um iterador e uma função de gerador é que a solução do iterador produzirá um valor IDisposable. Isso força o chamador a descartar ou pagar o preço de ter um finalizador ativo no GC. As necessidades de geradores sem descartar
JaredPar
2
@ JaredPar, isso não está certo. Só porque um tipo implementa IDisposable não significa que é finalizável.
Drew Noakes
3

Comece com um objeto de data fixa (1 de janeiro de 1995) e adicione um número aleatório de dias com AddDays (obviamente, preste atenção para não ultrapassar a data atual).

Gabriele D'Antona
fonte
Obrigado Friol. Eu ia perguntar como limitar o número passado aleatoriamente. Joel postou um exemplo com amostra de código, então vou marcar sua resposta como a resposta.
Judah Gabriel Himango
0

Estou um pouco atrasado para o jogo, mas aqui está uma solução que funciona bem:

    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;
            }
        }
    }
Hamit Gündogdu
fonte
0

Método pequeno que retorna uma data aleatória como string, com base em alguns parâmetros de entrada simples. Construído com base nas variações das respostas acima:

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