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

brenjt
sumber
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);
Jon Skeet
sumber
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;
}
Sven
sumber
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);
}
Brent
sumber
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);
Anjing kampung
sumber
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!!

Anik Islam Abhi
sumber
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);
Buta
sumber
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
    }
AJB
sumber
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();
    }
Alex Nolasco
sumber
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
Matas Vaitkevicius
sumber
-5

Versi C Tujuan:

+(NSInteger) daysUntilNextWeekday: (NSDate*)startDate withTargetWeekday: (NSInteger) targetWeekday
{
    NSInteger startWeekday = [[NSCalendar currentCalendar] component:NSCalendarUnitWeekday fromDate:startDate];
    return (targetWeekday - startWeekday + 7) % 7;
}
Max Hiroyuki Ueda
sumber
4
Jawaban keren, tetapi pertanyaan awal diajukan tentang .NET.
Adam Davis