【问题标题】:Random date in C#C#中的随机日期
【发布时间】:2010-09-16 17:30:09
【问题描述】:

我正在寻找一些简洁的现代 C# 代码来生成 1995 年 1 月 1 日和当前日期之间的随机日期。

我在想一些利用 Enumerable.Range 的解决方案可能会使这更简洁。

【问题讨论】:

标签: c# datetime random date


【解决方案1】:
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));
}

为了在重复调用时获得更好的性能,请在函数的外部创建startgen(甚至可能是range)变量。

【讨论】:

  • 随机只是伪随机。如果您需要真正随机,请尝试使用 System.Security.Cryptography 命名空间中的 RNGCryptoServiceProvider。
  • 实际上,Random 甚至不是特别伪随机,除非您将实例保留一段时间并不断从中获取值。
  • 这就是为什么这只是一个示例,而不是生产代码。
  • 是的,这对我有用;我的实际代码将在方法本身之外有 Random 实例。
  • @ShadowWizard 我的错。我在想 Days 不是 TimeSpan 中最重要的部分,因此 Days 和 TotalDays 之间的差异会非常明显,就像 Minutes 一样。
【解决方案2】:

这是对 Joel 关于制作稍微更优化版本的评论的轻微回应。与其直接返回随机日期,不如返回一个可以重复调用以创建随机日期的生成器函数。

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 改为类成员吗?
  • 他们可以而且在这种情况下他们是。在幕后,这将生成一个词法闭包,它是一个包含 start、gen 和 range 作为成员的类。这更简洁。
  • 不错的功能,我只是希望没有人会使用它:for (int i = 0; i &lt; 100; i++) { array[i].DateProp = RandomDayFunc()(); }
  • 这个函数是怎么用的,谁能解释一下?我的意思是我怎么称呼它?
  • @BurakKarakuş:你首先得到一个工厂:var getRandomDate = RandomDayFunc(); 然后你调用它来获取随机日期:var randomDate = getRandomDate(); 请注意,你需要重用 getRandomDate 以便它比乔尔的答案更有用.
【解决方案3】:

我接受了@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 个随机 DateTimes 写入控制台的示例:

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

【讨论】:

  • 为什么要创建 Random() 两次?一次在类变量 gen 声明中,其他时间在 c-tor 中?
  • 是的,一次就够了。我修好了。
  • 仅生成一个随机秒数并将其添加到您的开始日期大约快四倍:range = (int)(DateTime.Today - start).TotalSeconds;return start.AddSeconds(gen.Next(range));
【解决方案4】:

好吧,如果您要介绍替代优化,我们也可以使用迭代器:

 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,这不太对。仅仅因为一个类型实现了 IDisposable 并不意味着它是可终结的。
【解决方案5】:

从一个固定的日期对象(1995 年 1 月 1 日)开始,用 AddDays 添加一个随机天数(显然,注意不要超过当前日期)。

【讨论】:

  • 谢谢弗里奥尔。我要问如何限制传递给随机的数字。 Joel 发布了一个带有代码示例的示例,因此我会将他的回复标记为答案。
【解决方案6】:
Random rnd = new Random();
DateTime datetoday = DateTime.Now;

int rndYear = rnd.Next(1995, datetoday.Year);
int rndMonth = rnd.Next(1, 12);
int rndDay = rnd.Next(1, 31);

DateTime generateDate = new DateTime(rndYear, rndMonth, rndDay);
Console.WriteLine(generateDate);

//这可能不是最好的方法,但快速且易于理解

【讨论】:

    【解决方案7】:

    我玩游戏有点晚了,但这里有一个很好的解决方案:

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

    【讨论】:

      【解决方案8】:

      根据一些简单的输入参数返回随机日期作为字符串的小方法。基于上述答案的变体构建:

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

      【讨论】:

        【解决方案9】:

        基于@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。你确定吗?
        猜你喜欢
        • 2022-01-23
        • 2015-02-05
        • 2021-01-26
        • 2015-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-03
        • 2014-02-25
        相关资源
        最近更新 更多