2009-04-20 6 views
18

DateTimeを最も近い5秒に丸めます。これは私が現在やっている方法ですが、より簡潔な方法があれば疑問に思っていましたか?C#では、DateTimeを最も近い5秒に丸める良い方法がありますか?

DateTime now = DateTime.Now; 
int second = 0; 

// round to nearest 5 second mark 
if (now.Second % 5 > 2.5) 
{ 
    // round up 
    second = now.Second + (5 - (now.Second % 5)); 
} 
else 
{ 
    // round down 
    second = now.Second - (now.Second % 5); 
} 

DateTime rounded = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, second); 

しかし、彼らははなくラウンド時間を切り捨てる、私はthesetwo前の質問を見つけたことに注意してください。

答えて

29

のDateTimeのダニ数は、100ナノ秒間隔を表しますが、このような最寄り50000000-ティック間隔に丸めたラウンド最寄り5秒にすることができますので:

DateTime now = DateTime.Now; 
    DateTime rounded = new DateTime(((now.Ticks + 25000000)/50000000) * 50000000); 
より簡潔だ

ではなく、必然的に良い。コードの明快さよりも簡潔さとスピードを好むかどうかによって異なります。あなたは間違いなく理解しやすいです。

+4

これは、59秒で最も近い5に丸められて60になります。これは、DateTimeコンストラクタに '秒'パラメータとして渡すことはできません。この方法で、あなたはその落とし穴を避けます。 –

+0

ええ、それは良い点です - 私は自分のコードでその問題を逃しました... – Damovisa

+1

自分自身の答えを批判する潜在的な落とし穴の1つは、DateTimeがうるう秒をどのように考慮しているかわかりません。ティックカウントは、0001年1月1日の午前0時00分00秒から測定されます。その時以降の閏秒の数とDateTimeがそれらを考慮するかどうかによって、結果のSeconds値は5の倍数ではないことがあります。 – JayMcClellan

2

前述のように、切り捨てはかなり簡単です。だから、ちょうど2.5秒を追加し、次に切り捨てる。

+0

私が2.5秒を追加し、最も近い5秒に切り捨てて2.5秒を引くと、2.5秒、7.5秒、12.5秒などになります。 – Damovisa

+0

したがって、最後のステップを外してください秒)は動作するはずです... – Damovisa

1

私はおそらくラウンド法くくり出すだろうが、私は、より良い方法を考えることはできません。

static int Round(int n, int r) 
{ 
    if ((n % r) <= r/2) 
    { 
     return n - (n % r); 
    } 
    return n + (r - (n % r)); 
} 

をまた、%は、その2.5と比較することは少し奇妙として私を打つ、int型を返しますそれが正しいとしても。私は> = 3を使用します。

+0

ええ、私はあなたが2.5とそれを比較することで何を意味するか知っています - 少し不快であると感じました。あなたが言うように、それは正しいですが、それは意図が何であるかをより明確にします。 2.5は明らかに5の半分であり、3は適合しないようである。 – Damovisa

+0

'((n +(r >> 1))/ r)* r'(round midpoints up)または'((n + r >> 1 - 1)/ r)* r '(中点を丸める)。 'r'が奇数であることを知っていれば、私は奇数' r'に対して同じことをするので、最初のものを使うだけです。このアプローチでは、1つの除算(vs 3)しか使用せず、関数に比べて分岐を使用しません。 –

1

私はC#と石鹸のバーの違いを認識できませんでした(よく、この回答を書いたときにはできませんでした。 )しかし、あなたはより多くの簡潔解決策を探しているなら、私はただの関数で全体を置く - 簡単なコールよりも、あなたのコード内でより簡潔になることがあります少し機能を言ったために:

DateTime rounded = roundTo5Secs (DateTime.Now); 

次に、関数に必要なものを置いて、それがどのように動作するかをドキュメント化することができます(これらはすべて整数演算であると仮定します)。

secBase = now.Second/5; 
secExtra = now.Second % 5; 
if (secExtra > 2) { 
    return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 
     secBase + 5); 
} 
return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 
    secBase); 

secBaseが60になると、C#DateTimeオブジェクトが分を浮き上がらせるほどスマートでない(そして、分が60になると時間がかかるなどの場合を除き)いくつかの余分なチェックが必要な場合もあります。

+0

ええ、公正なポイント。私はこれをやっていきます - 私はちょうど質問で明確にしていませんでした。 – Damovisa

+0

あなたのためのバスタイムは難しいです;-) –

+0

いいです、@Gordon、私は最近、C#について公正なことをもっと知っていますが、bathtime _is_はかなり難しいです。それは私の部分で調整の欠如よりも若い子供たちを持つことともっと関係があります: – paxdiablo

1

これについて(いくつかの回答を組み合わせて)どうですか?私はそれが意味をよく伝え、AddSecondsのために優雅に(次の分に丸められる)端の場合を扱うべきだと思う。ジェイによって示されるように

// truncate to multiple of 5 
int second = 5 * (int) (now.Second/5); 
DateTime dt = new DateTime(..., second); 

// round-up if necessary 
if (now.Second % 5 > 2.5) 
{ 
    dt = dt.AddSeconds(5); 
} 

Ticksアプローチは、より簡潔であるが、少し読みにくくすることができます。この方法を使用する場合は、少なくともTimeSpan.TicksPerSecondを参照してください。

+0

-1:元の時間に1秒の小数が含まれている場合、動作しません。 – Joe

+0

あなたは正しいです。私は前の編集にロールバックしました。その編集はその事件を処理する上でより明確でした。 –

+0

その後-1を削除しました! – Joe

46

(復活のために申し訳ありませんが、私はそれは古いです認識し、質問に答え - ちょうどGoogleのためにいくつかの余分なコードを追加)

私はJayMcClellan's answerで始まったが、その後、私はそれがより一般的になりたかった、に丸めます任意の間隔(わずか5秒ではない)。だから私はチックにMath.Roundを使用し、任意の間隔を取ることができる拡張メソッドに入れて、丸めロジック(バンカーの丸めとゼロから離れる)を変更するオプションを提供するものにJayのメソッドを残してしまいました。

public static TimeSpan Round(this TimeSpan time, TimeSpan roundingInterval, MidpointRounding roundingType) { 
     return new TimeSpan(
      Convert.ToInt64(Math.Round(
       time.Ticks/(decimal)roundingInterval.Ticks, 
       roundingType 
      )) * roundingInterval.Ticks 
     ); 
    } 

    public static TimeSpan Round(this TimeSpan time, TimeSpan roundingInterval) { 
     return Round(time, roundingInterval, MidpointRounding.ToEven); 
    } 

    public static DateTime Round(this DateTime datetime, TimeSpan roundingInterval) { 
     return new DateTime((datetime - DateTime.MinValue).Round(roundingInterval).Ticks); 
    } 

それは裸の効率化のための任意の賞を獲得しませんが、私はそれが読みやすく、直感的に使用見つける:私はこれは同様に他の誰かに便利です、ここの場合で投稿しています。使用例:

new DateTime(2010, 11, 4, 10, 28, 27).Round(TimeSpan.FromMinutes(1)); // rounds to 2010.11.04 10:28:00 
new DateTime(2010, 11, 4, 13, 28, 27).Round(TimeSpan.FromDays(1)); // rounds to 2010.11.05 00:00 
new TimeSpan(0, 2, 26).Round(TimeSpan.FromSeconds(5)); // rounds to 00:02:25 
new TimeSpan(3, 34, 0).Round(TimeSpan.FromMinutes(37); // rounds to 03:42:00...for all your round-to-37-minute needs 
+0

ありがとうございます - 私が探していたものです! – chris

+0

これは素晴らしいコードです* nearest * DateTime'に丸めるために、しかし、私はまた、* up *を 'roundingInterval'の倍数に丸める能力が必要です。' DateTime'オーバーロードを修正して、 'MidpointRounding'を取って – HappyNomad

+0

@HappyNomad 'MidpointRounding'は、値が実際の中間点にあるときにのみ出現します。常に丸めたい場合は、オーバーロードや変更を追加する必要があります'Math.Round'の代わりに' Math.Ceiling'を使用し、 'roundingType'を完全に無視する最初の関数 –

0

技術的には、ほんの数秒で奇数の間隔に正しく丸めることはできません。

2、4、6、8、10 <は - あなたは間隔で時間を「配布」され、ジッタが低い場合、切り捨てがたくさん より扱いやすいであれば何の問題

ません。

ミリ秒を渡して500mSのマークで丸めることができれば、奇数 秒まで奇数にすることができ、ジッタ・ウェイの影響をスラッシュしたり完全に除去することができます。

関連する問題