Data casuale in C #


Risposte:


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

Per prestazioni migliori se questo verrà chiamato ripetutamente, creare le variabili starte gen(e forse anche range) al di fuori della funzione.


1
Il casuale è solo pseudo-casuale. Se hai davvero bisogno di casualità, prova a utilizzare RNGCryptoServiceProvider dallo spazio dei nomi System.Security.Cryptography.
tvanfosson,

Grazie tvanfosson. Lo pseudo-casuale è sufficiente per questo problema.
Judah Gabriel Himango,

5
In realtà, Random non è nemmeno particolarmente pseudo-casuale a meno che non tieni l'istanza in giro per un po 'e continui a ricavarne dei valori.
David Mitchell,

2
Ecco perché questo è solo un esempio, piuttosto che un codice di produzione.
Joel Coehoorn,

1
Sì, funziona per me; il mio codice del mondo reale avrà l'istanza casuale al di fuori del metodo stesso.
Judah Gabriel Himango,

25

Ciò è in leggera risposta al commento di Joel sulla creazione di una versione leggermente più ottimizzata. Invece di restituire direttamente una data casuale, perché non restituire una funzione generatore che può essere chiamata ripetutamente per creare una data casuale.

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

Puoi spiegare come questo è benefico? Non potresti invece iniziare, gen e range come membri della classe?
Mark A. Nicolosi,

Potrebbero e in questo caso lo sono. Sotto il cofano questo genererà una chiusura lessicale che è un clagass contenente start, gen e range come membri. Questo è solo più conciso.
JaredPar,

Bella funzione, spero solo che nessuno lo userà come:for (int i = 0; i < 100; i++) { array[i].DateProp = RandomDayFunc()(); }
Aidiakapi

2
Come viene utilizzata questa funzione, qualcuno può spiegare? Voglio dire come posso chiamarlo?
Burak Karakuş,

2
@ BurakKarakuş: ottieni prima una fabbrica: var getRandomDate = RandomDayFunc();poi la chiami per ottenere date casuali: var randomDate = getRandomDate();ricorda che devi riutilizzare getRandomDate affinché questo sia più utile della risposta di Joel.
Şafak Gür

8

Ho preso la risposta di @Joel Coehoorn e ho apportato le modifiche da lui suggerite: estrai la variabile dal metodo e metti tutto in classe. Inoltre ora anche il tempo è casuale. Ecco il risultato.

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

Ed esempio come usare per scrivere 100 DateTime casuali sulla console:

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

Perché crei Random () due volte? Una volta in classe dichiarazione gen variabile e altra volta nel c-tor?
pixel

Sì, una volta è abbastanza. L'ho riparato.
prespic

1
È circa quattro volte più veloce generare un solo numero casuale di secondi e aggiungerlo alla data di inizio: range = (int)(DateTime.Today - start).TotalSeconds;e return start.AddSeconds(gen.Next(range));.
Jurgy,

5

Bene, se presenterai un'ottimizzazione alternativa, possiamo anche optare per un iteratore:

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

potresti usarlo in questo modo:

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

1
Una cosa da considerare tra un iteratore e una funzione di generatore è che la soluzione di iteratore produrrà un valore identificabile. Ciò costringe il chiamante a disporre o pagare il prezzo di avere un finalizzatore in diretta nel GC. Il generatore non ha bisogno di essere smaltito
JaredPar,

2
@JaredPar, non è del tutto esatto. Solo perché un tipo implementa IDisposable non significa che sia finalizzabile.
Drew Noakes,

3

Inizia con un oggetto data fisso (1 gennaio 1995) e aggiungi un numero casuale di giorni con AddDays (ovviamente, fai attenzione a non superare la data corrente).


Grazie Friol. Stavo per chiedere come limitare il numero passato in modo casuale. Joel ha pubblicato un esempio con un esempio di codice, quindi segnerò la sua risposta come risposta.
Giuda Gabriel Himango,

0

Sono un po 'in ritardo nel gioco, ma ecco una soluzione che funziona bene:

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

0

Piccolo metodo che restituisce una data casuale come stringa, basata su alcuni semplici parametri di input. Costruito sulla base delle variazioni delle risposte sopra:

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);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.