web-dev-qa-db-ja.com

CLRで使用できる高解像度(マイクロ秒、ナノ秒)のDateTimeオブジェクトはありますか?

マイクロ秒レベルのタイムスタンプを保存する計測器があり、計測器からの情報収集の一部としてそれらのタイムスタンプを保存する必要があります。 しないでくださいタイムスタンプを生成する ;これらのタイムスタンプは、高解像度のリアルタイムオペレーティングシステムを使用して、機器自体によって事前に生成されます。これらの値を解析することは問題ではありません。これらの値は、標準形式を使用してUTC時間で格納されます。元々私は C#DateTime構造 を使用したかったのですが、タイムスタンプはミリ秒単位の解像度でしか保存できません。

.NETまたはマイクロ秒と(理想的には)ナノ秒の解像度のタイムスタンプをサポートする一般的なC#ライブラリで提供される別のオブジェクトはありますか、それとも自分でロールする必要がありますか?

26
Robert P

結局、DateTimeが使えるかもしれません。 DateTime.Ticks 'の分解能は100ナノ秒です。ティックはDateTime.AddTicksで設定できます。

13
steinar

回答とDateTime.Ticksプロパティを見ると、指定された値からマイクロ秒とナノ秒を計算することができます。その結果、この拡張メソッドクラスをまとめて実行しました。 (残念ながら、他の要件があれば使用できないと思いますが、他の人が便利だと思うかもしれません。)

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

これでも、作成時にマイクロ秒またはナノ秒を設定することはできませんが、すぐ後に追加できます。また、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

これが他の誰かのために働くことを願っています!

11
Robert P

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との変換
  • 加算/減算(同様のHiResTimeSpanが必要な場合があります)...など...
4
Joe

マイクロ秒のかなりの部分で動作するものが必要な場合は、いいえ。求めているものが標準ライブラリの一部として存在しませんが、求めているもののために、なぜこれが必要なのでしょうか。文字列(可変長、保持のほとんどすべての考えられる値)とネイティブで取得するUTC標準形式の日付/時刻のDateTimeの2つのコンポーネントが本当に必要なようです。

マイクロ/ナノスケールの第2タイムキーピングは「通常」の計算範囲にないため、「通常」の.NETライブラリでは提供されません。

これらのタイムスタンプで何をしますか?それらを比較しますか?それらを加算/減算しますか?基本的なDateTimeオブジェクトのリフレクターを実行することをお勧めします(実際には、これもすぐに実行すると思います)

あなたの利益のために、これは標準のDateTimeオブジェクトの.NET Reflector逆アセンブリの単純なバージョンです(そしてこの編集時の他の回答は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
        }
    }
}
2
jcolebrand

私はピコ秒の解像度のタイムスタンプを持っているプロジェクトを持っているという点で、これと同じ問題に苦労しています。私のソースデータは「time_t」形式です。つまり、エポック+ピコ秒+ UTCオフセットからの秒数です。

私が見つけた最良の解決策は、内部的には「UTCでのエポックからの小数秒」を時間形式として使用し、きれいな印刷オブジェクトとしてDateTimeのみを使用して、1秒の解像度までロケール/形式を抽出し、手動で操作することです。小数秒を含める文字列。

1
Chuu

あなたはおそらくあなた自身をさまざまな方法で転がすことができます。

1.)System.Decimalフィールドを「バッキングストア」として使用して構造を作成します。

2.)バッキングとしてSystem.Numerics.BigIntegerを使用して構造を作成します。

使用するラップ方法System.DateTime便利な「パーツ」(年、月、日、...)独自のNanonsecondPicosecondFemtosecondなど、プロパティとメソッド。

FYI:

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

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

BigInteger:任意に大きい!

0
Ben Stabile