Подтвердить что ты не робот

Существует ли доступный для CLR объект DateTime с высоким разрешением (микросекунда, наносекунда)?

У меня есть инструмент, который хранит временные метки микросекундного уровня, и мне нужно сохранить эти временные метки как часть сбора информации из инструмента. Обратите внимание, что мне не нужно генерировать временные метки; эти метки времени предварительно генерируются самим прибором, используя операционную систему реального времени с высоким разрешением. Разбор этих значений не является проблемой - они хранятся в стандартном формате в формате UTC. Изначально я хотел использовать Структура С# DateTime, которая может хранить только отметки времени до миллисекундного разрешения.

Есть ли еще один объект, поставляемый с .NET, или с общей библиотекой С#, которая поддерживает микро- и (в идеале) временные метки времени в наносекундах, или мне придется сворачивать свои собственные?

4b9b3361

Ответ 1

Возможно, вы сможете использовать DateTime. DateTime.Ticks 'составляет 100 наносекунд. Вы можете установить тики с помощью DateTime.AddTicks.

Ответ 2

Рассматривая ответы и свойство DateTime.Ticks, можно вычислить Microseconds и Nanoseconds из данных значений. В результате я собрал этот класс метода расширения для этого. (К сожалению, я не думаю, что смогу использовать его с учетом некоторых других требований, но другие люди могут оказаться полезными.)

/// <summary>
/// Extension methods for accessing Microseconds and Nanoseconds of a
/// DateTime object.
/// </summary>
public static class DateTimeExtensionMethods
{
   /// <summary>
   /// The number of ticks per microsecond.
   /// </summary>
   public const int TicksPerMicrosecond = 10;
   /// <summary>
   /// The number of ticks per Nanosecond.
   /// </summary>
   public const int NanosecondsPerTick = 100;

   /// <summary>
   /// Gets the microsecond fraction of a DateTime.
   /// </summary>
   /// <param name="self"></param>
   /// <returns></returns>
   public static int Microseconds(this DateTime self)
   {
      return (int)Math.Floor(
         (self.Ticks 
         % TimeSpan.TicksPerMillisecond )
         / (double)TicksPerMicrosecond);
   }
   /// <summary>
   /// Gets the Nanosecond fraction of a DateTime.  Note that the DateTime
   /// object can only store nanoseconds at resolution of 100 nanoseconds.
   /// </summary>
   /// <param name="self">The DateTime object.</param>
   /// <returns>the number of Nanoseconds.</returns>
   public static int Nanoseconds(this DateTime self)
   {
      return (int)(self.Ticks % TimeSpan.TicksPerMillisecond % TicksPerMicrosecond)
         * NanosecondsPerTick;
   }
   /// <summary>
   /// Adds a number of microseconds to this DateTime object.
   /// </summary>
   /// <param name="self">The DateTime object.</param>
   /// <param name="microseconds">The number of milliseconds to add.</param>
   public static DateTime AddMicroseconds(this DateTime self, int microseconds)
   {
      return self.AddTicks(microseconds * TicksPerMicrosecond);
   }
   /// <summary>
   /// 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().
   /// </summary>
   /// <param name="self">The DateTime object.</param>
   /// <param name="nanoseconds">The number of nanoseconds to add.</param>
   public static DateTime AddNanoseconds(this DateTime self, int nanoseconds)
   {
      return self.AddTicks((int)Math.Round(nanoseconds / (double)NanosecondsPerTick));
   }
}

Это все равно не позволит вам устанавливать Microseconds или Nanoseconds при создании, но они могут быть добавлены вскоре после этого. Он также не дает разрешения лучше, чем то, что может использовать 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

Здесь надеюсь, что это сработает для кого-то еще!

Ответ 3

Если мне действительно нужна была больше точности, чем разрешение 100 ns, предоставляемое DateTime, я бы подумал о создании структуры, содержащей 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
  • Добавить/вычесть (может потребоваться аналогичный HiResTimeSpan) ... и т.д....

Ответ 4

Если вы хотите что-то, что работает на значительных долях микросекунды, то Нет. Вещь, о которой вы просите, не существует как часть стандартных библиотек, но для чего вы спрашиваете, зачем вам это нужно?? Похоже, вам действительно нужны два компонента, строка (переменная длина, удержание почти любого мыслимого значения) и DateTime для стандартной даты/времени в формате UTC, которые вы получаете изначально.

Микро/наномасштабная шкала времени не находится в "нормальном" диапазоне вычислений, поэтому она не предоставляется в "обычных" библиотеках .NET.

Что вы будете делать с этими отметками времени? Вы будете сравнивать их? Добавление/вычитание? Я бы предложил запустить отражатель для базового объекта DateTime (на самом деле, я думаю, я тоже сделаю это очень быстро)

Для вашей выгоды здесь простая версия демонстрации .NET Reflector стандартного объекта DateTime (и поскольку другой ответ во время этого изменения предлагает также элемент TimeSpan)

[Serializable]
public struct DateTime : IComparable, IFormattable, IConvertible, ISerializable, IComparable<DateTime>, IEquatable<DateTime>
{
    // 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<TimeSpan>, IEquatable<TimeSpan>
{
    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
        }
    }
}

Ответ 5

Я борюсь с этой же проблемой, потому что у меня есть проект, где у меня есть метки времени пикосекундного разрешения. Мои исходные данные находятся в формате "time_t", то есть в секундах с эпохи + пикосекунды + UTC Offset.

Лучшее решение, которое я нашел, - это работать с "десятичными секундами с эпохи в UTC" в качестве внутреннего формата времени и использовать только DateTime в качестве красивого объекта печати, чтобы извлечь локаль/форматирование с разрешением до 1 затем вручную манипулируйте строкой, чтобы включить дробные секунды.

Ответ 6

Вероятно, вы можете использовать свой собственный способ различными способами.

1.) Создайте структуру, используя поле System.Decimal в качестве "хранилища резервных копий".

2.) Создайте структуру, используя System.Numerics.BigInteger в качестве поддержки.

Оберните методы, чтобы использовать System.DateTime для удобных "частей" (год, месяц, день,...) Включите собственные Nanonsecond, Picosecond, Femtosecond и т.д., Свойства и методы.

FYI:

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

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

BigInteger: произвольно большой!