当尝试将分钟/秒舍入到最接近的小时(在这种情况下忽略分/秒部分)时,我对以下行为感到好奇.
我尝试了两种方法,并使用BenchMarkDotNet进行基准测试.
private DateTime testData = DateTime.Now;
[Benchmark]
public DateTime CeilingUsingNewOperator() => new DateTime(testData.Year,testData.Month,testData.Day,testData.Hour + 1,0,0);
[Benchmark]
public DateTime CeilingUsingAddOperator() => testData.AddHours(1).AddMinutes(-testData.Minute).AddSeconds(-testData.Second);
Run Code Online (Sandbox Code Playgroud)
以下是结果.
+-------------------------+-----------+----------+----------+
| Method | Mean | Error | StdDev |
+-------------------------+-----------+----------+----------+
| CeilingUsingNewOperator | 207.99 ns | 3.465 ns | 3.072 ns |
| CeilingUsingAddOperator | 108.74 ns | 1.429 ns | 1.337 ns |
+-------------------------+-----------+----------+----------+
Run Code Online (Sandbox Code Playgroud)
我很好奇为什么新运算符更慢,如果我假设,每次我们在第二种方法中调用AddX方法时,我们得到一个Datetime.
有人能解开一些光吗?
可以使用进一步的基准来验证这一点,但我强烈怀疑这是因为AddHours,AddMinutes并且AddSeconds方法都可以在不执行任何复杂的日期/时间算法的情况下工作.他们只需要:
DateTimeDateTime使用新的滴答数创建新值您还使用了Minute和Second属性,但可以在不计算月/日/年值的情况下计算它们.
将其与需要的"单一构造函数"调用进行比较:
计算年,月和日的代码需要"理解"公历 - 为了提取信息,要执行的计算要复杂得多.有些可以被缓存(例如,每年开始时的刻度数)但是在内存访问方面你会失去一些参考位置.
我希望最有效的方法是直接计算刻度,只需简单的算术:
long originalTicks = testData.Ticks;
long hoursSinceEpoch = originalTicks / TimeSpan.TicksPerHour;
long newTicks = hoursSinceEpoch * TimeSpan.TicksPerHour;
return new DateTime(newTicks, testData.Kind);
Run Code Online (Sandbox Code Playgroud)
这方面的一个显著下跌:我相信它会节省边界周围日光问题当DateTimeKind是Local,因为真的有四个种类的,而不是三个,我们通常使用(Utc,Local,Unspecified).Local有效地分成两部分以"知道"当先前选项和后一选项之间的值不明确时,表示哪个日期/时间.如果你没有使用Local它,它应该没问题.