HighPrecisionTimeStamps 0.1.1-beta

This is a prerelease version of HighPrecisionTimeStamps.
There is a newer version of this package available.
See the version list below for details.
dotnet add package HighPrecisionTimeStamps --version 0.1.1-beta
NuGet\Install-Package HighPrecisionTimeStamps -Version 0.1.1-beta
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="HighPrecisionTimeStamps" Version="0.1.1-beta" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add HighPrecisionTimeStamps --version 0.1.1-beta
#r "nuget: HighPrecisionTimeStamps, 0.1.1-beta"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install HighPrecisionTimeStamps as a Cake Addin
#addin nuget:?package=HighPrecisionTimeStamps&version=0.1.1-beta&prerelease

// Install HighPrecisionTimeStamps as a Cake Tool
#tool nuget:?package=HighPrecisionTimeStamps&version=0.1.1-beta&prerelease

High Precision Timestamps

A utility providing convenient and appropriate alternatives to DateTime.Now.

It is well known that DateTime.Now is often used inappropriately. For example, it may be used together with TimeSpan to produce a task's timeout point or subtracted from another DateTime to calculate a duration. This can cause subtle bugs because DateTime is not monotonic: the system clock can change, making the result of the subtraction inaccurate -- potentially causing a premature timeout or an infinite loop. Yet, DateTime is an incredibly convenient and widely used value type in .NET code and is especially useful when printed in ISO-8601 format (with the "O" format specifier).

With the "O" specifier, you can resolution down to tenths of a microsecond, which is nice. Until you learn that the resolution of the system clock is usually more coarse than several milliseconds, making the additional decimal places misleading garbage values. For calculating durations (time between events), it is better to use a high-resolution and monotonic clock like that provided by System.Diagnostics.Stopwatch: on most computers it is far more accurate than DateTime.Now even though, seemingly paradoxically, on a few systems, its resolution is lower than that of DateTime. Also, unsurprisingly, Stopwatch does not provide values that correlate to times of day: while it is appropriate for calculating durations, it is inappropriate for timestamping against a readable date and time.

This library provides timestamps (both as DateTime and as analogous value types it defines) that use the Stopwatch (and your system's high performance event counter) as its clock, but returns values as DateTimes or an analog thereto so that these values can be used for a mixed purpose of timestamping and providing a meaningful way to calculate time elapsed between events.

It provides Monotonic timestamps and High Resolution timestamps.

High Resolution Timestamps

These timestamps are expressed as DateTime values and are derived from Stopwatch. They are calibrated (correlating a reference tick value of the Stopwatch to a reference time value of the system clock) on a per thread basis and have a calibration window that expires. These are suitable for logging times (in a way meaningful to humans) and can be used to measure the time elapsed between events on a single thread within one calibration window. A calibration window by default lasts for fifteen minutes. Eventually, there will be drift between the system clock and the Stopwatch, making re-calibration necessary. Nevertheless, for the resolution provided by Stopwatch, fifteen minutes should be a sufficient period for the intended use-case of these timestamps. Also, you can always manually trigger a calibration.

Monotonic Timestamps

These use the same source (Stopwatch) for their clock, but calibration happens exactly once per process and is the same across all threads. Thus, you can accurately log the time of events across multiple threads and have meaningful data to compare when events happen. Also, because calibration happens once these values are safe to use to calculate a timeout period, how long to perform a task, etc without the possibility that a change to the system clock can cause a bug. Like the High Resolution Timestamps, their fractional seconds are meaningful on every system I have tested. These are essentially dual-use values: they can be used to log timestamps and to calculate durations or time that your application should spend doing a task before quitting or timing out, etc. The monotonic clock provided returns a value type provided by this library rather than DateTime, though the value type is conveniently convertible into a DateTime. This choice was made because the Stopwatch's frequency can vary between systems and these stamps are intended to be used for calculating and measuring durations in addition to logging: it was desirable not to need to calculate a conversion to and from DateTime/TimeSpan scale when obtaining a stamp or performing a duration calculation. For a similar reason, there is a Duration value type that is to the monotonic stamp what System.TimeSpan is to DateTime: a duration value with a matching frequency.

Example Code

An example code project (available at ExampleCode) is available and used to provide a tour of the functionality and its recommended use-cases. All of the example code below can be found therein. For more elaboration, please consult the full Readme.md in the source repository as it is too long to be displayed on NuGet.

Status of Testing / Project

See the release notes and issues 12 and 13 for version for a fix involving serialization and deserialization of portable monotonic timestamps.

Please inform me of any bugs found on the issues page or via email: I intend to fix bugs. I consider this project more or less feature complete and do not imagine any additional extensive features being added by me. If you would like to add features, I am happy to review any pull-request or issue.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on HighPrecisionTimeStamps:

Package Downloads

Synchronization Library and Static Analysis Tool for C# 8 DotNetVault is a library and static code analysis tool that makes managing shared mutable state in multi-threaded applications more manageable and less error prone. It also provides a common abstraction over several commonly used synchronization mechanisms, allowing you to change from one underlying type to another (such as from lock free synchronization to mutex/monitor lock based) without needing to refactor your code. Where errors do still occur, they are easier to locate and identify. The project description (a detailed design document) can be read here: https://github.com/cpsusie/DotNetVault/blob/master/DotNetVault_Description_v1.0.pdf. A quick start guide for installation (Windows, Vs 2019+) can be found here: https://github.com/cpsusie/DotNetVault/blob/v0.2.5.x/QuickStart_Install_VS2019_Windows.md. A quick start guide for installation (Tested on Amazon Linux, Rider 2019.3.1+) can be found here: https://github.com/cpsusie/DotNetVault/blob/v0.2.5.x/Quick_Start_Install_Rider_Amazon_Linux.md. A guided tour / quick start guide for this project's functionality can be found here: https://github.com/cpsusie/DotNetVault/blob/v0.2.5.x/Quick_Start_Functionality_Tour.md

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated 236 2/1/2022 27,058 10/1/2021 366 9/19/2021 371 9/4/2021 462 8/21/2021
1.0.0 444 8/13/2021
0.1.1-beta 325 8/5/2021
0.1.0 505 12/13/2020 307 12/6/2020 291 11/27/2020
0.0.4-beta 304 11/18/2020
0.0.3-beta 360 11/15/2020
0.0.2-alpha 281 11/14/2020
0.0.1-alpha 386 1/25/2020

This beta release fixes a major problem with PortableMonotonic stamps being serialized and deserialized on different systems.  Apparently, the min value of DateTime.ToUniversalTime can differ from system to system.  Moreover, it does not seem always to be an offset around the non-daylight savings time utc offset of the current timezone: indeed, I have seen different platforms on the same timezone vary by an odd number of minutes.  I am unsure why this is.  The result was that a portable monotonic stamp serialized on one platform, then deserialized on another would be interpreted differently leading to a discrepancy in the values by sometimes bizarre amounts.  This was resolved by adding a string field to the PortableMonotonic stamp that is set during the OnSerializing callback.  When the stamp is deserialized, the string --if present-- is parsed into a portable monotonic stamp and the internal fields are adjusted accordingly.  If you were only serializing/deserializing these on similar systems in the same timezone, this fix should not affect you.  Going forward, serialized portable stamps will have both the nanoseconds offset field and the stringigied field.  After this beta is tested as used in software I maintain, I will release a non-beta version.