Nothing is better than seeing some numbers reflecting the
points mentioned above, so here I try to write simple programs that compare the
performance of DateTime.Now, DateTime.UtcNow,
and Stopwatch. Normally, it’s hard to compare the
properties of DateTime structure with Stopwatch as they are different by nature, however,
thinking a little bit about good examples, it’s possible to relate them
together and compare their runtime performance.
Here I develop three pieces of code that accomplish the same
goal using these three approaches. I generate different sample sizes
(incremented by a unit of 500 for 10 sample data batches) and perform a very
basic (and senseless) task. I use DateTime.Now, DateTime.UtcNow, and Stopwatch to
calculate the time that it takes to run my code. I measure my elapsed time
using QueryPerformanceCounter to have a good
precision.
Listing 5: Code to test DateTime.Now
private static void TestDateTimeNow()
{
Console.WriteLine("Testing DateTime.Now ...");
for (int sampleSize = 500; sampleSize <= 5000; sampleSize += 500)
{
long start = 0;
QueryPerformanceCounter(ref start);
for (int counter = 0; counter < sampleSize; counter++)
{
DateTime startTime = DateTime.Now;
int dumbSum = 0;
for (int temp = 0; temp < 5; temp++)
dumbSum++;
DateTime endTime = DateTime.Now;
TimeSpan duration = endTime - startTime;
}
long end = 0;
QueryPerformanceCounter(ref end);
long time = 0;
time = end - start;
Console.WriteLine("Sample Size: {0} - Time: {1}", sampleSize, time);
}
}
A very similar code can be used with DateTime.UtcNow
(listing 6).
Listing 6: Code to test DateTime.Now
private static void TestDateTimeUtcNow()
{
Console.WriteLine("Testing DateTime.UtcNow ...");
for (int sampleSize = 500; sampleSize <= 5000; sampleSize += 500)
{
long start = 0;
QueryPerformanceCounter(ref start);
for (int counter = 0; counter < sampleSize; counter++)
{
DateTime startTime = DateTime.UtcNow;
int dumbSum = 0;
for (int temp = 0; temp < 5; temp++)
dumbSum++;
DateTime endTime = DateTime.UtcNow;
TimeSpan duration = endTime - startTime;
}
long end = 0;
QueryPerformanceCounter(ref end);
long time = 0;
time = end - start;
Console.WriteLine("Sample Size: {0} - Time: {1}", sampleSize, time);
}
}
And finally, Stopwatch can be
applied to measure the duration of time to execute this code using its Start and Stop methods as well as
its Elapsed property (listing 7).
Listing 7: Code to test Stopwatch
private static void TestStopwatch()
{
Console.WriteLine("Testing Stopwatch ...");
for (int sampleSize = 500; sampleSize <= 5000; sampleSize += 500)
{
long start = 0;
QueryPerformanceCounter(ref start);
for (int counter = 0; counter < sampleSize; counter++)
{
Stopwatch watch = new Stopwatch();
watch.Start();
int dumbSum = 0;
for (int temp = 0; temp < 5; temp++)
dumbSum++;
watch.Stop();
TimeSpan duration = watch.Elapsed;
}
long end = 0;
QueryPerformanceCounter(ref end);
long time = 0;
time = end - start;
Console.WriteLine("Sample Size: {0} - Time: {1}", sampleSize, time);
}
}
Sometimes a picture is worth a thousand words and figure 1 can
reflect whatever I’ve mentioned so far.
Figure 1: Quantitative comparison between
DateTime.Now, DateTime.UtcNow, and Stopwatch
Here we see some interesting results and it’s more
interesting when we consider the fact that these codes are tested with
realistic sample data sizes between 500 and 5000. Here DateTime.Now
(the blue line) has the worst performance at top followed by Stopwatch (the green line) and DateTime.UtcNow
(the red line). UtcNow stands much lower than the
other options with a very steady pace (unlike other two options) and
surprisingly, performs better than Stopwatch. This is
of course expected as I showed you the internal implementation of Stopwatch which is using DateTime.UtcNow
with some extra processing.
Here a good question is why we need to use Stopwatch when DateTime.UtcNow is
performing better. The answer is that it’s possible to do that and actually,
it’s much better if you’re sure that you get such a significant difference by
applying UtcNow rather than Stopwatch.
But there is a major and a minor advantage for Stopwatch
over UtcNow. The major advantage is that Stopwatch can perform in a higher resolution by applying QueryPerformanceCounter rather than DateTime.UtcNow.
The minor advantage is that Stopwatch provides a more
fluent and human-readable method to perform this task.