日時-次の火曜日を取得


154

次の火曜日の日付を取得するにはどうすればよいですか?

PHPでは、と同じくらい簡単strtotime('next tuesday');です。

どうすれば.NETで同様のことを達成できますか


15
ASP.NETはWebテクノロジーのセットです。C#は言語です。プレーン.NETの観点からこれを考える必要があります。さて、「次の火曜日」-それは「今日の後の最初の火曜日」ですか?月曜日で、誰かが「次の火曜日にお会いしましょう」と言った場合、1日ではなく8日ということになると思います。今日が火曜日の場合はどうでしょうか。何時に必要ですか?
Jon Skeet、2011年

今日が火曜日の場合、次の火曜日の日付を知りたいですか?または今日は月曜日ですが、月曜日から2番目の火曜日を検索しますか?
ファイアパンダ2011

特定の日までの最も近い火曜日。
brenjt 2011年

2
@brenjtL:そして、すでに火曜日なら?
Jon Skeet

すでに火曜日の場合は、その同じ日
brenjt '06 / 06/14

回答:


371

コメントで述べたように、「次の火曜日」という言葉にはさまざまな意味がありますが、このコードでは「次の火曜日、または火曜日の場合は今日」となります。

DateTime today = DateTime.Today;
// The (... + 7) % 7 ensures we end up with a value in the range [0, 6]
int daysUntilTuesday = ((int) DayOfWeek.Tuesday - (int) today.DayOfWeek + 7) % 7;
DateTime nextTuesday = today.AddDays(daysUntilTuesday);

すでに火曜日である場合に「1週間の時間」を指定したい場合は、以下を使用できます。

// This finds the next Monday (or today if it's Monday) and then adds a day... so the
// result is in the range [1-7]
int daysUntilTuesday = (((int) DayOfWeek.Monday - (int) today.DayOfWeek + 7) % 7) + 1;

...または元の式を使用できますが、明日から:

DateTime tomorrow = DateTime.Today.AddDays(1);
// The (... + 7) % 7 ensures we end up with a value in the range [0, 6]
int daysUntilTuesday = ((int) DayOfWeek.Tuesday - (int) tomorrow.DayOfWeek + 7) % 7;
DateTime nextTuesday = tomorrow.AddDays(daysUntilTuesday);

編集:これを素敵で用途の広いものにするために:

public static DateTime GetNextWeekday(DateTime start, DayOfWeek day)
{
    // The (... + 7) % 7 ensures we end up with a value in the range [0, 6]
    int daysToAdd = ((int) day - (int) start.DayOfWeek + 7) % 7;
    return start.AddDays(daysToAdd);
}

したがって、「今日または今後6日間」の値を取得するには:

DateTime nextTuesday = GetNextWeekday(DateTime.Today, DayOfWeek.Tuesday);

「今日を除く次の火曜日」の値を取得するには:

DateTime nextTuesday = GetNextWeekday(DateTime.Today.AddDays(1), DayOfWeek.Tuesday);

わあ、次の火曜日までn日目を取得する方法を考えていたところ、ニースの例を使用して回答を更新しました。ありがとう
brenjt

正しい答えを選ぶのは大変でした。しかし、あなたのものが最も用途が広いようで、理解しやすくしました。助けてくれてありがとう。
brenjt

1
@brenjt:実は、曜日を指定できるので、Svenの方が用途が広いと思いますが、それはあなたの呼び出しです:)(私は、より一般的なバージョンを提供するために私のものを編集しました。)
Jon Skeet

1
+7)%7解決策は、しかしかなりいいです。私がそれを使用しなかった理由は、それがマイクロ最適化のビットであり、誤解するのがあまりにも簡単である(そしていくつかの読みやすさを犠牲にする)ためですが、もちろん私見です。
スベン

単体テスト:[T​​estMethod] public void ShouldGetNextSaturday(){var now = DateTime.Now; var test = GetNextWeekday(DateTime.Today、DayOfWeek.Saturday); Assert.IsTrue(now.Day <test.Day、 "予想される月の日はここにありません。"); Assert.IsTrue(test.DayOfWeek == DayOfWeek.Saturday、 "予想される曜日がここにありません。"); Assert.IsTrue((test.Day-now.Day)<7、 "予想される日間隔はここにありません。"); }
rasx 2012年

67

これでうまくいくはずです:

static DateTime GetNextWeekday(DayOfWeek day)
{
    DateTime result = DateTime.Now.AddDays(1);
    while( result.DayOfWeek != day )
        result = result.AddDays(1);
    return result;
}

今日が火曜日(これはhaです)の場合、これは今日または次の火曜日に返されますか?
brenjt 2011年

3
これは次の火曜日に戻ります。今日それを返したい場合.AddDays(1)は、最初の行からを削除するだけで、DateTime.Nowそれ自体もチェックされます。
スベン

7

この問題には冗長ではなく、より巧妙でエレガントな解決策がありますが、次のC#関数は多くの状況で非常にうまく機能します。

/// <summary>
/// Find the closest weekday to the given date
/// </summary>
/// <param name="includeStartDate">if the supplied date is on the specified day of the week, return that date or continue to the next date</param>
/// <param name="searchForward">search forward or backward from the supplied date. if a null parameter is given, the closest weekday (ie in either direction) is returned</param>
public static DateTime ClosestWeekDay(this DateTime date, DayOfWeek weekday, bool includeStartDate = true, bool? searchForward=true)
{
    if (!searchForward.HasValue && !includeStartDate) 
    {
        throw new ArgumentException("if searching in both directions, start date must be a valid result");
    }
    var day = date.DayOfWeek;
    int add = ((int)weekday - (int)day);
    if (searchForward.HasValue)
    {
        if (add < 0 && searchForward.Value)
        {
            add += 7;
        }
        else if (add > 0 && !searchForward.Value)
        {
            add -= 7;
        }
        else if (add == 0 && !includeStartDate)
        {
            add = searchForward.Value ? 7 : -7;
        }
    }
    else if (add < -3) 
    {
        add += 7; 
    }
    else if (add > 3)
    {
        add -= 7;
    }
    return date.AddDays(add);
}

1
DateTimeの拡張機能として実装される唯一の答え。他のソリューションはすべて機能しますが、それを拡張メソッドとして使用すると、最も使いやすいコードが生成されます。
ライアンマッカーサー2018年

5
DateTime nextTuesday = DateTime.Today.AddDays(((int)DateTime.Today.DayOfWeek - (int)DayOfWeek.Tuesday) + 7);

今日が月曜日である場合、指定した答えは明日ではなく火曜日から1週間になります。
2014年

5

@ジョンスキート良い答え。

前日:

private DateTime GetPrevWeekday(DateTime start, DayOfWeek day) {
    // The (... - 7) % 7 ensures we end up with a value in the range [0, 6]
    int daysToRemove = ((int) day - (int) start.DayOfWeek - 7) % 7;
    return start.AddDays(daysToRemove);
}

ありがとう!!


このソリューションには、モジュロ演算子に渡される負の数が含まれることに注意してください。モジュロ演算子についてのWikipediaの記事は、と言っている「またはNのいずれかが負の場合、ナイーブダウン定義ブレークやプログラミング言語は、これらの値が定義されている方法が異なります。」これはおそらくC#で動作しますが、同じ結果を得るために、数学的により「固体」ソリューションを交換することになりますDayOfWeek。このような値int daysToSubtract = -(((int)dateTime.DayOfWeek - (int)day + 7) % 7);
アンドレ

4
DateTime nexttuesday=DateTime.Today.AddDays(1);

while(nexttuesday.DayOfWeek!=DayOfWeek.Tuesday)
   nexttuesday = nexttuesday.AddDays(1);

3

現在の日付を含めたり除外したりするための非常に単純なサンプルで、日付と曜日を指定します。

public static class DateTimeExtensions
{
    /// <summary>
    /// Gets the next date.
    /// </summary>
    /// <param name="date">The date to inspected.</param>
    /// <param name="dayOfWeek">The day of week you want to get.</param>
    /// <param name="exclDate">if set to <c>true</c> the current date will be excluded and include next occurrence.</param>
    /// <returns></returns>
    public static DateTime GetNextDate(this DateTime date, DayOfWeek dayOfWeek, bool exclDate = true)
    {
        //note: first we need to check if the date wants to move back by date - Today, + diff might move it forward or backwards to Today
        //eg: date - Today = 0 - 1 = -1, so have to move it forward
        var diff = dayOfWeek - date.DayOfWeek;
        var ddiff = date.Date.Subtract(DateTime.Today).Days + diff;

        //note: ddiff < 0 : date calculates to past, so move forward, even if the date is really old, it will just move 7 days from date passed in
        //note: ddiff >= (exclDate ? 6 : 7) && diff < 0 : date is into the future, so calculated future weekday, based on date
        if (ddiff < 0 || ddiff >= (exclDate ? 6 : 7) && diff < 0)
            diff += 7; 

        //note: now we can get safe values between 0 - 6, especially if past dates is being used
        diff = diff % 7;

        //note: if diff is 0 and we are excluding the date passed, we will add 7 days, eg: 1 week
        diff += diff == 0 & exclDate ? 7 : 0;

        return date.AddDays(diff);
    }
}

いくつかのテストケース

[TestMethod]
    public void TestNextDate()
    {
        var date = new DateTime(2013, 7, 15);
        var start = date;
        //testing same month - forwardOnly
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Tuesday)); //16
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Wednesday)); //17
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Thursday)); //18
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Friday)); //19
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Saturday)); //20
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Sunday)); //21
        Assert.AreEqual(start.AddDays(1), date.GetNextDate(DayOfWeek.Monday)); //22

        //testing same month - include date
        Assert.AreEqual(start = date, date.GetNextDate(DayOfWeek.Monday, false)); //15
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Tuesday, false)); //16
        Assert.AreEqual(start.AddDays(1), date.GetNextDate(DayOfWeek.Wednesday, false)); //17

        //testing month change - forwardOnly
        date = new DateTime(2013, 7, 29);
        start = date;
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Tuesday)); //30
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Wednesday)); //31
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Thursday)); //2013/09/01-month increased
        Assert.AreEqual(start.AddDays(1), date.GetNextDate(DayOfWeek.Friday)); //02

        //testing year change
        date = new DateTime(2013, 12, 30);
        start = date;
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Tuesday)); //31
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Wednesday)); //2014/01/01 - year increased
        Assert.AreEqual(start = start.AddDays(1), date.GetNextDate(DayOfWeek.Thursday)); //02
    }

いくつかの広範なテストを行った後、元の回答からさらに変更を加えました。これにより、使用された日付、過去、現在、未来に基づいて翌日が安全に計算されます。これまでのすべての例は優れていますが、特定の条件下では失敗しました。計算を行っていることに対して追加のコメントを付けることができるように、それを1行のステートメントにはしませんでした。Jon Skeetによる前向きなケースは素晴らしかったですが、日付から1日戻らなければならないケースでしたが、それでも今日よりも大きく、今日または昨日に移動した場合はどうなりますか...これで解決しました。
AJB

1

それも拡張機能である可能性があり、それはすべて依存します

public static class DateTimeExtensions
{
    public static IEnumerable<DateTime> Next(this DateTime date, DayOfWeek day)
    {
        // This loop feels expensive and useless, but the point is IEnumerable
        while(true)
        {
            if (date.DayOfWeek == day)
            {
                yield return date;
            }
            date = date.AddDays(1);
        }
    }
}

使用法

    var today = DateTime.Today;
    foreach(var monday in today.Next(DayOfWeek.Monday))
    {
        Console.WriteLine(monday);
        Console.ReadKey();
    }

0

ワンライナーフレーバーになりました-何らかのメカニズムにパラメーターとして渡す必要がある場合。

DateTime.Now.AddDays(((int)yourDate.DayOfWeek - (int)DateTime.Now.DayOfWeek + 7) % 7).Day

この特定のケースでは:

DateTime.Now.AddDays(((int)DayOfWeek.Tuesday - (int)DateTime.Now.DayOfWeek + 7) % 7).Day

-5

Objective Cバージョン:

+(NSInteger) daysUntilNextWeekday: (NSDate*)startDate withTargetWeekday: (NSInteger) targetWeekday
{
    NSInteger startWeekday = [[NSCalendar currentCalendar] component:NSCalendarUnitWeekday fromDate:startDate];
    return (targetWeekday - startWeekday + 7) % 7;
}

4
クールな答えですが、元の質問は.NETについて尋ねました。
アダム・デイビス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.