2

Google カレンダーと Outlook がすべての時間エントリが 30 分離れている時間選択を処理する方法をエミュレートしようとしています。私は、1 つのことを除いて、ほぼすべての機能テストを機能テストで使用しています。私の問題は、現在の日付を常に 30 分に丸める方法がわからないことです。

私は次のコードを使用しています:

protected DateTime GetStartTime()
{
    var spanTicks = TimeSpan.FromMinutes(30).Ticks;
    var ticks = (Time.Now.Ticks + spanTicks - 1) / spanTicks;

    return new DateTime(ticks * spanTicks);
}

これは、午前 12 時 (午前 12 時 30 分に返されると予想される場合) と午前 8 時 56 分 (午前 9 時に返されると予想される場合) を除いて、ほとんどの場合に機能します。

どうすればこれを修正できますか?

4

5 に答える 5

2

なぜダニを気にするのですか?:30次のように、時間を正確にまたはに強制することができます:00

protected DateTime GetStartTime() {
    var now = DateTime.Now;
    int addHours;
    int minute;
    if (now.Minute >= 30) {
        addHour = 1;
        minute = 0;
    } else {
        addHour = 0;
        minute = 30;
    }
    return new DateTime(now.Year, now.Month, now.Day, hour, minute, 0).AddHours(addHours);
}
于 2012-01-18T14:05:00.947 に答える
2

編集:元のバージョンは機能しませんでした!古いMonoの大げさな実装から来ました!

新しいバージョン:

protected DateTime GetStartTime()
{
    DateTime dt=DateTime.Now;
    if (dt.Minute<30) 
    {
        dt=dt.AddMinutes(30-dt.Minute);
    }
    else 
    {
        dt=dt.AddMinutes(60-dt.Minute);
    }

    //dt now has the upcoming half-hour border

    //...

}
于 2012-01-18T14:05:50.977 に答える
1

次のようなことを試しましたか?同様の方法を使用して、次の1時間、1分、1日などに切り上げることに成功しました...

private static readonly long _ticksIn30Mins = TimeSpan.FromMinutes(30).Ticks;

protected DateTime GetRoundedTime(DateTime inputTime) 
{     
    long currentTicks = inputTime.Ticks;
    return new DateTime(currentTicks.RoundUp(_ticksIn30Mins)); 
} 

public static class ExtensionMethods 
{     
    public static long RoundUp(this long i, long toTicks)     
    {         
        return (long)(Math.Round(i / (double)toTicks, 
                  MidpointRounding.AwayFromZero)) * toTicks; 
    } 
} 

これは、この前の質問からRoundOffメソッドを取ります。MidpointRoundingMode.AwayFromZeroを使用して、常に切り上げるように変更する必要があります。

最後に、12:00amが12:30 amになるという特定のケースに対処するために、丸め前と丸め後の値が同じであるかどうかを確認し、同じである場合は、ティックの切り上げ量を増やします(30分など)。

var currentTime = DateTime.Now;
var rounded = GetRoundedTime(currentTime); 
if (rounded == currentTime) 
{ 
    rounded = new DateTime(rounded.Ticks + _ticksIn30Mins); 
} 

この原則を示すテスト済みのコンソールアプリケーションについては、以下を参照してください。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        private static readonly long _ticksIn30Mins = TimeSpan.FromMinutes(30).Ticks; 

        static void Main(string[] args)
        {
            WriteDateString(new DateTime(2012, 01, 18, 09, 45, 11, 152));
            WriteDateString(new DateTime(2012, 01, 18, 12, 15, 11, 999));
            WriteDateString(new DateTime(2012, 01, 18, 12, 00, 00, 000));

            Console.ReadLine();
        }

        private static void WriteDateString(DateTime dateTime)
        {
            Console.WriteLine("Before: {0}, After: {1}", dateTime, GetRoundedTime(dateTime));
        }

        private static DateTime GetRoundedTime(DateTime inputTime)
        {
            long currentTicks = inputTime.Ticks; 
            var rounded = new DateTime(currentTicks.RoundUp(_ticksIn30Mins));
            if (rounded == inputTime)
            {
                rounded = new DateTime(rounded.Ticks + _ticksIn30Mins);
            }
            return rounded;
        } 
    }

    public static class ExtensionMethods
    {
        public static long RoundUp(this long i, long toTicks)
        {
            return (long)(Math.Round(i / (double)toTicks, MidpointRounding.AwayFromZero)) * toTicks;
        }
    }  
}

出力:

日付の切り上げの例からのコンソール出力

よろしくお願いします、

于 2012-01-18T14:07:06.577 に答える
1

.NETにすべての特殊なケースを処理させてください。

var now = DateTime.Now;
DateTime result = now.AddMinutes(now.Minute >= 30 ? (60-now.Minute) : (30-now.Minute));
result = result.AddSeconds(-1* result.Second); // To reset seconds to 0
result = result.AddMilliseconds(-1* result.Millisecond); // To reset milliseconds to 0
于 2012-01-18T14:12:59.007 に答える