【问题标题】:What's the best practice for getting a random DateTime between two date-times?在两个日期时间之间获取随机 DateTime 的最佳做法是什么?
【发布时间】:2010-12-01 19:18:45
【问题描述】:

我正在尝试随机化一个简单的 DateTime 数据字段的值。

我希望获得两个日期/时间之间的随机日期/时间(例如最小日期/时间和最大日期/时间)。

所以让我们想象一下我是在一个随机的日期/时间之后

1/1/2000 10:00:00am1/1/2000 5:00:00pm

此外,此代码将在 for 循环中使用,包含 100 个项目......这意味着所有 100 个项目将在最小/最大日期/时间段之间具有随机日期/时间。

有什么想法吗?

【问题讨论】:

标签: c# .net datetime random


【解决方案1】:

您可以尝试使用:

var randomTest = new Random();

TimeSpan timeSpan = endDate - startDate;
TimeSpan newSpan = new TimeSpan(0, randomTest.Next(0, (int)timeSpan.TotalMinutes), 0);
DateTime newDate = startDate + newSpan;

这将为您提供精确到分钟的不同时间。如果您想要 100 个(或超过 1 个)DateTimes,那么只需创建一次 Random 对象。 MSDN page on Random 详细解释了为什么快速连续创建多个 Random 对象是一个坏主意。

使用不同的TimeSpan 构造函数会给你不同的粒度。来自TimeSpan constructor MSDN

TimeSpan(Int64) 将新的 TimeSpan 初始化为指定的刻度数。
TimeSpan(Int32, Int32, Int32) 将新的 TimeSpan 初始化为指定的小时、分钟和秒数。
TimeSpan(Int32, Int32, Int32, Int32) 将新的 TimeSpan 初始化为指定的 天、小时、分钟和秒。
TimeSpan(Int32, Int32, Int32, Int32, Int32) 将新的 TimeSpan 初始化为指定的天、小时、分钟、秒和毫秒数.

【讨论】:

    【解决方案2】:

    这是我的算法和代码:

    • 找出两个日期之间的差异
    • 对于每次迭代,在两个日期之间创建一个随机数
    • 在他们之间创建一个新的日期。只需将该随机数作为分钟添加到开始日期时间。

      Random randNum = new Random();
      
      DateTime minDt = new DateTime(2000,1,1,10,0,0);
      DateTime maxDt = new DateTime(2000,1,1,17,0,0);
      List<DateTime> myDates = new List<DateTime>();
      //Random.Next in .NET is non-inclusive to the upper bound (@NickLarsen)
      int minutesDiff = Convert.ToInt32(maxDt.Subtract(minDt).TotalMinutes+1);
      
      for (int i = 0; i < 100; i++)
      {
         // some random number that's no larger than minutesDiff, no smaller than 1
         int r=   randNum.Next(1, minutesDiff); 
         myDates.Add(minDt.AddMinutes(r));
      }
      
      foreach (DateTime d in myDates)
      {
        Console.WriteLine(string.Format("{0:dd-MMM-yyyy hh:mm}",d));
      }
      

    【讨论】:

      【解决方案3】:

      这是我正在使用的:

      class RandomDates
      {
          private Random random = new Random();
      
          public DateTime Date(DateTime? start = null, DateTime? end = null)
          {
              if (start.HasValue && end.HasValue && start.Value >= end.Value)
                  throw new Exception("start date must be less than end date!");
      
              DateTime min = start ?? DateTime.MinValue;
              DateTime max = end ?? DateTime.MaxValue;
      
              // for timespan approach see: http://stackoverflow.com/q/1483670/1698987
              TimeSpan timeSpan = max - min;
      
              // for random long see: http://stackoverflow.com/a/677384/1698987
              byte[] bytes = new byte[8];
              random.NextBytes(bytes);
      
              long int64 = Math.Abs(BitConverter.ToInt64(bytes, 0)) % timeSpan.Ticks;
      
              TimeSpan newSpan = new TimeSpan(int64);
      
              return min + newSpan;
          }
      }
      

      我在接受的答案中使用了该方法,但由于遇到问题而对其进行了轻微修改。

      【讨论】:

      • 这个方法应该命名为DateTime而不是Date——我脑子里想的是简单的日期,但它当然会返回一个DateTime
      【解决方案4】:

      真的很快:

      1. 将您的日期转换为 TotalHours
      2. 一个数字减去另一个数字并使用 Abs 得到正数
      3. 在1和2的结果范围内创建一个随机数。以上
      4. 将生成的随机小时数加回两个日期中较早的日期

      【讨论】:

      • 当你的答案出现时,我只是给出了相同的答案;)
      • 正在尝试将此评论附加到上一篇文章...请记住 .NET 中的 Random.Next 不包含上限。
      【解决方案5】:

      首先,弄清楚你想要的随机 DateTime 的精度是多少(小时、分钟、秒、毫秒等)。

      然后找出该单元中两个日期之间的差异。

      在 0 和那个差之间创建一个随机整数。

      以单位为单位的随机整数添加到原始日期。

      根据您上面所说的用例,在 for 循环中计算外部差异。

      在 for 循环中,获取随机 int 并构造随机日期。

      【讨论】:

        【解决方案6】:

        基于 ChrisF 解决方案的单线

        var newDate = startDate.AddHours(new Random(Convert.ToInt32(DateTime.Now.Ticks / int.MaxValue)).Next(0, (int)(endDate - startDate).TotalHours));
        

        【讨论】:

        • 只想说,这样的单行代码对代码的可读性没有好处。对于生产系统,请避免使用这些。
        【解决方案7】:

        这是一个使用随机刻度数的方法:

        Random r= new Random(); 
            //for better randomness don't recreate a new Random() too frequently.
        long rand62bit = (((long)r.Next())<<31) + r.Next(); 
            // 62bits suffices for random datetimes, 31 does not!
        DateTime newDate = startDate + new TimeSpan(rand62bit % (endDate - startDate).Ticks); 
        

        此方法不包括最后一个日期,包括第一个日期。您可以通过在基本(endDate - startDate).Ticks 数量上添加一个勾号来轻松包含最后日期。

        【讨论】:

          猜你喜欢
          • 2017-06-03
          • 2014-05-22
          • 2014-11-06
          • 1970-01-01
          • 2018-10-16
          • 2011-06-05
          • 2013-11-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多