1

When calling DateTime.UtcNow multiple times in short succession, is there a way to guarantee that it will return two different times and subsequent calls will have ever-increasing values?

I'm more concerned with precision than accuracy, and this is not a timer issue (i.e., I'm not trying to time how long something takes, I just want to get 2+ "current" but unique DateTimes).

Problem Example: The following code will repeat the same Ticks value many times and only increment every 15-30ms depending on the computer's speed.

for(int i = 0; i < 1000; i++) { Console.WriteLine(DateTime.UtcNow.Ticks); }

Right now I'm doing the following, but it seems like overkill for something as simple as getting the current time to a high precision - especially the Sleep(1). Is there a better way, and does this fulfill my original question? While it's statistically unlikely I'd get duplicate values at the Ticks level, I'm not sure this guarantees my values are ever-increasing due to the possibility of my clock being reset by a time server, leap seconds, or other issues I may not be thinking of. Daylight savings shouldn't be an issue since I'm using UTC.

private static DateTime prevDateTime = DateTime.UtcNow;
private static object nowLock = new object();
public static DateTime Now()
{
    lock(nowLock)
    {
        DateTime now = DateTime.UtcNow;
        if (now <= prevDateTime)
        {
            System.Threading.Thread.Sleep(1);
            now = DateTime.UtcNow;
        }
        prevDateTime = now;
        return now;
    }
}

// then call
for(int i = 0; i < 1000; i++) { Console.WriteLine(Now()); }
Rick
  • 1,733
  • 2
  • 18
  • 41
  • 6
    This sounds very much like an XY Problem. Perhaps you can describe what your end goal actually is? Everything about this just seems to be a bit smelly. – DavidG Jan 07 '17 at 16:47
  • 1
    http://stackoverflow.com/q/747742/11683 might be useful. – GSerg Jan 07 '17 at 16:53
  • @DavidG If successful, this could be used for multiple purposes in a DB (stored as bigint). It's unique, it would allow logging/playback of events in the proper order, and not require a separate timestamp AND counter field, it could be generated outside of the DB so that a roundtrip isn't needed to get an incrementing key to be used as a FK in linked tables. – Rick Jan 07 '17 at 17:20
  • 3
    @Rick It could only work for that if limit yourself to a single client. If you have multiple clients, you cannot prevent them from getting the same time. It also means that if your clock is ever wrong and you end up saving a date of e.g. 1-1-2018 in your database, you'll have made it very difficult to recover from that mistake. –  Jan 07 '17 at 17:42
  • if you need precision for local measurements, use `Stopwatch`, not `Datetime`. But the scenario you described two comments up is just not possible with APIs alone. It also requires [specialized time-synchronization hardware](https://www.meinbergglobal.com/english/products/) and advanced OS features, like those [now available in Windows Server 2016](https://technet.microsoft.com/en-us/windows-server-docs/identity/ad-ds/get-started/windows-time-service/windows-2016-accurate-time). – Matt Johnson-Pint Jan 07 '17 at 23:52

1 Answers1

3

Unfortunateely, you can not achieve your goal with DateTime.

DateTime.UtcNow accuracy is something about 15-16 msec in best case.

Probably, WinApi can help you (since Windows 8 and Windows Server 2012). See this article for more information.

Soner Gönül
  • 91,172
  • 101
  • 184
  • 324
Yury Glushkov
  • 661
  • 5
  • 14
  • 1
    Technically it's possible to get the accuracy of `UtcNow` lower than 15 ms. On our work machines we have it configured to have an accuracy of about 1 ms (it'll vary between 0.5-1.5 ms). Regardless, one should never count on the accuracy of this. Especially not for generating unique numbers. – Kyle Jan 07 '17 at 17:56
  • 1
    You are right, but usually it is not scalable, especially in case of end-users machines. – Yury Glushkov Jan 07 '17 at 17:57