web-dev-qa-db-fra.com

Existe-t-il un objet DateTime haute résolution (microseconde, nanoseconde) disponible pour le CLR?

J'ai un instrument qui stocke des horodatages au niveau de la microseconde et je dois stocker ces horodatages dans le cadre de la collecte d'informations à partir de l'instrument. Notez que j’ai pas besoin de générer des horodatages ; Ces horodatages sont pré-générés par l'instrument lui-même à l'aide d'un système d'exploitation temps réel haute résolution. L'analyse de ces valeurs n'est pas un problème - elles sont stockées en utilisant un format standard en heure UTC. À l'origine, je souhaitais utiliser la structure La structure C # DateTime ne peut stocker que des horodatages avec une résolution de l'ordre de la milliseconde.

Existe-t-il un autre objet fourni avec .NET ou une bibliothèque commune C # qui prend en charge les horodatages de résolution en microsecondes et (idéalement) nanosecondes, ou vais-je devoir rouler le mien?

24
Robert P

Vous pourrez peut-être utiliser DateTime après tout. La résolution de DateTime.Ticks 'est de 100 nanosecondes. Vous pouvez définir les ticks avec DateTime.AddTicks.

12
steinar

En examinant les réponses et la propriété DateTime.Ticks, il est possible de calculer des microsecondes et des nanosecondes à partir des valeurs données. En conséquence, j'ai mis en place cette classe de méthode d'extension pour le faire. (Malheureusement, je ne pense pas que je serai capable de l'utiliser compte tenu de certaines autres exigences, mais d'autres personnes pourraient le trouver utile.)

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

Cela ne vous permet toujours pas de définir les microsecondes ou les nanosecondes lors de la création, mais elles peuvent être ajoutées peu de temps après. Cela ne donne pas non plus une résolution meilleure que ce qu’un DateTime peut obtenir (par exemple, une résolution de 1/10 de microseconde, autrement dit une résolution de 100 nanosecondes).

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

En espérant que cela fonctionne pour quelqu'un d'autre!

10
Robert P

Si j'avais vraiment besoin de plus de précision que la résolution de 100 ns fournie par DateTime, je envisagerais de créer une structure contenant une DateTime et une valeur entière:

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

Puis mettez en œuvre ce qui est nécessaire, par exemple:

  • Comparaison (DateTime d'abord, puis Nanoseconds)
  • ToString() p. ex. Formatez DateTime avec une précision de 100 ns, puis ajoutez des nanosecondes.
  • Conversion vers/de DateTime
  • Ajouter/soustraire (peut nécessiter une HiResTimeSpan similaire) ... etc. ...
4
Joe

Si vous voulez quelque chose qui fonctionne avec une fraction de fraction de microseconde, alors Non. Ce que vous demandez n'existe pas dans les bibliothèques standard, mais pourquoi, pourquoi avez-vous besoin de cela? On dirait que vous avez vraiment besoin de deux composants, une chaîne (longueur variable, presque toute valeur concevable) et un DateTime pour la date/heure formatée au format UTC que vous obtenez en mode natif.

Le deuxième chronométrage à l’échelle micro/nano n’est pas dans la plage de calculs "normale", il n’est donc pas fourni dans les bibliothèques .NET "normales".

Que ferez-vous avec ces horodatages? Voulez-vous les comparer? En les ajoutant/soustrayant? Je suggérerais d'utiliser un réflecteur pour l'objet de base DateTime (en fait, je pense que je vais le faire très vite aussi)

Pour votre bénéfice, voici la version simple du désassemblage .NET Reflector de l'objet DateTime standard (et puisque l'autre réponse au moment de cette modification suggère l'élément TimeSpan, cela aussi)

[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

Je suis aux prises avec le même problème, en ce sens que j'ai un projet pour lequel j'ai des horodatages en résolution picoseconde. Mes données source sont au format "time_t", c'est-à-dire secondes depuis Epoch + picoseconds + UTC Offset.

La meilleure solution que j’ai trouvée est de travailler en interne avec "secondes décimales depuis Epoch en UTC" et d’utiliser uniquement DateTime comme bel objet d’impression pour extraire les paramètres régionaux/formatage jusqu’à une résolution de 1 s, puis de manipuler manuellement chaîne pour inclure des fractions de secondes.

1
Chuu

Vous pourriez probablement rouler le vôtre de différentes façons.

1.) Créez une structure en utilisant System.Decimal champ comme "magasin de sauvegarde".

2.) Créez une structure en utilisant System.Numerics.BigInteger en tant que sauvegarde.

Méthodes d'habillage à utiliser System.DateTime pour des "parties" pratiques (année, mois, jour, ...) Indiquez votre propre Nanonsecond , Picoseconde , Femtoseconde , etc., propriétés et méthodes.

Pour votre information:

DateTime.MaxValue.Ticks: 3.155.378.975.999.999.999

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

BigInteger: arbitrairement grand!

0
Ben Stabile