web-dev-qa-db-ja.com

DateTimeオブジェクトの丸め

日付と時刻をチャート作成アプリケーションの最も近い間隔に丸めたい。次のような拡張メソッドのシグネチャが欲しいので、丸めをあらゆるレベルの精度で実現できます。

static DateTime Round(this DateTime date, TimeSpan span);

考えは、10分のタイムスパンでパスすると、最も近い10分の間隔に丸められるということです。実装について頭を悩ますことはできませんし、あなたの誰かが以前に似たようなものを書いたり使ったりすることを望んでいます。

床、天井、または最も近い実装のいずれでも問題ないと思います。

何か案は?

編集:@tvanfossonと@ShuggyCoUkのおかげで、実装は次のようになります。

public static class DateExtensions {
    public static DateTime Round(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;
        return new DateTime(ticks * span.Ticks);
    }
    public static DateTime Floor(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks / span.Ticks);
        return new DateTime(ticks * span.Ticks);
    }
    public static DateTime Ceil(this DateTime date, TimeSpan span) {
        long ticks = (date.Ticks + span.Ticks - 1) / span.Ticks;
        return new DateTime(ticks * span.Ticks);
    }
}

そして次のように呼ばれます:

DateTime nearestHour = DateTime.Now.Round(new TimeSpan(1,0,0));
DateTime minuteCeiling = DateTime.Now.Ceil(new TimeSpan(0,1,0));
DateTime weekFloor = DateTime.Now.Floor(new TimeSpan(7,0,0,0));
...

乾杯!

100
grenade

long ticks = date.Ticks / span.Ticks;

return new DateTime( ticks * span.Ticks );

ラウンド(中間点で切り上げ)

long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;

return new DateTime( ticks * span.Ticks );

天井

long ticks = (date.Ticks + span.Ticks - 1)/ span.Ticks;

return new DateTime( ticks * span.Ticks );
121
tvanfosson

これにより、指定された間隔に丸めることができます。また、目盛りを分割してから乗算するよりもわずかに高速です。

public static class DateTimeExtensions
{
  public static DateTime Floor(this DateTime dateTime, TimeSpan interval)
  {
    return dateTime.AddTicks(-(dateTime.Ticks % interval.Ticks));
  }

  public static DateTime Ceiling(this DateTime dateTime, TimeSpan interval)
  {
    var overflow = dateTime.Ticks % interval.Ticks;

    return overflow == 0 ? dateTime : dateTime.AddTicks(interval.Ticks - overflow);
  }

  public static DateTime Round(this DateTime dateTime, TimeSpan interval)
  {
    var halfIntervalTicks = (interval.Ticks + 1) >> 1;

    return dateTime.AddTicks(halfIntervalTicks - ((dateTime.Ticks + halfIntervalTicks) % interval.Ticks));
  }
}
35
aj.toulan

四捨五入する場合も明確にする必要があります。

  1. 間隔の開始点、終了点、または中間点になります
    • 開始は最も簡単で、多くの場合予想されますが、最初の仕様を明確にする必要があります。
  2. 境界ケースを丸める方法。
    • 通常、最後ではなく中央に丸めている場合にのみ問題になります。
    • 真ん中への丸めは、バイアスのない答えを求める試みなので、 Bankers Rounding のようなものを使用する必要があります。

本当に最初の点だけを気にすることは非常に可能性が高いですが、これらの「単純な」質問では、実際の世界で使用すると、結果として生じる振る舞いが広範囲に及ぶ可能性があります(多くの場合、ゼロに近い間隔で)

tvanfossonのソリューションは、1にリストされているすべてのケースをカバーします。中間点の例は、上方に偏っています。これが時間関連の丸めで問題になることは疑わしいです。

10
ShuggyCoUk

Ticksを使用し、それを使用して値をフロア、セル、丸め、乗算します。

2
Lucero