是否有可用于CLR的高分辨率(微秒,纳秒)DateTime对象?

我有一个仪器存储时间戳微秒级别,我需要存储这些时间戳作为从仪器收集信息的一部分。 请注意,我不需要生成时间戳 ; 这些时间标记由仪器本身使用高分辨率实时操作系统预先生成。 解析这些值不是问题 – 它们使用UTC时间的标准格式存储。 本来我想用C#DateTime结构只能存储时间戳达毫秒级的分辨率。

是否有另一个.NET提供的对象或一个支持微观和(理想情况下)纳秒分辨率时间戳的通用C#库,或者我是否需要自己动手?

毕竟你可能能够使用DateTimeDateTime.Ticks的分辨率是100纳秒。 您可以使用DateTime.AddTicks设置刻度。

查看答案和DateTime.Ticks属性,可以从给定值计算微秒和纳秒。 结果,我把这个扩展方法类放在一起来做。 (遗憾的是,我不认为我可以在其他要求的情况下使用它,但其他人可能会发现它很有用。)

 ///  /// Extension methods for accessing Microseconds and Nanoseconds of a /// DateTime object. ///  public static class DateTimeExtensionMethods { ///  /// The number of ticks per microsecond. ///  public const int TicksPerMicrosecond = 10; ///  /// The number of ticks per Nanosecond. ///  public const int NanosecondsPerTick = 100; ///  /// Gets the microsecond fraction of a DateTime. ///  ///  ///  public static int Microseconds(this DateTime self) { return (int)Math.Floor( (self.Ticks % TimeSpan.TicksPerMillisecond ) / (double)TicksPerMicrosecond); } ///  /// Gets the Nanosecond fraction of a DateTime. Note that the DateTime /// object can only store nanoseconds at resolution of 100 nanoseconds. ///  /// The DateTime object. /// the number of Nanoseconds. public static int Nanoseconds(this DateTime self) { return (int)(self.Ticks % TimeSpan.TicksPerMillisecond % TicksPerMicrosecond) * NanosecondsPerTick; } ///  /// Adds a number of microseconds to this DateTime object. ///  /// The DateTime object. /// The number of milliseconds to add. public static DateTime AddMicroseconds(this DateTime self, int microseconds) { return self.AddTicks(microseconds * TicksPerMicrosecond); } ///  /// Adds a number of nanoseconds to this DateTime object. Note: this /// object only stores nanoseconds of resolutions of 100 seconds. /// Any nanoseconds passed in lower than that will be rounded using /// the default rounding algorithm in Math.Round(). ///  /// The DateTime object. /// The number of nanoseconds to add. public static DateTime AddNanoseconds(this DateTime self, int nanoseconds) { return self.AddTicks((int)Math.Round(nanoseconds / (double)NanosecondsPerTick)); } } 

这仍然不允许您在创建时设置微秒或纳秒,但可以在不久之后添加它们。 它也不能提供比DateTime更好的分辨率(例如,1/10微秒,即100纳秒分辨率。)

 DateTime time = new DateTime(year, month, day, hour, min, sec, msec); time = time.AddMicroseconds(microseconds); time = time.AddNanoseconds(nanoseconds); # note: rounds if not enough added 

这里希望这适用于其他人!

如果我真的需要比DateTime提供的100 ns分辨率更高的精度,我会考虑创建一个包含DateTime和整数值的结构:

 public struct HiResDateTime { public HiResDateTime(DateTime dateTime, int nanoseconds) { if (nanoSeconds < 0 || nanoSeconds > 99) throw new ArgumentOutOfRangeException(...); DateTime = dateTime; Nanoseconds = nanoseconds; } ... possibly other constructors including one that takes a timestamp parameter ... in the format provided by the instruments. public DateTime DateTime { get; private set; } public int Nanoseconds { get; private set; } ... implementation ... } 

然后实现所需的任何东西,例如:

  • 比较(首先是DateTime ,然后是Nanoseconds
  • ToString()例如将DateTime格式化为100 ns精度,然后附加纳秒。
  • 转换为DateTime或从DateTime转换
  • 加/减(可能需要类似的HiResTimeSpan )……等……

如果你想要的东西在很短的几分之一微秒内运行,那么你要求的东西并不是标准库的一部分,但是对于你所问的,你为什么需要这个呢? 听起来你真的需要两个组件,一个字符串(可变长度,保持几乎任何可以想象的值)和一个DateTime,用于UTC标准格式化的日期/时间,你本地。

微/纳秒级别的第二次计时不在“正常”计算范围内,因此在“普通”.NET库中没有提供。

你会对这些时间戳做些什么? 你会比较它们吗? 加/减它们? 我建议为基本的DateTime对象运行reflection器(实际上我觉得我也会很快这样做)

为了您的利益,这里是标准DateTime对象的.NET Reflector反汇编的简单版本(因为此编辑时的另一个答案建议使用TimeSpan元素)

 [Serializable] public struct DateTime : IComparable, IFormattable, IConvertible, ISerializable, IComparable, IEquatable { // Fields private ulong dateData; private const string DateDataField = "dateData"; private const int DatePartDay = 3; private const int DatePartDayOfYear = 1; private const int DatePartMonth = 2; private const int DatePartYear = 0; private const int DaysPer100Years = 0x8eac; private const int DaysPer400Years = 0x23ab1; private const int DaysPer4Years = 0x5b5; private const int DaysPerYear = 0x16d; private const int DaysTo10000 = 0x37b9db; private const int DaysTo1601 = 0x8eac4; private const int DaysTo1899 = 0xa9559; private static readonly int[] DaysToMonth365; private static readonly int[] DaysToMonth366; private const long DoubleDateOffset = 0x85103c0cb83c000L; private const long FileTimeOffset = 0x701ce1722770000L; private const ulong FlagsMask = 13835058055282163712L; private const ulong KindLocal = 9223372036854775808L; private const ulong KindLocalAmbiguousDst = 13835058055282163712L; private const int KindShift = 0x3e; private const ulong KindUnspecified = 0L; private const ulong KindUtc = 0x4000000000000000L; private const ulong LocalMask = 9223372036854775808L; private const long MaxMillis = 0x11efae44cb400L; internal const long MaxTicks = 0x2bca2875f4373fffL; public static readonly DateTime MaxValue; private const int MillisPerDay = 0x5265c00; private const int MillisPerHour = 0x36ee80; private const int MillisPerMinute = 0xea60; private const int MillisPerSecond = 0x3e8; internal const long MinTicks = 0L; public static readonly DateTime MinValue; private const double OADateMaxAsDouble = 2958466.0; private const double OADateMinAsDouble = -657435.0; private const long OADateMinAsTicks = 0x6efdddaec64000L; private const long TicksCeiling = 0x4000000000000000L; private const string TicksField = "ticks"; private const ulong TicksMask = 0x3fffffffffffffffL; private const long TicksPerDay = 0xc92a69c000L; private const long TicksPerHour = 0x861c46800L; private const long TicksPerMillisecond = 0x2710L; private const long TicksPerMinute = 0x23c34600L; private const long TicksPerSecond = 0x989680L; // Methods static DateTime(); public DateTime(long ticks); private DateTime(ulong dateData); public DateTime(long ticks, DateTimeKind kind); private DateTime(SerializationInfo info, StreamingContext context); public DateTime(int year, int month, int day); internal DateTime(long ticks, DateTimeKind kind, bool isAmbiguousDst); public DateTime(int year, int month, int day, Calendar calendar); public DateTime(int year, int month, int day, int hour, int minute, int second); public DateTime(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind); public DateTime(int year, int month, int day, int hour, int minute, int second, Calendar calendar); public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond); public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind); public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar); public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, Calendar calendar, DateTimeKind kind); public DateTime Add(TimeSpan value); private DateTime Add(double value, int scale); public DateTime AddDays(double value); public DateTime AddHours(double value); public DateTime AddMilliseconds(double value); public DateTime AddMinutes(double value); public DateTime AddMonths(int months); public DateTime AddSeconds(double value); public DateTime AddTicks(long value); public DateTime AddYears(int value); public static int Compare(DateTime t1, DateTime t2); public int CompareTo(DateTime value); public int CompareTo(object value); private static long DateToTicks(int year, int month, int day); public static int DaysInMonth(int year, int month); internal static long DoubleDateToTicks(double value); public bool Equals(DateTime value); public override bool Equals(object value); public static bool Equals(DateTime t1, DateTime t2); public static DateTime FromBinary(long dateData); internal static DateTime FromBinaryRaw(long dateData); public static DateTime FromFileTime(long fileTime); public static DateTime FromFileTimeUtc(long fileTime); public static DateTime FromOADate(double d); private int GetDatePart(int part); public string[] GetDateTimeFormats(); public string[] GetDateTimeFormats(char format); public string[] GetDateTimeFormats(IFormatProvider provider); public string[] GetDateTimeFormats(char format, IFormatProvider provider); public override int GetHashCode(); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern long GetSystemTimeAsFileTime(); public TypeCode GetTypeCode(); internal bool IsAmbiguousDaylightSavingTime(); public bool IsDaylightSavingTime(); public static bool IsLeapYear(int year); public static DateTime operator +(DateTime d, TimeSpan t); public static bool operator ==(DateTime d1, DateTime d2); public static bool operator >(DateTime t1, DateTime t2); public static bool operator >=(DateTime t1, DateTime t2); public static bool operator !=(DateTime d1, DateTime d2); public static bool operator <(DateTime t1, DateTime t2); public static bool operator <=(DateTime t1, DateTime t2); public static TimeSpan operator -(DateTime d1, DateTime d2); public static DateTime operator -(DateTime d, TimeSpan t); public static DateTime Parse(string s); public static DateTime Parse(string s, IFormatProvider provider); public static DateTime Parse(string s, IFormatProvider provider, DateTimeStyles styles); public static DateTime ParseExact(string s, string format, IFormatProvider provider); public static DateTime ParseExact(string s, string format, IFormatProvider provider, DateTimeStyles style); public static DateTime ParseExact(string s, string[] formats, IFormatProvider provider, DateTimeStyles style); public static DateTime SpecifyKind(DateTime value, DateTimeKind kind); public TimeSpan Subtract(DateTime value); public DateTime Subtract(TimeSpan value); bool IConvertible.ToBoolean(IFormatProvider provider); byte IConvertible.ToByte(IFormatProvider provider); char IConvertible.ToChar(IFormatProvider provider); DateTime IConvertible.ToDateTime(IFormatProvider provider); decimal IConvertible.ToDecimal(IFormatProvider provider); double IConvertible.ToDouble(IFormatProvider provider); short IConvertible.ToInt16(IFormatProvider provider); int IConvertible.ToInt32(IFormatProvider provider); long IConvertible.ToInt64(IFormatProvider provider); sbyte IConvertible.ToSByte(IFormatProvider provider); float IConvertible.ToSingle(IFormatProvider provider); object IConvertible.ToType(Type type, IFormatProvider provider); ushort IConvertible.ToUInt16(IFormatProvider provider); uint IConvertible.ToUInt32(IFormatProvider provider); ulong IConvertible.ToUInt64(IFormatProvider provider); [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)] void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context); private static double TicksToOADate(long value); private static long TimeToTicks(int hour, int minute, int second); public long ToBinary(); internal long ToBinaryRaw(); public long ToFileTime(); public long ToFileTimeUtc(); public DateTime ToLocalTime(); public string ToLongDateString(); public string ToLongTimeString(); public double ToOADate(); public string ToShortDateString(); public string ToShortTimeString(); public override string ToString(); public string ToString(IFormatProvider provider); public string ToString(string format); public string ToString(string format, IFormatProvider provider); public DateTime ToUniversalTime(); internal static bool TryCreate(int year, int month, int day, int hour, int minute, int second, int millisecond, out DateTime result); public static bool TryParse(string s, out DateTime result); public static bool TryParse(string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result); public static bool TryParseExact(string s, string[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result); public static bool TryParseExact(string s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result); // Properties public DateTime Date { get; } public int Day { get; } public DayOfWeek DayOfWeek { get; } public int DayOfYear { get; } public int Hour { get; } private ulong InternalKind { get; } private long InternalTicks { get; } public DateTimeKind Kind { get; } public int Millisecond { get; } public int Minute { get; } public int Month { get; } public static DateTime Now { get; } public int Second { get; } public long Ticks { get; } public TimeSpan TimeOfDay { get; } public static DateTime Today { get; } public static DateTime UtcNow { get; } public int Year { get; } } [Serializable, StructLayout(LayoutKind.Sequential), ComVisible(true)] public struct TimeSpan : IComparable, IComparable, IEquatable { public const long TicksPerMillisecond = 0x2710L; private const double MillisecondsPerTick = 0.0001; public const long TicksPerSecond = 0x989680L; private const double SecondsPerTick = 1E-07; public const long TicksPerMinute = 0x23c34600L; private const double MinutesPerTick = 1.6666666666666667E-09; public const long TicksPerHour = 0x861c46800L; private const double HoursPerTick = 2.7777777777777777E-11; public const long TicksPerDay = 0xc92a69c000L; private const double DaysPerTick = 1.1574074074074074E-12; private const int MillisPerSecond = 0x3e8; private const int MillisPerMinute = 0xea60; private const int MillisPerHour = 0x36ee80; private const int MillisPerDay = 0x5265c00; private const long MaxSeconds = 0xd6bf94d5e5L; private const long MinSeconds = -922337203685L; private const long MaxMilliSeconds = 0x346dc5d638865L; private const long MinMilliSeconds = -922337203685477L; public static readonly TimeSpan Zero; public static readonly TimeSpan MaxValue; public static readonly TimeSpan MinValue; internal long _ticks; public TimeSpan(long ticks); public TimeSpan(int hours, int minutes, int seconds); public TimeSpan(int days, int hours, int minutes, int seconds); public TimeSpan(int days, int hours, int minutes, int seconds, int milliseconds); public long Ticks { get; } public int Days { get; } public int Hours { get; } public int Milliseconds { get; } public int Minutes { get; } public int Seconds { get; } public double TotalDays { get; } public double TotalHours { get; } public double TotalMilliseconds { get; } public double TotalMinutes { get; } public double TotalSeconds { get; } public TimeSpan Add(TimeSpan ts); public static int Compare(TimeSpan t1, TimeSpan t2); public int CompareTo(object value); public int CompareTo(TimeSpan value); public static TimeSpan FromDays(double value); public TimeSpan Duration(); public override bool Equals(object value); public bool Equals(TimeSpan obj); public static bool Equals(TimeSpan t1, TimeSpan t2); public override int GetHashCode(); public static TimeSpan FromHours(double value); private static TimeSpan Interval(double value, int scale); public static TimeSpan FromMilliseconds(double value); public static TimeSpan FromMinutes(double value); public TimeSpan Negate(); public static TimeSpan Parse(string s); public static bool TryParse(string s, out TimeSpan result); public static TimeSpan FromSeconds(double value); public TimeSpan Subtract(TimeSpan ts); public static TimeSpan FromTicks(long value); internal static long TimeToTicks(int hour, int minute, int second); private string IntToString(int n, int digits); public override string ToString(); public static TimeSpan operator -(TimeSpan t); public static TimeSpan operator -(TimeSpan t1, TimeSpan t2); public static TimeSpan operator +(TimeSpan t); public static TimeSpan operator +(TimeSpan t1, TimeSpan t2); public static bool operator ==(TimeSpan t1, TimeSpan t2); public static bool operator !=(TimeSpan t1, TimeSpan t2); public static bool operator <(TimeSpan t1, TimeSpan t2); public static bool operator <=(TimeSpan t1, TimeSpan t2); public static bool operator >(TimeSpan t1, TimeSpan t2); public static bool operator >=(TimeSpan t1, TimeSpan t2); static TimeSpan(); // Nested Types [StructLayout(LayoutKind.Sequential)] private struct StringParser { private string str; private char ch; private int pos; private int len; private ParseError error; internal void NextChar(); internal char NextNonDigit(); internal long Parse(string s); internal bool TryParse(string s, out long value); internal bool ParseInt(int max, out int i); internal bool ParseTime(out long time); internal void SkipBlanks(); // Nested Types private enum ParseError { ArgumentNull = 4, Format = 1, Overflow = 2, OverflowHoursMinutesSeconds = 3 } } } 

我正在努力解决同样的问题,因为我有一个项目,我有皮秒分辨率的时间戳。 我的源数据采用“time_t”格式,即epoch + picoseconds + UTC Offset后的第二种格式。

我发现的最佳解决方案是使用“UTC时代以来的十进制秒数”作为我内部的时间格式,并且仅使用DateTime作为漂亮的打印对象,提取最高1 s分辨率的区域设置/格式,然后手动操作字符串包括小数秒。

你可以用各种方式自己动手。

1.)使用System.Decimal字段作为“后备存储”创建结构。

2.)使用System.Numerics.BigInteger作为支持创建结构。

包装方法使用System.DateTime方便“部件”(年,月,日,……)包括您自己的NanonsecondPicosecondFemtosecond等属性和方法。

供参考:

DateTime.MaxValue.Ticks:3,155,378,975,999,999,999

Decimal.MaxValue:79,228,162,514,264,337,593,543,950,335

BigInteger:任意大!