C#
DateTime
precision
.NET
programming

C DateTime.Now precision

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

DateTime.Now in C# has a resolution of approximately 10-15 milliseconds on most Windows systems, despite the DateTime struct storing values with 100-nanosecond precision (ticks). This means two consecutive calls to DateTime.Now can return the same value even if real time has passed. For high-precision timing, use Stopwatch or DateTime.UtcNow (which avoids timezone conversion overhead).

DateTime Resolution vs Precision

The DateTime struct can represent time down to 100-nanosecond intervals (ticks), but DateTime.Now does not update that frequently:

csharp
1// These may all print the same time
2for (int i = 0; i < 5; i++)
3{
4    Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fffffff"));
5}
6// Output:
7// 14:30:25.1234560
8// 14:30:25.1234560
9// 14:30:25.1234560
10// 14:30:25.1234560
11// 14:30:25.1234560

The system clock updates at intervals determined by the OS timer resolution — typically 15.625ms on Windows (64 Hz).

Key Terminology

TermDefinition
ResolutionHow often the clock updates (~15ms for DateTime.Now)
PrecisionSmallest representable unit (100ns / 1 tick for DateTime)
AccuracyHow close the value is to the true time (depends on NTP sync)

DateTime.Now has high precision (100ns ticks) but low resolution (15ms updates). It is like a ruler marked in millimeters but only read with a magnifying glass every centimeter.

Demonstrating the Resolution Limit

csharp
1var timestamps = new List<DateTime>();
2
3for (int i = 0; i < 10000; i++)
4    timestamps.Add(DateTime.Now);
5
6var distinct = timestamps.Distinct().Count();
7Console.WriteLine($"10000 calls, {distinct} unique values");
8// Typical output: 10000 calls, ~5-20 unique values

Only a handful of distinct values appear because the clock does not update between calls.

DateTime.Now vs DateTime.UtcNow

DateTime.Now converts from UTC to local time on every call, adding overhead:

csharp
1var sw = Stopwatch.StartNew();
2for (int i = 0; i < 1_000_000; i++)
3    _ = DateTime.Now;
4sw.Stop();
5Console.WriteLine($"DateTime.Now: {sw.ElapsedMilliseconds}ms");
6
7sw.Restart();
8for (int i = 0; i < 1_000_000; i++)
9    _ = DateTime.UtcNow;
10sw.Stop();
11Console.WriteLine($"DateTime.UtcNow: {sw.ElapsedMilliseconds}ms");
12
13// DateTime.Now:    ~120ms
14// DateTime.UtcNow: ~30ms  (3-4x faster)

DateTime.UtcNow is faster because it skips timezone conversion. Both have the same ~15ms resolution.

High-Precision Timing with Stopwatch

For measuring elapsed time with microsecond or nanosecond precision, use Stopwatch:

csharp
1using System.Diagnostics;
2
3var sw = Stopwatch.StartNew();
4
5// Operation to measure
6Thread.Sleep(1);
7
8sw.Stop();
9
10Console.WriteLine($"Elapsed: {sw.Elapsed.TotalMilliseconds:F4}ms");
11Console.WriteLine($"Ticks: {sw.ElapsedTicks}");
12Console.WriteLine($"Frequency: {Stopwatch.Frequency} ticks/sec");
13Console.WriteLine($"High resolution: {Stopwatch.IsHighResolution}");
14
15// Elapsed: 1.2345ms
16// Frequency: 10000000 ticks/sec (on most modern systems)
17// High resolution: True

Stopwatch uses the hardware performance counter (QueryPerformanceCounter on Windows), which has nanosecond resolution.

Increasing System Timer Resolution

On Windows, you can increase the timer resolution to ~1ms using timeBeginPeriod:

csharp
1using System.Runtime.InteropServices;
2
3[DllImport("winmm.dll")]
4static extern uint timeBeginPeriod(uint period);
5
6[DllImport("winmm.dll")]
7static extern uint timeEndPeriod(uint period);
8
9// Increase resolution to 1ms
10timeBeginPeriod(1);
11
12// Now DateTime.Now updates approximately every 1ms
13var timestamps = new List<DateTime>();
14for (int i = 0; i < 10000; i++)
15    timestamps.Add(DateTime.Now);
16
17var distinct = timestamps.Distinct().Count();
18Console.WriteLine($"Distinct: {distinct}");  // Many more unique values
19
20// Restore default resolution
21timeEndPeriod(1);

Warning: Increasing timer resolution increases power consumption system-wide. Always restore the default when done.

.NET 8+ Improvements

Starting with .NET 8, TimeProvider offers a testable abstraction:

csharp
1// Production
2var provider = TimeProvider.System;
3DateTimeOffset now = provider.GetUtcNow();
4long timestamp = provider.GetTimestamp();
5
6// Testing with a fake clock
7var fakeProvider = new FakeTimeProvider(new DateTimeOffset(2024, 1, 1, 0, 0, 0, TimeSpan.Zero));
8DateTimeOffset fakeNow = fakeProvider.GetUtcNow();
9fakeProvider.Advance(TimeSpan.FromHours(1));  // Move time forward

Generating Unique Timestamps

If you need monotonically increasing timestamps (e.g., for ordering events):

csharp
1class UniqueTimestamp
2{
3    private long _lastTicks;
4
5    public DateTime GetUniqueNow()
6    {
7        long ticks;
8        do
9        {
10            ticks = DateTime.UtcNow.Ticks;
11            long last = Interlocked.Read(ref _lastTicks);
12            if (ticks <= last)
13                ticks = last + 1;
14        } while (Interlocked.CompareExchange(ref _lastTicks, ticks, Interlocked.Read(ref _lastTicks)) != Interlocked.Read(ref _lastTicks));
15
16        return new DateTime(ticks, DateTimeKind.Utc);
17    }
18}

Or simply use a counter suffix or Guid.NewGuid() for uniqueness.

Common Pitfalls

  • Using DateTime.Now for performance measurement: DateTime.Now has 15ms resolution, making it useless for sub-millisecond benchmarks. Use Stopwatch instead.
  • Assuming unique timestamps: Two events within the same 15ms window get the same DateTime.Now value. Do not use timestamps as unique identifiers.
  • DateTime.Now in tight loops: DateTime.Now performs a timezone conversion on every call. In hot loops, use DateTime.UtcNow and convert to local time once at display time.
  • Cross-platform differences: Linux and macOS have higher timer resolution (~1ms) than Windows (~15ms). Code that works on Linux may behave differently on Windows.
  • Thread.Sleep precision: Thread.Sleep(1) actually sleeps for ~15ms on Windows due to the same timer resolution. Use SpinWait or Stopwatch for sub-millisecond delays.

Summary

  • DateTime.Now has ~15ms resolution on Windows despite storing 100ns ticks
  • Use Stopwatch for high-precision elapsed time measurement
  • Use DateTime.UtcNow instead of DateTime.Now for better performance (no timezone conversion)
  • Do not rely on DateTime.Now for unique timestamps or sub-millisecond accuracy
  • On .NET 8+, use TimeProvider for testable time abstractions

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.