C # 'da rastgele tarih


Yanıtlar:


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

Eğer tekrar tekrar çağrılırsa daha iyi performans için startve gen(ve hatta belki range) değişkenleri fonksiyonun dışında oluşturun.


1
Rastgele yalnızca sözde rastgele olur. Gerçekten rasgele ihtiyacınız varsa, System.Security.Cryptography ad alanından RNGCryptoServiceProvider'ı kullanmayı deneyin.
tvanfosson

Teşekkürler tvanfosson. Bu sorun için sözde rastgele yeterlidir.
Judah Gabriel Himango

5
Aslında, örneği bir süre boyunca tutmazsanız ve değerlerden çıkarmaya devam etmezseniz, Rastgele özellikle sözde rastgele değildir.
David Mitchell

2
Bu yüzden bu, üretim kodu yerine sadece bir örnektir.
Joel Coehoorn

1
Evet, bu benim için işe yarıyor; gerçek dünya kodumda, yöntemin kendisinin dışında Random örneği bulunur.
Judah Gabriel Himango

25

Bu, Joel'in çok daha optimize edilmiş bir sürüm yapma hakkındaki yorumuna hafif bir yanıt veriyor. Rastgele bir tarihi doğrudan döndürmek yerine, neden rastgele bir tarih oluşturmak için tekrar tekrar çağrılabilen bir jeneratör işlevi döndürmüyorsunuz?

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

Bunun nasıl faydalı olduğunu açıklayabilir misiniz? Bunun yerine başlangıç, gen ve menzil sınıf üyesi olamaz mı?
Mark A.Nicolosi

Yapabilirler ve bu durumda öyleler. Kaputun altında bu, üye olarak başlangıç, gen ve menzil içeren karmaşık bir sözcük oluşturacak. Bu sadece daha özlü.
JaredPar

Güzel bir işlev, sadece kimsenin onu kullanamayacağını umuyorum:for (int i = 0; i < 100; i++) { array[i].DateProp = RandomDayFunc()(); }
Aidiakapi

2
Bu işlev nasıl kullanılır, birisi açıklayabilir mi? Nasıl diyebilirim ki?
Burak Karakuş

2
@ BurakKarakuş: İlk önce bir fabrika alırsınız: var getRandomDate = RandomDayFunc();o zaman rastgele tarihler almak için onu çağırırsınız: Bunun var randomDate = getRandomDate();Joel'in cevabından daha yararlı olması için getRandomDate'i tekrar kullanmanız gerektiğini unutmayın.
Şafak Gür

8

@Joel Coehoorn'un cevabını aldım ve önerdiği değişiklikleri yaptım - değişkeni metodun dışına çık ve hepsini sınıfa koydum. Artı şimdi zaman da rastgele. İşte sonuç.

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

Konsolda 100 rastgele DateTimes yazmak için nasıl kullanılacağına örnek:

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

Neden iki kez Random () oluşturuyorsunuz? Sınıfta bir kez değişken gen bildirimi ve diğer zaman c-tor?
piksel

Evet, bir kere yeter. Onardım.
prespic

1
Sadece rastgele bir sayıda saniye oluşturmak ve bunu başlangıç ​​tarihinize eklemek yaklaşık dört kat daha hızlıdır: range = (int)(DateTime.Today - start).TotalSeconds;ve return start.AddSeconds(gen.Next(range));.
Jurgy

5

Alternatif optimizasyon sunacaksanız, bir yineleyici de yapabiliriz:

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

şöyle kullanabilirsiniz:

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

1
Bir yineleyici ile bir jeneratör işlevi arasında dikkate alınması gereken bir şey, yineleyici çözümünün IDisposable bir değer üretmesidir. Bu, arayanı bir sonlandırıcıyı GC'de yaşamanın fiyatını atmaya veya ödemeye zorlar. Jeneratör bertaraf gerektirmiyor
JaredPar

2
@JaredPar, bu pek doğru değil. Bir tipin IDisposable'ı uygulaması, sonlandırılabilir olduğu anlamına gelmez.
Drew Noakes

3

Sabit bir tarih nesnesiyle başlayın (1 Ocak 1995) ve AddDays ile rastgele sayıda gün ekleyin (açıkça, geçerli tarihi geçmemeye dikkat edin).


Teşekkürler Friol. Rastgele geçen sayıyı nasıl sınırlayacağımı soracaktım. Joel kod örneği ile bir örnek gönderdi, bu yüzden cevabını cevap olarak işaretleyeceğim.
Judah Gabriel Himango

0

Oyuna biraz geç kaldım, ama burada iyi çalışan bir çözüm var:

    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

Bazı basit giriş parametrelerine dayanarak rastgele bir tarih dize olarak döndüren küçük yöntem. Yukarıdaki cevaplardan farklı olarak oluşturulmuştur:

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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.