วันที่และเวลา - รับวันอังคารหน้า


154

ฉันจะรับวันอังคารถัดไปได้อย่างไร

ใน PHP strtotime('next tuesday');มันเป็นง่ายๆเป็น

ฉันจะทำสิ่งที่คล้ายกันใน. NET ได้อย่างไร


15
ASP.NET เป็นชุดของเทคโนโลยีเว็บ C # เป็นภาษา คุณต้องคิดถึงสิ่งนี้ในแง่ของ. NET แบบธรรมดา ตอนนี้สำหรับ "วันอังคารหน้า" - นั่นคือ "วันอังคารแรกหลังจากวันนี้" หรือไม่? หากเป็นวันจันทร์และมีคนพูดว่า "เจอกันวันอังคารหน้า" ฉันคาดหวังว่าจะหมายถึงเวลา 8 วันแทนที่จะเป็น 1 วันนี้ถ้าวันนี้เป็นวันอังคาร คุณต้องการเวลากี่โมง
Jon Skeet

หากวันนี้เป็นวันอังคารคุณต้องการค้นหาวันที่วันอังคารถัดไปหรือไม่ หรือวันนี้คือวันจันทร์คุณต้องการค้นหาวันอังคารที่สองจากวันจันทร์หรือไม่
สนามแพนด้า

วันอังคารที่ใกล้เคียงที่สุดเดินหน้าไปถึงวันใดวันหนึ่งโดยเฉพาะ
brenjt

2
@brenjtL: และถ้ามันเป็นวันอังคารแล้ว?
Jon Skeet

ถ้าวันอังคารเป็นเช่นนั้นแล้ววันเดียวกันนั้น
brenjt

คำตอบ:


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

หากคุณต้องการให้ "เวลาหนึ่งสัปดาห์" หากถึงวันอังคารแล้วคุณสามารถใช้:

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

ว้าวฉันแค่สงสัยว่าฉันจะหาวันที่สามได้จนถึงวันอังคารหน้าแล้วคุณก็ปรับปรุงคำตอบของคุณด้วยตัวอย่าง Nice ขอบคุณ
brenjt

มันยากที่จะเลือกคำตอบที่ถูกต้อง แต่ดูเหมือนว่าคุณจะมีความหลากหลายที่สุดและคุณทำให้เข้าใจง่าย ขอบคุณสำหรับความช่วยเหลือ
brenjt

1
@brenjt: ที่จริงฉันจะบอกว่า Sven มีความหลากหลายมากกว่าที่คุณสามารถระบุวันของสัปดาห์ แต่มันเป็นสายของคุณ :) (ตอนนี้ฉันแก้ไขของฉันที่จะให้รุ่นทั่วไปมากขึ้น)
Jon Skeet

1
+7)%7แก้ปัญหาคือสวยดีแม้ว่า แม้ว่าเหตุผลที่ฉันไม่ได้ใช้นั่นเป็นเพราะมันเป็นบิตของการเพิ่มประสิทธิภาพขนาดเล็กและง่ายเกินไปที่จะผิด (เช่นเดียวกับการเสียสละบางอย่างอ่าน) แน่นอน imho
Sven

การทดสอบหน่วย: [TestMethod] โมฆะสาธารณะสาธารณะ ShouldGetNextSaturday () {var now = DateTime.Now; var test = GetNextWeekday (DateTime.Today, DayOfWeek.Saturday) Assert.IsTrue (ตอนนี้วัน <ทดสอบวันที่ "วันที่คาดว่าจะไม่ได้อยู่ที่นี่") Assert.IsTrue (test.DayOfWeek == DayOfWeek.Saturday "วันสัปดาห์ที่คาดหวังไม่ได้อยู่ที่นี่"); Assert.IsTrue ((ทดสอบวันนี้ - วันนี้) <7, "ช่วงวันที่คาดหวังไม่ได้อยู่ที่นี่"); }
rasx

67

สิ่งนี้ควรทำเคล็ดลับ:

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

การตอบสนองที่ยอดเยี่ยมหากวันนี้เป็นวันอังคาร (ซึ่งก็คือฮ่า) จะกลับมาในวันนี้หรือวันอังคารหน้า?
brenjt

3
นี่จะกลับมาในวันอังคารหน้า หากคุณต้องการให้คืนวันนี้เพียงแค่ลบออก.AddDays(1)จากบรรทัดแรกด้วยวิธีนั้นก็จะตรวจสอบDateTime.Nowตัวเอง
Sven

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 ในขณะที่โซลูชันอื่น ๆ ใช้งานได้ทั้งหมดการใช้เป็นวิธีส่วนขยายจะทำให้ใช้รหัสได้ง่ายที่สุด
Ryan McArthur

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

หากวันนี้เป็นวันจันทร์คำตอบที่คุณให้ไว้จะให้ผลในวันอังคารตั้งแต่วันอังคารแทนที่จะเป็นพรุ่งนี้
Tony

5

@Jon Skeet คำตอบที่ดี

สำหรับวันก่อนหน้า:

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

ขอบคุณ !!


โปรดทราบว่าการแก้ปัญหานี้เกี่ยวข้องกับจำนวนลบส่งไปยังผู้ประกอบการโมดูโล บทความวิกิพีเดียเกี่ยวกับผู้ประกอบการโมดูโลกล่าวว่า"เมื่อทั้งสองหรือ n เป็นลบแบ่งนิยามไร้เดียงสาลงและการเขียนโปรแกรมภาษาแตกต่างกันในวิธีการที่ค่าเหล่านี้จะถูกกำหนดไว้." ในขณะนี้อาจใช้งานได้ใน C #, โซลูชัน 'แข็ง' ทางคณิตศาสตร์มากขึ้นเพื่อให้ได้ผลลัพธ์เดียวกันคือการแลกเปลี่ยนDayOfWeekค่าเช่นนี้:int daysToSubtract = -(((int)dateTime.DayOfWeek - (int)day + 7) % 7);
Andre


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
    }

ฉันได้ทำการเปลี่ยนแปลงเพิ่มเติมจากคำตอบเดิมหลังจากการทดสอบอย่างละเอียด ตอนนี้จะคำนวณวันถัดไปอย่างปลอดภัยโดยอิงจากวันที่ที่ผ่านมาปัจจุบันและอนาคต ตัวอย่างก่อนหน้าทั้งหมดที่ยอดเยี่ยม แต่ล้มเหลวภายใต้เงื่อนไขบางประการ ฉันไม่ได้ทำให้มันเป็นคำสั่งหนึ่งซับเพื่อให้ความคิดเห็นเพิ่มเติมสามารถทำสิ่งที่การคำนวณกำลังทำอยู่ คดีในเชิงบวกโดย 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

ตอนนี้อยู่ในรสชาติของ oneliner - ในกรณีที่คุณต้องผ่านมันเป็นพารามิเตอร์ในกลไกบางอย่าง

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

วัตถุประสงค์รุ่น C:

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

4
เด็ดคำตอบ แต่คำถามเดิมถามเกี่ยวกับ. NET
Adam Davis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.