如何获得Now和之前某个时间点之间的随机时间(例如1小时前)?

Pur*_*ome 5 .net c# random

我正在尝试创建一个扩展方法,允许我以TimeSpan的形式在Now和一些用户请求的历史时间点之间创建一个随机时间.

例如:从现在到1小时之前的随机时间.

所以,我提出了以下Random(..)扩展方法.

我想让随机种子不是静态的,但是如果我把这种方法称为很多而且很快(例如在循环中),那么我认为种子(基于时间)对于真正的快速调用来说并不是真正随机的.真的吗?(似乎是,当我检查我的结果时)

public static DateTimeOffset Random(this DateTimeOffset value, TimeSpan timeSpan)
{
    var random = new Random();
    DateTimeOffset minDateTime = value.Subtract(timeSpan);
    int range = ((DateTime.Today - minDateTime)).Hours;
    return minDateTime.AddHours(random.Next(range));
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 9

正如其他人所说,问题是new Random()使用当前时间来形成种子,并且你会多次获得相同的种子.

基本上你想创建相对较少的实例.由于Random不是线程安全的,您需要ThreadStaticThreadLocal<T>- 后者是.NET 4.0的新手.这是一个示例StaticRandom类(使用.NET 4.0),它允许您使用该Instance属性获取此线程的有效实例.请注意,在类型初始化时,将从当前时间设置计数器.然后将其用于连续种子.

using System;
using System.Threading;

public static class StaticRandom
{
    private static int seed;

    private static ThreadLocal<Random> threadLocal = new ThreadLocal<Random>
        (() => new Random(Interlocked.Increment(ref seed)));

    static StaticRandom()
    {
        seed = Environment.TickCount;
    }

    public static Random Instance { get { return threadLocal.Value; } }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以随时使用StaticRandom.Instance你需要的实例Random.

现在回到最初的问题,目前的扩展方法正在做什么并不完全清楚.你为什么一直在使用DateTime.Today?我怀疑你想要的东西:

public static DateTimeOffset Random(this DateTimeOffset value, TimeSpan timeSpan)
{
    double seconds = timeSpan.TotalSeconds * StaticRandom.Instance.NextDouble();

    // Alternatively: return value.AddSeconds(-seconds);
    TimeSpan span = TimeSpan.FromSeconds(seconds);
    return value - span;
}
Run Code Online (Sandbox Code Playgroud)

然而,这将给你一个完全随机的时间 - 例如,它几乎必然会在一毫秒之内.这没关系,或者你有效地希望它是基于原始时间跨度的精确秒数(或分钟,或小时)?


Luk*_*keH 7

使用Random一个创建/初始化对象一次,并不会在每次方法被调用的时间.另一种选择是Random在调用它时将实例传递给方法.

您还可以创建允许您执行上述任一选项的重载:

public static DateTimeOffset Random(this DateTimeOffset value, TimeSpan timeSpan)
{
    if (_threadStaticRng == null)
        _threadStaticRng = new Random();

    return value.Random(timeSpan, _threadStaticRng);
}

public static DateTimeOffset Random(
    this DateTimeOffset value, TimeSpan timeSpan, Random rng)
{
    DateTimeOffset minDateTime = value.Subtract(timeSpan);
    int range = ((DateTime.Today - minDateTime)).Hours;
    return minDateTime.AddHours(rng.Next(range));
}

[ThreadStatic]
private static Random _threadStaticRng;
Run Code Online (Sandbox Code Playgroud)

  • 这段代码唯一不好的地方在于,当它创建一个新实例时,它仍在使用当前时间.如果许多线程同时启动,它们将获得相同的序列.我想我会添加一个解决这个问题的答案...... (2认同)