Datetime - Dapatkan selasa berikutnya


154

Bagaimana saya bisa mendapatkan tanggal Selasa depan?

Di PHP, sesederhana itu strtotime('next tuesday');.

Bagaimana saya bisa mencapai sesuatu yang serupa di .NET


15
ASP.NET adalah seperangkat teknologi web. C # adalah bahasa. Anda benar-benar perlu memikirkan hal ini dalam hal .NET. Sekarang, untuk "Selasa depan" - apakah itu "Selasa pertama setelah hari ini"? Jika itu hari Senin dan seseorang berkata "sampai jumpa hari Selasa depan" saya akan berharap itu berarti waktu 8 hari daripada 1. Bagaimana kalau hari ini adalah hari Selasa? Jam berapa hari yang Anda butuhkan?
Jon Skeet

Jika hari ini selasa, Anda ingin mencari tahu kapan hari selasa berikutnya? Atau hari ini hari Senin, Anda ingin mencari selasa kedua dari hari Senin?
API Panda

Selasa terdekat menuju hari yang paling khusus.
brenjt

2
@ brenjtL: Dan jika sudah hari Selasa?
Jon Skeet

Jika sudah hari Selasa maka hari yang sama
brenjt

Jawaban:


371

Seperti yang saya sebutkan di komentar, ada berbagai hal yang dapat Anda maksud dengan "Selasa depan", tetapi kode ini memberi Anda "Selasa berikutnya untuk terjadi, atau hari ini jika sudah Selasa":

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

Jika Anda ingin memberi "waktu seminggu" jika sudah Selasa, Anda dapat menggunakan:

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

... atau Anda dapat menggunakan rumus asli, tetapi mulai besok:

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

EDIT: Hanya untuk menjadikan ini menyenangkan dan serbaguna:

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

Jadi untuk mendapatkan nilai untuk "hari ini atau dalam 6 hari ke depan":

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

Untuk mendapatkan nilai "Selasa berikutnya tidak termasuk hari ini":

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

Wow, saya hanya ingin tahu bagaimana saya bisa mendapatkan hari ke-til sampai selasa berikutnya dan Anda kemudian memperbarui jawaban Anda dengan contoh yang bagus. Terima kasih
brenjt

Sulit untuk memilih jawaban yang benar. Tapi milikmu tampaknya paling fleksibel dan kau membuatnya mudah dimengerti. Terima kasih atas bantuannya.
brenjt

1
@ brenjt: Sebenarnya saya akan mengatakan bahwa Sven lebih fleksibel, karena Anda dapat menentukan hari dalam seminggu, tapi ini panggilan Anda :) (Saya sekarang telah mengedit milik saya untuk memberikan versi yang lebih umum.)
Jon Skeet

1
The +7)%7solusi adalah cukup bagus meskipun. Meskipun alasan saya tidak menggunakannya adalah karena itu sedikit optimasi mikro dan terlalu mudah salah (serta mengorbankan beberapa keterbacaan), tentu saja.
Sven

Unit test: [TestMethod] public void ShouldGetNextSaturday () {var now = DateTime.Now; var test = GetNextWeekday (DateTime.Today, DayOfWeek.Saturday); Assert.IsTrue (now.Day <test.Day, "Hari bulan yang diharapkan tidak ada di sini."); Assert.IsTrue (test.DayOfWeek == DayOfWeek.Saturday, "Hari minggu yang diharapkan tidak ada di sini."); Assert.IsTrue ((test.Day - now.Day) <7, "Interval hari yang diharapkan tidak ada di sini."); }
rasx

67

Ini harus melakukan trik:

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

Respons yang bagus, jika hari ini adalah Selasa (yang mana ha) akankah ini kembali hari ini atau selasa berikutnya
brenjt

3
Ini akan kembali Selasa depan. Jika Anda ingin mengembalikannya hari ini, hapus saja .AddDays(1)dari baris pertama, dengan begitu ia akan memeriksa DateTime.Nowsendiri.
Sven

7

Ada solusi yang kurang verbose dan lebih pintar / elegan untuk masalah ini, tetapi fungsi C # berikut bekerja dengan sangat baik untuk sejumlah situasi.

/// <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
Satu-satunya jawaban yang menerapkan ekstensi ke DateTime. Sementara solusi lain semuanya berfungsi, menjadikannya sebagai metode ekstensi menghasilkan kode yang paling mudah digunakan.
Ryan McArthur

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

Jika hari ini adalah hari Senin, jawaban yang Anda berikan akan menghasilkan satu minggu dari hari Selasa, bukan besok.
Tony

5

@ Jon Skeet jawaban yang bagus.

Untuk Hari sebelumnya:

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

Terima kasih!!


Perhatikan bahwa solusi ini melibatkan angka negatif yang diberikan kepada operator modulo. The Wikipedia artikel tentang operator Modulo mengatakan bahwa "Ketika baik atau n adalah negatif, definisi naif rusak dan bahasa pemrograman berbeda dalam bagaimana nilai-nilai ini didefinisikan." Meskipun ini mungkin bekerja di C #, solusi matematis yang lebih 'solid' untuk mendapatkan hasil yang sama akan menukar DayOfWeeknilai - nilai seperti ini:int daysToSubtract = -(((int)dateTime.DayOfWeek - (int)day + 7) % 7);
Andre

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

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

3

Sampel yang sangat sederhana untuk memasukkan atau mengecualikan tanggal saat ini, Anda menentukan tanggal dan hari minggu Anda tertarik.

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

beberapa kasus uji

[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
    }

Saya telah membuat perubahan tambahan dari jawaban awal setelah beberapa pengujian ekstensif. Ini sekarang akan menghitung dengan aman hari berikutnya berdasarkan tanggal yang digunakan, masa lalu, sekarang dan masa depan. Semua contoh sebelumnya di mana hebat, tetapi gagal dalam kondisi tertentu. Saya tidak menjadikannya pernyataan satu baris, sehingga komentar tambahan dapat dibuat untuk apa yang dilakukan perhitungan. Kasus positif oleh Jon Skeet sangat bagus, meskipun kasus yang saya miliki adalah pindah 1 hari kembali dari kencan, tetapi masih lebih besar dari Hari ini, dan bagaimana jika pindah ke hari ini atau kemarin ... ini menyelesaikannya.
AJB

1

Ini bisa menjadi perpanjangan juga, itu semua tergantung

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

Pemakaian

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

0

Sekarang dalam rasa oneliner - jika Anda perlu mengirimkannya sebagai parameter ke beberapa mekanisme.

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

Dalam kasus khusus ini:

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

-5

Versi C Tujuan:

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

4
Jawaban keren, tetapi pertanyaan awal diajukan tentang .NET.
Adam Davis
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.