Zufälliges Datum in C #


140

Ich suche nach einem prägnanten, modernen C # -Code, um ein zufälliges Datum zwischen dem 1. Januar 1995 und dem aktuellen Datum zu generieren.

Ich denke an eine Lösung, die Enumerable verwendet. Range kann dies irgendwie prägnanter machen.


Antworten:


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

Um eine bessere Leistung zu erzielen, wenn dies wiederholt aufgerufen wird, erstellen Sie die Variablen startund gen(und möglicherweise sogar range) außerhalb der Funktion.


1
Random ist nur pseudozufällig. Wenn Sie wirklich zufällige Daten benötigen, verwenden Sie RNGCryptoServiceProvider aus dem System.Security.Cryptography-Namespace.
Tvanfosson

Danke tvanfosson. Pseudozufällig ist für dieses Problem ausreichend.
Judah Gabriel Himango

5
Tatsächlich ist Random nicht einmal besonders pseudozufällig, es sei denn, Sie behalten die Instanz eine Weile bei und erhalten immer wieder Werte daraus.
David Mitchell

2
Aus diesem Grund ist dies nur ein Beispiel und kein Produktionscode.
Joel Coehoorn

1
Ja, das funktioniert bei mir; Mein realer Code hat die Random-Instanz außerhalb der Methode.
Judah Gabriel Himango

25

Dies ist eine leichte Reaktion auf Joels Kommentar, eine etwas optimierte Version zu erstellen. Anstatt ein zufälliges Datum direkt zurückzugeben, können Sie eine Generatorfunktion zurückgeben, die wiederholt aufgerufen werden kann, um ein zufälliges Datum zu erstellen.

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

Können Sie erklären, wie vorteilhaft dies ist? Könnten Start, Gen und Range nicht stattdessen Klassenmitglieder sein?
Mark A. Nicolosi

Sie könnten und in diesem Fall sind sie. Unter der Haube wird ein lexikalischer Verschluss erzeugt, der eine Klasse ist, die Start, Gen und Bereich als Mitglieder enthält. Dies ist nur prägnanter.
JaredPar

Gute Funktion, ich hoffe nur, dass niemand sie verwenden wird als:for (int i = 0; i < 100; i++) { array[i].DateProp = RandomDayFunc()(); }
Aidiakapi

2
Wie wird diese Funktion verwendet, kann jemand bitte erklären? Ich meine, wie kann ich es nennen?
Burak Karakuş

2
@ BurakKarakuş: Sie erhalten zuerst eine Fabrik: var getRandomDate = RandomDayFunc();Dann rufen Sie sie auf, um zufällige Daten zu erhalten: var randomDate = getRandomDate();Denken Sie daran, dass Sie getRandomDate wiederverwenden müssen, damit dies nützlicher ist als Joels Antwort.
Şafak Gür

8

Ich habe die Antwort von @Joel Coehoorn genommen und die von ihm empfohlenen Änderungen vorgenommen - die Variable aus der Methode entfernen und alle in die Klasse einfügen. Außerdem ist die Zeit jetzt auch zufällig. Hier ist das Ergebnis.

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

Und ein Beispiel für das Schreiben von 100 zufälligen DateTimes in die Konsole:

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

Warum erstellen Sie Random () zweimal? Einmal in der Klassenvariablen-Gendeklaration und ein anderes Mal im C-Tor?
Pixel

Ja, einmal ist genug. Ich habe es repariert.
Prespic

1
Es ist ungefähr viermal schneller, nur eine zufällige Anzahl von Sekunden zu generieren und diese zu Ihrem Startdatum hinzuzufügen: range = (int)(DateTime.Today - start).TotalSeconds;und return start.AddSeconds(gen.Next(range));.
Jurgy

5

Wenn Sie eine alternative Optimierung vorstellen, können wir uns auch für einen Iterator entscheiden:

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

Sie könnten es so verwenden:

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

1
Eine Sache, die zwischen einer Iterator- und einer Generatorfunktion berücksichtigt werden muss, ist, dass die Iteratorlösung einen IDisposable-Wert erzeugt. Dies zwingt den Anrufer, über den Preis eines Live-Finalisierers im GC zu verfügen oder diesen zu zahlen. Der Generator muss nicht entsorgt werden
JaredPar

2
@ JaredPar, das ist nicht ganz richtig. Nur weil ein Typ IDisposable implementiert, heißt das nicht, dass er finalisierbar ist.
Drew Noakes

3

Beginnen Sie mit einem Objekt mit festem Datum (1. Januar 1995) und fügen Sie mit AddDays eine zufällige Anzahl von Tagen hinzu (achten Sie darauf, dass Sie das aktuelle Datum nicht überschreiten).


Danke Friol. Ich wollte fragen, wie ich die zufällige Anzahl begrenzen kann. Joel hat ein Beispiel mit einem Codebeispiel veröffentlicht, daher werde ich seine Antwort als Antwort markieren.
Judah Gabriel Himango

0

Ich bin etwas spät dran, aber hier ist eine Lösung, die gut funktioniert:

    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

Kleine Methode, die basierend auf einigen einfachen Eingabeparametern ein zufälliges Datum als Zeichenfolge zurückgibt. Gebaut basierend auf Abweichungen von den obigen Antworten:

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);
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.