为什么我的随机 DateTime 生成器使日期超出范围?

Why my random DateTime generator make dates outside of range?

我有一个函数可以在两个日期之间的范围内生成随机日期时间...并且它以某种方式使随机日期出现在最小日期之前。我的代码有什么问题?

public void TestFunct()
{
    GenerateRandomTimeBetweenDates(new Random(), DateTime.ParseExact("01.01.2017 00:00:00", "dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture), DateTime.ParseExact("01.02.2017 00:00:00", "dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture));
}

public DateTime GenerateRandomTimeBetweenDates(Random RNG, DateTime dt1, DateTime dt2)
{
    int dt1_sec = (int)dt1.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds; //calc seconds since Unix epoch
    int dt2_sec = (int)dt2.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
    int random_sec = RNG.Next(Math.Min(dt1_sec, dt2_sec), Math.Max(dt1_sec, dt2_sec)); //RNG is Random instance. Here I generate seconds amount between two amounts - minimal and maximal.

    DateTime random_dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(random_sec); //I try to recreate date by adding generated seconds amount to Unix epoch.

    if (random_dt.Year == 2016)
        random_dt = random_dt; //this I use to trigger breakpoint

    return random_dt;
}

这里的问题是ToUniversalTime()。如果您的日期是 LocalUnspecified - ToUniversalTime 会将它们转换为 UTC 假设(在 Unspecified 的情况下)它们是本地的。通过这样做,您的 dt1,即 2017 年 1 月 1 日将在 UTC 中表示为 2016 年的日期。当随机值接近最小值时 - 结果也将在 2016 年。要修复 - 只需删除对 ToUniversalTime() 的调用。您可以删除它,因为根据 Substract 方法的文档:

The System.DateTime.Subtract(System.DateTime) method does not consider the value of the System.DateTime.Kind property of the two System.DateTime values when performing the subtraction

但是请注意,最好 return 结果与输入的类型相同,因此:

DateTime random_dt = new DateTime(1970, 1, 1, 0, 0, 0, dt1.Kind).AddSeconds(random_sec); 

因为否则,如果您的输入代表当地时间并且结果是 UTC - 没有多大意义。