为什么我的随机 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()
。如果您的日期是 Local
或 Unspecified
- 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 - 没有多大意义。
我有一个函数可以在两个日期之间的范围内生成随机日期时间...并且它以某种方式使随机日期出现在最小日期之前。我的代码有什么问题?
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()
。如果您的日期是 Local
或 Unspecified
- 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 - 没有多大意义。