it-swarm.com.de

Gibt es ein DateTime-Objekt mit hoher Auflösung (Mikrosekunde, Nanosekunde) für die CLR?

Ich habe ein Instrument, das Zeitstempel im Mikrosekundenbereich speichert, und ich muss diese Zeitstempel als Teil des Sammelns von Informationen vom Instrument speichern. Beachten Sie, dass ich not nicht brauchen muss, um Zeitstempel zu erzeugen ; Diese Zeitstempel werden vom Gerät selbst unter Verwendung eines Echtzeit-Betriebssystems mit hoher Auflösung vorab generiert. Das Parsen dieser Werte ist kein Problem - sie werden in einem Standardformat in UTC-Zeit gespeichert. Ursprünglich wollte ich die C # DateTime-Struktur verwenden kann nur Zeitstempel bis zu einer Millisekunden-Auflösung speichern.

Gibt es ein anderes Objekt, das mit .NET geliefert wird, oder eine übliche C # -Bibliothek, die Zeitstempel für die Auflösung von Mikro- und (idealerweise) Nanosekunden unterstützt, oder muss ich meine eigenen rollen?

24
Robert P

Möglicherweise können Sie DateTime trotzdem verwenden. Die Auflösung von DateTime.Ticks beträgt 100 Nanosekunden. Sie können die Markierungen mit DateTime.AddTicks setzen.

12
steinar

Betrachtet man die Antworten und die DateTime.Ticks-Eigenschaft, können aus den angegebenen Werten Mikrosekunden und Nanosekunden berechnet werden. Als Ergebnis habe ich diese Erweiterungsmethodenklasse dafür zusammengestellt. (Leider glaube ich nicht, dass ich sie unter bestimmten Voraussetzungen nutzen kann, aber andere Leute finden es vielleicht nützlich.)

/// <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));
   }
}

Sie können die Mikrosekunden oder Nanosekunden beim Erstellen jedoch noch nicht festlegen, sie können jedoch kurz danach hinzugefügt werden. Es gibt auch keine bessere Auflösung als das, was eine DateTime kann (z. B. 1/10 einer Mikrosekunde oder 100 Nanosekunden Auflösung).

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

Ich hoffe, das funktioniert für jemand anderen!

10
Robert P

Wenn ich wirklich mehr Genauigkeit als die von DateTime bereitgestellte Auflösung von 100 ns brauchte, würde ich in Betracht ziehen, eine Struktur zu erstellen, die eine DateTime und einen Ganzzahlwert enthält:

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 ...
}

Dann implementieren Sie, was erforderlich ist, zum Beispiel:

  • Vergleich (zuerst DateTime, dann Nanoseconds)
  • ToString() z.B. DateTime mit einer Genauigkeit von 100 ns formatieren und dann Nanosekunden anhängen.
  • Umstellung auf/von DateTime
  • Addieren/subtrahieren (benötigt möglicherweise eine ähnliche HiResTimeSpan) ... usw. ...
4
Joe

Wenn Sie etwas wollen, das für bedeutende Bruchteile einer Mikrosekunde gültig ist, dann Nein. Das, wonach Sie verlangen, existiert nicht als Teil der Standardbibliotheken. Aber warum brauchen Sie das? Es klingt, als ob Sie wirklich zwei Komponenten benötigen, eine Zeichenfolge (variable Länge, fast jeden denkbaren Wert für Hold) und eine DateTime für das UTC-Standardformat, das Sie nativ erhalten.

Die zweite Zeitmessung im Mikro-/Nanomaßstab ist nicht im "normalen" Berechnungsbereich, daher wird sie nicht in den "normalen" .NET-Bibliotheken bereitgestellt.

Was wirst du mit diesen Zeitstempeln machen? Wirst du sie vergleichen? Hinzufügen/Subtrahieren? Ich würde vorschlagen, Reflektor für das grundlegende DateTime-Objekt auszuführen (eigentlich denke ich, dass ich das auch schnell machen werde)

Zu Ihrem Vorteil ist hier die einfache Version der .NET Reflector-Zerlegung des Standard-DateTime-Objekts (und da die andere Antwort zum Zeitpunkt dieser Bearbeitung das TimeSpan-Element vorschlägt, auch das)

[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
        }
    }
}
2
jcolebrand

Ich kämpfe mit diesem Problem, indem ich ein Projekt habe, bei dem ich Zeitstempel mit Pikosekundenauflösung habe. Meine Quelldaten liegen im Format "time_t" vor, d. H. Seit Epoche + Pikosekunden + UTC-Offset.

Die beste Lösung, die ich gefunden habe, besteht darin, intern mit "Dezimalsekunden seit Epoch in UTC" zu arbeiten und DateTime nur als hübsches Druckobjekt zu verwenden, um das Gebietsschema/die Formatierung mit einer Auflösung von bis zu 1 s zu extrahieren und dann manuell zu bearbeiten Zeichenfolge für Sekundenbruchteile.

1
Chuu

Sie könnten wahrscheinlich auf verschiedene Weise Ihre eigenen Rollen.

1.) Erstellen Sie eine Struktur mit dem Feld System.Decimal als "Backing Store".

2.) Erstellen Sie eine Struktur mit System.Numerics.BigInteger als Hintergrund.

Umbrechen von Methoden zur Verwendung von System.DateTime für bequeme "Parts" (Jahr, Monat, Tag, ...) Fügen Sie Ihre eigenen Nanonsecond, Picosekunden, Femtosekunden hinzu. usw. Eigenschaften und Methoden.

FYI:

DateTime.MaxValue.Ticks: 3.155.378.975.999.999.999

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

BigInteger: beliebig groß!

0
Ben Stabile