【问题标题】:Datetime - Get next tuesday日期时间 - 获取下周二
【发布时间】:2011-09-14 19:46:55
【问题描述】:

如何获得下周二的日期?

在 PHP 中,就像strtotime('next tuesday'); 一样简单。

如何在 .NET 中实现类似的功能

【问题讨论】:

  • ASP.NET 是一组 Web 技术。 C# 是一种语言。您确实需要从纯 .NET 的角度来考虑这一点。现在,对于“下周二”——是“今天之后的第一个周二”吗?如果是星期一,有人说“下星期二见”,我希望这意味着 8 天而不是 1 天。如果今天是星期二呢?您需要一天中的什么时间?
  • 如果今天是星期二,你想找出下一个星期二的日期吗?或者今天是星期一,你想从星期一开始找到第二个星期二?
  • 最近的星期二是任何特定的日子。
  • @brenjtL:如果已经是星期二?
  • 如果已经是星期二,那么就在同一天

标签: c# .net date


【解决方案1】:

包含或排除当前日期的非常简单的示例,您指定您感兴趣的日期和星期几。

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
    }

【讨论】:

  • 经过一些广泛的测试后,我对原始答案进行了额外的更改。现在,这将根据使用的日期、过去、现在和未来安全地计算第二天。前面的所有示例都很棒,但在某些条件下都失败了。我没有使它成为一个单行语句,以便可以对计算所做的事情进行额外的 cmets。 Jon Skeet 的正面案例很棒,虽然我的案例是从一个日期向后移动 1 天,但仍然大于今天,如果它移动到今天或昨天怎么办......这解决了它。
【解决方案2】:

Objective C 版本:

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

【讨论】:

  • 很酷的答案,但最初的问题是关于 .NET。
【解决方案3】:

也可以是一个扩展,这完全取决于

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

【讨论】:

  • 没有退出子句的循环收益回报似乎有点冒险。
【解决方案4】:

现在是单线风格 - 以防您需要将其作为参数传递给某些机制。

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】:

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

    谢谢!!

    【讨论】:

    • 请注意,此解决方案涉及传递​​给模运算符的负数。 Wikipedia article about the modulo operator“当 a 或 n 为负数时,天真的定义就会失效,编程语言在定义这些值的方式上会有所不同。” 虽然这可能在 C# 中有效,但在数学上更 '获得相同结果的可靠解决方案是像这样交换 DayOfWeek 值:int daysToSubtract = -(((int)dateTime.DayOfWeek - (int)day + 7) % 7);
    【解决方案6】:
    DateTime nexttuesday=DateTime.Today.AddDays(1);
    
    while(nexttuesday.DayOfWeek!=DayOfWeek.Tuesday)
       nexttuesday = nexttuesday.AddDays(1);
    

    【讨论】:

      【解决方案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);
      }
      

      【讨论】:

      • 唯一实现为 DateTime 扩展的答案。虽然其他解决方案都可以工作,但将其作为扩展方法会产生最容易使用的代码。
      【解决方案8】:

      正如我在 cmets 中提到的,“下周二”可以表示多种含义,但这段代码给出了“下周二发生,或者今天如果已经是周二”:

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

      【讨论】:

      • 哇,我只是想知道我如何才能在下周二之前获得第 n 天,然后你用一个很好的例子更新了你的答案。谢谢
      • 很难选择正确的答案。但你的似乎是最多才多艺的,你让它很容易理解。谢谢你的帮助。
      • @brenjt:实际上我会说 Sven 的用途更广泛,因为您可以指定星期几,但这是您的决定 :)(我现在编辑了我的版本以提供更通用的版本.)
      • +7)%7 解决方案非常好。虽然我没有使用它的原因是因为它有点微优化并且太容易出错(以及牺牲一些可读性),但恕我直言。
      • 单元测试:[TestMethod] public void ShouldGetNextSaturday() { var now = DateTime.Now; var test = GetNextWeekday(DateTime.Today, DayOfWeek.Saturday); Assert.IsTrue(now.Day
      【解决方案9】:
      DateTime nextTuesday = DateTime.Today.AddDays(((int)DateTime.Today.DayOfWeek - (int)DayOfWeek.Tuesday) + 7);
      

      【讨论】:

      • 如果今天是星期一,您提供的答案将是从星期二开始的一周,而不是明天。
      【解决方案10】:

      这应该可以解决问题:

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

      【讨论】:

      • 很好的回应,如果今天是星期二(哈哈),今天或下星期二会返回吗?
      • 这将在下周二返回。如果您希望它今天返回,只需从第一行中删除 .AddDays(1),这样它还会检查 DateTime.Now 本身。
      猜你喜欢
      • 1970-01-01
      • 2019-03-31
      • 1970-01-01
      • 2015-01-29
      • 1970-01-01
      • 1970-01-01
      • 2018-02-04
      • 1970-01-01
      相关资源
      最近更新 更多