views:

137

answers:

3

A colleague and I are going back and forth on this issue and I'm hoping to get some outside opinions as to whether or not my proposed solution is a good idea.

First, a disclaimer: I realize that the notion of "optimizing DateTime.Now" sounds crazy to some of you. I have a couple of pre-emptive defenses:

  1. I sometimes suspect that those people who always say, "Computers are fast; readability always comes before optimization" are often speaking from experience developing applications where performance, though it may be important, is not critical. I'm talking about needing things to happen as close to instantaneously as possible -- like, within nanoseconds (in certain industries, this does matter -- for instance, real-time high-frequency trading).
  2. Even with that in mind, the alternative approach I describe below is, in fact, quite readable. It is not a bizarre hack, just a simple method that works reliably and fast.
  3. We have runs tests. DateTime.Now is slow (relatively speaking). The method below is faster.

Now, onto the question itself.

Basically, from tests, we've found that DateTime.Now takes roughly 25 ticks (around 2.5 microseconds) to run. This is averaged out over thousands to millions of calls, of course. It appears that the first call actually takes a significant amount of time and subsequent calls are much faster. But still, 25 ticks is the average.

However, my colleague and I noticed that DateTime.UtcNow takes substantially less time to run -- on average, a mere 0.03 microseconds.

Given that our application will never be running while there is a change in Daylight Savings Time, my suggestion was to create the following class:

public static class FastDateTime {
    public static TimeSpan LocalUtcOffset { get; private set; }

    public static DateTime Now {
        get { return DateTime.UtcNow + LocalUtcOffset; }
    }

    static FastDateTime() {
        LocalUtcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
    }
}

In other words, determine the UTC offset for the local timezone once -- at startup -- and from that point onward leverage the speed of DateTime.UtcNow to get the current time a lot faster via FastDateTime.Now.

I could see this being a problem if the UTC offset changed during the time the application was running (if, for example, the application was running overnight); but as I stated already, in our case, that will not happen.

My colleague has a different idea about how to do it, which is a bit too involved for me to explain here. Ultimately, as far as I can tell, both of our approaches return an accurate result, mine being slightly faster (~0.07 microseconds vs. ~0.21 microseconds).

What I want to know is:

  1. Am I missing something here? Given the abovementioned fact that the application will only run within the time frame of a single date, is FastDateTime.Now safe?
  2. Can anyone else perhaps think of an even faster way of getting the current time?
+1  A: 

To answer in reverse order:

2) I cannot think of a faster way.

1) It would be worth checking if there are any framework improvements in the pipeline like they have just announced for System.IO

It's hard to be sure about safety but it's something that is crying out for a lot of unit tests. Daylight savings comes to mind. The System one is obviously very battle hardened while yours is not.

dove
+5  A: 

Could you just use DateTime.UtcNow, and only convert to local time when the data is presented? You've already determined that DateTime.UtcNow is much faster and it will remove any ambiguity around DST.

Michael
+1 I read that UtcNow is a lot faster, which was surprising to me. http://blogs.msdn.com/clrperfblog/archive/2009/09/08/computing-time-in-net.aspx
kenny
I'm going to go ahead and just accept this answer because it makes so much darned sense. Unfortunately I don't think we'll be doing this (at least not yet) because of the amount of code we'd have to change. But it's an incredibly logical suggestion.
Dan Tao
A: 

One difference between the result of

DateTime.Now

and

DateTime.UtcNow + LocalUtcOffset 

is the value of the Kind property - Local vs Utc respectively. If the resultant DateTime is being passed to a third party library consider returning

DateTime.SpecifyKind(DateTime.UtcNow + LocalUtcOffset, DateTimeKind.Local)
Handcraftsman