15

I just saw this upvoted comment

IIRC DateTime.Today is a quite expensive call, so you better store the value in a variable first.

It was in response to a post that contained the code:

var first = 
    new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(-1);
var last = 
    new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddDays(-1);

If I am looking to improve performance, how important is it to store DateTime.Today in a variable instead of calling it multiple times? And roughly how many uses of DateTime.Today would justify creating a variable for it?

Edit: I realize I should test my program to see if there are performance problems first before worrying about something as trivial as this. For the sake of this question, assume that I have already done this and determined that additional optimization is needed.

Community
  • 1
  • 1
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Personally I'd only take a variable if I wanted the `Today` value to be the same for all usages. Otherwise I'd code for readability and forget about the performance issue until it becomes a hot spot. Of course, if performance is paramount then the obvious answer is to take a variable whenever you use it 2 or more times. How many times before it becomes a problem is entirely subjective, but I would surmise it'd take *a lot* of calls before it comes a problem. – Adam Houldsworth Apr 03 '13 at 15:29
  • 2
    I think you should write a program to test it out and post the results! – Mike Christensen Apr 03 '13 at 15:29
  • 2
    Side note: the main issue with this code it is *not correct* - imagine what will happen once a day/year when 2 calls to `Today` hit different days. It also shows that `Today`/`Now` are not testable as writing unit test for "new year" condition is less than trivial - so you'd be much better off abstracting this call even at some performance cost and testing results... – Alexei Levenkov Apr 03 '13 at 15:50

7 Answers7

9

how important is it to store DateTime.Today in a variable

The best answer to that is to benchmark on the hardware you expect your code to be running on. Unless you are calling it in an extremely tight loop, I doubt it will be a problem.

A better reason to store it in a variable is that you just might roll over from one day to the next between the two calls.

UPDATE

To provide an order of magnitude, @RichardBrown shared in his answer a link indicating that the cost of DateTime.Today is was tested to be on the order of a few hundred nanoseconds (on the particular hardware used for that test).

Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • +1 especially for "roll over" - `Today`/`Now` called throughout the code will easily cause interesting issues when called multiple times in same computation/condition... And one can't test such code - so "performance improvements" due to caching of result will likely be achieved by ignoring correctness altogether. – Alexei Levenkov Apr 03 '13 at 15:54
  • Thanks for pointing out a good reason to use a variable instead of `DateTime.Today`, however I am specifically asking about if `DateTime.Today` is an expensive operation in terms of micro-optimizing my code, and your answer of "I doubt it" isn't really what I was looking for :) – Rachel Apr 03 '13 at 16:12
  • If you truly are interested in micro-optimization, see the blog post in @RichardBrown's answer that I reference in my answer. – Eric J. Apr 03 '13 at 16:18
6

Benchmark (on my machine, using the Stopwatch class):

10,000 DateTime.Today calls and assignment to local variable: 0.0125781 seconds.

10,000 Assignment only operations: 0.0001062 seconds.

Code:

var s = new Stopwatch();
DateTime date = DateTime.Today;
DateTime date2 = DateTime.Today;
s.Start();
for (int i=0; i<10000; i++)
    date = DateTime.Today;
s.Stop();
Debug.Print(s.Elapsed.ToString());

s.Reset();
s.Start();
for (int i=0; i<10000; i++)
    date2 = date;
s.Stop();
Debug.Print(s.Elapsed.ToString());
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • I just did 100,000 and it took around 37-38 ms – Cemafor Apr 03 '13 at 15:41
  • @Cemafor: I'll post my code. It's on a quad-core Dell Precision workstation, about 2 years old. – Robert Harvey Apr 03 '13 at 15:45
  • The conclusion I draw from your answer is that it's safe to assume that the claim of `DateTime.Today` being an "expensive" call is not really true (at least with today's technology). It's a more expensive call than reading from a variable, but the call itself isn't really expensive and I shouldn't really be concerned about it unless I'm trying to micro-optimize your code. Thank you :) – Rachel Apr 03 '13 at 16:10
  • 2
    @Rachel: If two orders of magnitude is not a significant difference, then yes, I guess you can make that conclusion. :) The only likely scenario that I can forsee DateTime being called this many times is in a report or batch process, and for that, I might cache the value, for reasons mentioned by others here not related to performance (on the off-chance that someone is running a report or batch process at one minute before midnight). – Robert Harvey Apr 03 '13 at 16:13
  • @RobertHarvey: I'm on a lenovo thinkpad with an i7-2630gm @ 2.00GHz. The code I used was almost exactly the same. I actually tried both starting and stoping inside (just around the DateTime.Today call) and outside the loop, and inside was actually slower. Presumably because the calls to Start and Stop have some overhead that can't be avoided. – Cemafor Apr 03 '13 at 16:45
  • @Cemafor: If you wrote the code correctly, the start and stop calls are only executed *once*, for every 100,000 calls to `DateTime.Today`. The overhead should be negligible. – Robert Harvey Apr 03 '13 at 16:46
  • @RobertHarvey I tried both, just to see the difference when leaving out the loop "logic". With the start and stop being called once, it was faster, even though it had the loop iteration/checking as part of the timer. Moving the Start and Stop into the loop took out the loop's overhead but compounded the overhead of the Start and Stop calls. – Cemafor Apr 03 '13 at 16:52
  • @RobertHarvey: Matches what I was getting with mine. With 10k itterations, both ran in 3.55ms. With 100k, yours was 33.26ms and mine 33.19ms (the 37ms I posted before was with the multiple Start/Stop calls). – Cemafor Apr 03 '13 at 16:59
  • @Cemafor: I got 0.1257827 with 100,000 iterations, almost exactly 10x the execution time of 10,000 iterations. It appears that, *on this particular task,* your combination of hardware and software is about 4 times faster than mine executing `DateTime.Today`. :) – Robert Harvey Apr 03 '13 at 17:05
  • The moral of the story is DateTime.Today isn't that slow and computer speeds very. And save DateTime.Today if there is a possiblility of the execution happening over the midnight barrier, and it is important they are the same. – Cemafor Apr 03 '13 at 17:13
3

I reject the premise that DateTime.Today is an expensive call. You should store it in a variable if it's important that it not change over time. If this code runs right around midnight of the end of a month you could have...problems. From a performance perspective I highly doubt this would be an issue.

In any case, it would be a micro-optimization. As with any performance issues if your working program is too slow you should profile it and look for sections taking quite a lot of time and focus on optimizing those, looking for code spending more time running than you would expect. If it happens that this one line of code is consuming a lot of time then consider changing it. Until then, only refactor it for correctness or readability, not performance.

Servy
  • 202,030
  • 26
  • 332
  • 449
2

For hard numbers on the performance of DateTime read this blog post. As previous answers state it's important to look at your particular configuration and needs when determining performance.

Richard Brown
  • 11,346
  • 4
  • 32
  • 43
1

I would guess that it is a problem if you are calling the code in a loop. But the best way to find out is to time it and see for yourself how long it takes.

var sw = new Stopwatch();
sw.Start();
today = DateTime.Today();
sw.Stop();
var ts = stopWatch.Elapsed;

MSDN Stopwatch reference

  • The time it takes to perform a single call like that of something that is so quick is meaningless. You need to make *lots* of calls an average the time spent. – Servy Apr 03 '13 at 16:24
1

The real reason to extract DateTime.Today as variable is to prevent possible bugs which will appear because of Murphy's law, but would never be isolated and fixed..

Idea is that between first and second usage of Today actual date may be changed, so you can get, for example, previous year and new month here:

var first = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(-1);

which may result, for example, in (January 2013) - 1 month instead of (December 2013) - 1 month.

More probable and more evil issue will be if you get date change between first and last assignment:

var first = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(-1);
var last = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddDays(-1);

which will result a year-more period.. Depending on your logic, it may lead to really expensive loss.

Lanorkin
  • 7,310
  • 2
  • 42
  • 60
0

More important than the question of performance is imo the readability and maintainability of code.

unless you don't have performance issues I would follow the rule "pay attention to performance improvements"

Perhaps if you have a loop than a variable could be named appropriate with "today" but again as long as there arent performance issued i would focus on the other concerns

Boas Enkler
  • 12,264
  • 16
  • 69
  • 143