Introduce DataBase,Asp.net,JavaScript,Xml,Html,Css,Sql,Php,ASP.NET Controls,AJAX,Tools,HTML,CSS,JavaScript,Open Source Project,WPF,.Net Framework,Linq
Top Recommended Hosting

DateTimePrecise class in C#

by the3factory 4/11/2008 1:35:00 AM

The .NET Framework provides two ways to sample the current time: DateTime.Now and Diagnostics.Stopwatch.GetTimestamp(). DateTime.Now is accurate—it tells you the current time—but it only has 16 millisecond precision. Stopwatch.GetTimestamp() is as precise as your CPU instruction counter and can distinguish between nanoseconds, but it is not accurate at all—it contains no information about what the absolute time is.

The DateTime struct is just a wrapper for a signed 64 bit integer which represents the number of 100-nanosecond periods since midnight of January 1st of the year one. DateTime, therefore, is capable of representing a time with 100 nanosecond precision.

DateTimePrecise.Now returns a DateTime struct that supplements DateTime.Now with information from the Stopwatch, giving you a current time that has 16 millisecond accuracy and 100 nanosecond precision. It will also smooth out discontinuities in the system clock time, like when your computer synchronizes with an internet time server.

Features of DateTimePrecise

  • Continuous and strictly increasing, even when the system clock time is changed, so long as the system clock time is changed by less than the resynchronization period.
  • Thread-safe and lock-free. Uses internal immutable states to ensure consistency. Atomic operations are not even needed, because DateTimePrecise is tolerant of read-write instruction re-ordering and memory caching.
  • Will asymptotically approach the system clock time, but damped, so that it is stable and doesn't accelerate suddenly.

The following table shows how much time it takes, in seconds, to call each time sampling method on Windows Server 2003 x64 Standard Edition, .NET Framework 2.0, Intel Xeon Woodcrest. There are a few interesting surprises in this table.

Stopwatch.GetTimestamp() 0.000000184
DateTime.Now 0.000000226
DateTime.UtcNow 0.000000010
DateTime.UtcNow.ToLocalTime() 0.000000221
DateTimePrecise.Now 0.000000482
DateTimePrecise.UtcNow 0.000000248
DateTimePrecise.UtcNow.ToLocalTime() 0.000000455

Using the code

DateTimePrecise is as easy to use as DateTime.Now, except that DateTimePrecise.Now is an instance method instead of a static method, so you have to first instantiate a DateTimePrecise.

DateTimePrecise dateTimePrecise = new DateTimePrecise(10);
DateTime timeNow = dateTimePrecise.Now;

 

Here is the source code, in C#.

Collapse
using System;
using System.Diagnostics;
namespace JamesBrock
{
/// 
/// DateTimePrecise provides a way to get a DateTime that exhibits the relative precision of
/// System.Diagnostics.Stopwatch, and the absolute accuracy of DateTime.Now.
/// 
/// 
///

/// Each successive call to Now or UtcNow will be asymptotically closer to the true time.
/// 

///

/// Creates no background threads. 
/// 

///

/// Accuracy is about 16 milliseconds, the same as DateTime.Now.
/// 

///

/// Precision is 100 nanoseconds, the maximum precision for DateTime.
/// 

///

/// Continuous and strictly increasing, even when the system clock time is changed, so long as the system clock time is changed by less than the resynchronization period.
/// 

///

/// Thread-safe and lock-free. Uses internal immutable states to ensure consistency. 
/// 

///

/// Error < (0.032 seconds / resynchronization period) + (Stopwatch error * resynchronization period)
/// 

/// 
public class DateTimePrecise
{
/// 
/// Creates a new instance of DateTimePrecise.
/// 
/// 
/// A large value of synchronizePeriodSeconds may cause arithmetic overthrow exceptions to be thrown. A small value may cause the time to be unstable. A good value is 10.
/// 
/// 

public DateTimePrecise(long synchronizePeriodSeconds)
{
Stopwatch = Stopwatch.StartNew();
this.Stopwatch.Start();
DateTime t = DateTime.UtcNow;
_immutable = new DateTimePreciseSafeImmutable(t, t, Stopwatch.ElapsedTicks, Stopwatch.Frequency);
_synchronizePeriodSeconds = synchronizePeriodSeconds;
_synchronizePeriodStopwatchTicks = synchronizePeriodSeconds * Stopwatch.Frequency;
_synchronizePeriodClockTicks = synchronizePeriodSeconds * _clockTickFrequency;
}
/// 
/// Returns the current date and time, just like DateTime.UtcNow.
/// 
public DateTime UtcNow
{
get
{
long s = this.Stopwatch.ElapsedTicks;
DateTimePreciseSafeImmutable immutable = _immutable;
if (s < immutable._s_observed + _synchronizePeriodStopwatchTicks)
{
checked
{
return immutable._t_base.AddTicks(((s - immutable._s_observed) * _clockTickFrequency) / (immutable._stopWatchFrequency));
}
}
else
{
DateTime t = DateTime.UtcNow;
DateTime _t_base_new = immutable._t_base.AddTicks(((s - immutable._s_observed) * _clockTickFrequency) / (immutable._stopWatchFrequency));
long measuredStopwatchFrequency = ((s - immutable._s_observed) * _clockTickFrequency) / (t.Ticks - immutable._t_observed.Ticks);
DateTimePreciseSafeImmutable immutableNew;
if (s - immutable._s_observed < _synchronizePeriodStopwatchTicks)
{
immutableNew = new DateTimePreciseSafeImmutable(
t,
_t_base_new,
s,
(measuredStopwatchFrequency +
(
(_synchronizePeriodSeconds * measuredStopwatchFrequency * _clockTickFrequency)
/
(t.Ticks + _synchronizePeriodClockTicks - _t_base_new.Ticks)
)
) / 2
);
}
else
{
immutableNew = new DateTimePreciseSafeImmutable(
t,
_t_base_new,
s,
measuredStopwatchFrequency
);
}
_immutable = immutableNew;
return _t_base_new;
}
}
}
/// 
/// Returns the current date and time, just like DateTime.Now.
/// 
public DateTime Now
{
get
{
return this.UtcNow.ToLocalTime();
}
}
/// 
/// The internal System.Diagnostics.Stopwatch used by this instance.
/// 
public Stopwatch Stopwatch;
private long _synchronizePeriodStopwatchTicks;
private long _synchronizePeriodSeconds;
private long _synchronizePeriodClockTicks;
private const long _clockTickFrequency = 10000000;
private DateTimePreciseSafeImmutable _immutable;
}
internal sealed class DateTimePreciseSafeImmutable
{
internal DateTimePreciseSafeImmutable(DateTime t_observed, DateTime t_base, long s_observed, long stopWatchFrequency)
{
_t_observed = t_observed;
_t_base = t_base;
_s_observed = s_observed;
_stopWatchFrequency = stopWatchFrequency;
}
internal readonly DateTime _t_observed;
internal readonly DateTime _t_base;
internal readonly long _s_observed;
internal readonly long _stopWatchFrequency;
}
}

 

Related posts

Sign up for PayPal and start accepting credit card payments instantly.


Powered by BlogEngine.NET 1.2.0.0