DateTimeオブジェクトの丸め


105

チャートアプリケーションの日付/時刻を最も近い間隔に丸めたい。次のような拡張メソッドシグネチャを使用して、任意のレベルの精度で丸めを実行できるようにします。

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

アイデアは、10分のタイムスパンを渡すと、最も近い10分の間隔に丸められるということです。私は実装を理解することができず、あなたの1人が以前に同様の何かを書いたり使用したりすることを望んでいます。

床、天井、または最も近い実装のいずれかで結構です。

何か案は?

編集:@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));
...

乾杯!


1
ここでの実装の一部も役立つ可能性があります。stackoverflow.com
Matt Hamilton


3
元のDateTimeKindを新しく作成された日付exに追加することを忘れないでください:new DateTime(ticks * span.Ticks、date.Kind);
AM

回答:


130

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

5
最近、DateTimeKindが保持されない問題に遭遇しました。各メソッドの最後の行に以下の微調整は、私の場合には役立った:return new DateTime(ticks * span.Ticks, date.Kind);
ピート

39

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

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

11

丸めが必要かどうかも明確にする必要があります。

  1. 間隔の開始、終了、または中間にある
    • startが最も簡単で、多くの場合予想されますが、最初の仕様を明確にする必要があります。
  2. 境界ケースを丸める方法。
    • 通常は、端ではなく中央に丸める場合にのみ問題になります。
    • 真ん中の丸めはバイアスのない答えの試みなので、本当にバイアスがないようにするには、バンカーズ丸めのようなものを技術的に半分丸める必要があります。

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

tvanfossonのソリューションは、1にリストされたすべてのケースをカバーしています。中間点の例は、上向きにバイアスされています。これが時間に関連する丸めの問題になるかどうかは疑問です。


3

ティックを使用し、それを使用して、値を除算、フロア/天井/ラウンド、および乗算して戻します。


-2

時間を天井値に切り上げるだけの場合

Console.WriteLine(DateTime.Now.ToString("M/d/yyyy hh:00:00"));

OPは、返されるオブジェクトとしてDateTimeを要求しました。
aj.toulan 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.