Ngày tháng - Nhận thứ ba tiếp theo


154

Làm thế nào tôi có thể có được ngày thứ ba tiếp theo?

Trong PHP, nó đơn giản như strtotime('next tuesday'); .

Làm thế nào tôi có thể đạt được một cái gì đó tương tự trong .NET


15
ASP.NET là một tập hợp các công nghệ web. C # là một ngôn ngữ. Bạn thực sự cần phải nghĩ về điều này về mặt .NET. Bây giờ, cho "Thứ ba tiếp theo" - đó có phải là "Thứ ba đầu tiên sau ngày hôm nay" không? Nếu đó là thứ Hai và ai đó nói "hẹn gặp lại vào thứ ba tuần sau" thì tôi mong rằng điều đó có nghĩa là thời gian 8 ngày chứ không phải 1. Còn hôm nay là thứ ba thì sao? Bạn cần thời gian nào trong ngày?
Jon Skeet

Nếu hôm nay là thứ ba, bạn muốn tìm ngày nào là thứ ba tiếp theo? Hay hôm nay là thứ hai, bạn muốn tìm thứ ba thứ hai từ thứ hai?
FIre Panda

Thứ ba gần nhất sắp tới mà ngày nào cũng vậy.
brenjt

2
@brenjtL: Và nếu đã là thứ ba?
Jon Skeet

Nếu đã là thứ ba thì cùng ngày hôm đó
brenjt

Câu trả lời:


371

Như tôi đã đề cập trong các bình luận, có nhiều điều bạn có thể có nghĩa là "Thứ ba tiếp theo", nhưng mã này cung cấp cho bạn "thứ ba tiếp theo sẽ xảy ra hoặc hôm nay nếu đó là thứ ba":

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

Nếu bạn muốn đưa ra "thời gian một tuần" nếu đã là thứ ba, bạn có thể sử dụng:

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

... Hoặc bạn có thể sử dụng công thức gốc, nhưng từ ngày mai:

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: Chỉ để làm cho điều này tốt đẹp và linh hoạt:

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

Vì vậy, để có được giá trị cho "hôm nay hoặc trong 6 ngày tới":

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

Để nhận giá trị cho "thứ ba tiếp theo trừ ngày hôm nay":

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

Ồ, tôi chỉ tự hỏi làm thế nào tôi có thể có được ngày thứ n cho đến thứ ba tiếp theo và sau đó bạn cập nhật câu trả lời của mình với một ví dụ Nice. Cảm ơn
brenjt

Thật khó để chọn câu trả lời đúng. Nhưng bạn dường như là người linh hoạt nhất và bạn đã làm cho nó dễ hiểu. Cảm ơn sự giúp đỡ của bạn.
brenjt

1
@brenjt: Thật ra tôi muốn nói rằng Sven linh hoạt hơn, vì bạn có thể chỉ định ngày trong tuần, nhưng đó là cuộc gọi của bạn :) (Bây giờ tôi đã chỉnh sửa của tôi để đưa ra một phiên bản tổng quát hơn.)
Jon Skeet

1
Các +7)%7giải pháp là khá tốt mặc dù. Mặc dù lý do tôi không sử dụng là vì đó là một chút tối ưu hóa vi mô và quá dễ bị sai (cũng như hy sinh một số khả năng đọc), tất nhiên là imho.
Sven

Một bài kiểm tra đơn vị: [TestMethod] public void ShouldGetNextSaturday () {var now = DateTime.Now; var test = GetNextWeekday (DateTime.Today, DayOfWeek.Saturday); Assert.IsTrue (now.Day <test.Day, "Ngày tháng dự kiến ​​không có ở đây."); Assert.IsTrue (test.DayOfWeek == DayOfWeek.Saturday, "Ngày trong tuần dự kiến ​​không có ở đây."); Assert.IsTrue ((test.Day - now.Day) <7, "Khoảng thời gian dự kiến ​​không có ở đây."); }
rasx

67

Cái này cần phải dùng mẹo:

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

Phản ứng tuyệt vời, nếu hôm nay là thứ ba (mà là ha) thì điều này sẽ trở lại vào hôm nay hay thứ ba tiếp theo?
brenjt

3
Điều này sẽ trở lại vào thứ ba tiếp theo. Nếu bạn muốn nó trở lại ngày hôm nay, chỉ cần xóa .AddDays(1)dòng đầu tiên, theo cách đó nó cũng sẽ DateTime.Nowtự kiểm tra .
Sven

7

Có ít giải pháp dài dòng hơn và thông minh hơn / giải pháp cho vấn đề này, nhưng hàm C # sau hoạt động thực sự tốt cho một số tình huống.

/// <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
Câu trả lời duy nhất thực hiện như phần mở rộng cho DateTime. Trong khi tất cả các giải pháp khác đều hoạt động, việc sử dụng nó như một phương thức mở rộng sẽ tạo ra mã dễ sử dụng nhất.
Ryan McArthur

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

Nếu hôm nay là thứ Hai, câu trả lời mà bạn cung cấp sẽ mang lại một tuần kể từ thứ Ba, thay vì ngày mai.
Tony

5

@Jon Skeet trả lời tốt.

Cho ngày trước:

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

Cảm ơn!!


Lưu ý rằng giải pháp này liên quan đến các số âm được trao cho toán tử modulo. Các bài viết trên Wikipedia về các nhà điều hành modulo nói rằng "Khi một trong hai một hoặc n là tiêu cực, phá vỡ nét ngây thơ xuống và ngôn ngữ lập trình khác nhau về cách thức các giá trị này được xác định." Trong khi điều này có thể hoạt động trong C #, một giải pháp 'vững chắc' hơn về mặt toán học để có được kết quả tương tự sẽ là trao đổi các DayOfWeekgiá trị như thế này: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

Mẫu rất đơn giản để bao gồm hoặc loại trừ ngày hiện tại, bạn chỉ định ngày và ngày trong tuần bạn quan tâm.

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

một số trường hợp thử nghiệm

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

Tôi đã thực hiện các thay đổi bổ sung từ câu trả lời ban đầu sau một số thử nghiệm mở rộng. Điều này bây giờ sẽ tính toán một cách an toàn vào ngày tiếp theo dựa trên ngày được sử dụng, quá khứ, hiện tại và tương lai. Tất cả các ví dụ trước đây tuyệt vời, nhưng thất bại trong các điều kiện nhất định. Tôi đã không làm cho nó thành một tuyên bố một lót, để có thể nhận xét bổ sung cho những gì các tính toán đang làm. Trường hợp tích cực của Jon Skeet là tuyệt vời, mặc dù trường hợp tôi gặp phải là quay lại 1 ngày kể từ ngày, nhưng vẫn lớn hơn Hôm nay, và nếu nó chuyển sang ngày hôm nay hoặc hôm qua ... thì điều này đã giải quyết nó.
AJB

1

cũng có thể là một phần mở rộng, tất cả phụ thuộc vào

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

Sử dụng

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

0

Bây giờ trong hương vị oneliner - trong trường hợp bạn cần chuyển nó dưới dạng tham số vào một số cơ chế.

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

Trong trường hợp cụ thể này:

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

-5

Phiên bản mục tiêu C:

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

4
Câu trả lời tuyệt vời, nhưng câu hỏi ban đầu hỏi về .NET.
Adam Davis
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.