【问题标题】:How do I loop through a date range?如何循环遍历日期范围?
【发布时间】:2010-12-23 06:51:06
【问题描述】:

如果不使用一些可怕的 for 循环/计数器类型的解决方案,我什至不确定如何做到这一点。问题来了:

我有两个日期,一个开始日期和一个结束日期,我需要在指定的时间间隔内采取一些行动。例如:对于从 2009 年 3 月 10 日到 2009 年 3 月 26 日的第三天之间的每个日期,我需要在列表中创建一个条目。所以我的输入是:

DateTime StartDate = "3/10/2009";
DateTime EndDate = "3/26/2009";
int DayInterval = 3;

我的输出将是一个包含以下日期的列表:

2009 年 3 月 13 日 2009 年 3 月 16 日 2009 年 3 月 19 日 2009 年 3 月 22 日 2009 年 3 月 25 日

那么我怎么会做这样的事情呢?我考虑过使用一个 for 循环,该循环将在范围内的每一天之间使用一个单独的计数器进行迭代,如下所示:

int count = 0;

for(int i = 0; i < n; i++)
{
     count++;
     if(count >= DayInterval)
     {
          //take action
          count = 0;
     }

}

但似乎还有更好的方法?

【问题讨论】:

  • 我猜 C# 有一个你可以使用的日期数据结构。

标签: c# asp.net datetime loops


【解决方案1】:

好吧,您需要以一种或另一种方式循环它们。我更喜欢定义这样的方法:

public IEnumerable<DateTime> EachDay(DateTime from, DateTime thru)
{
    for(var day = from.Date; day.Date <= thru.Date; day = day.AddDays(1))
        yield return day;
}

那么你可以这样使用它:

foreach (DateTime day in EachDay(StartDate, EndDate))
    // print it or whatever

通过这种方式,您可以每隔一天、每隔三天、仅在工作日等。例如,要从“开始”日期开始每隔三天返回一次,您可以在循环中调用 AddDays(3) 而不是AddDays(1).

【讨论】:

  • 您甚至可以为间隔添加另一个参数。
  • 这将包括第一个日期。如果你不想这样,只需将 'var day = from.Date' 更改为 'var day = from.Date.AddDays(dayInterval)'
  • 一个非常好的解决方案,可以解决一个有趣且真实的单词问题。我喜欢这显示了很多有用的语言技术。这让我想起了 for 循环不仅是 for (int i = 0;...) (-.
  • 将此作为 datetime 的扩展方法可能会更好。
  • 看看我的答案,以延长几天和几个月的时间;)只是为了你的快乐:D
【解决方案2】:

我在MiscUtil 中有一个Range 课程,您会发现它很有用。结合各种扩展方法,你可以这样做:

foreach (DateTime date in StartDate.To(EndDate).ExcludeEnd()
                                   .Step(DayInterval.Days())
{
    // Do something with the date
}

(您可能希望也可能不希望排除结尾 - 我只是想我会提供它作为示例。)

这基本上是 mquander 解决方案的现成(和更通用)形式。

【讨论】:

  • 当然只是个人喜好问题,你是否喜欢这些东西作为扩展方法。 ExcludeEnd()很可爱。
  • 当然,您可以在不使用扩展方法的情况下完成所有这些操作。 IMO 会更难看更难读 :)
  • 哇 - MiscUtil 是多么棒的资源 - 感谢您的回答!
  • 以防除我以外的其他人将 DayInterval 误认为是一个结构/类,它在这个示例中实际上是一个整数。如果你仔细阅读这个问题当然很明显,我没有。
【解决方案3】:

对于您的示例,您可以尝试

DateTime StartDate = new DateTime(2009, 3, 10);
DateTime EndDate = new DateTime(2009, 3, 26);
int DayInterval = 3;

List<DateTime> dateList = new List<DateTime>();
while (StartDate.AddDays(DayInterval) <= EndDate)
{
   StartDate = StartDate.AddDays(DayInterval);
   dateList.Add(StartDate);
}

【讨论】:

  • 这和我想的一样(虽然我也喜欢 mquander 上面的回答),但我不知道你是怎么这么快就发布了一个不错的代码示例!
  • 我认为我们需要 StartDate.AddDays(DayInterval);在这个循环中一次而不是两次。
【解决方案4】:

来自@mquander 和@Yogurt The Wise 的代码用于扩展:

public static IEnumerable<DateTime> EachDay(DateTime from, DateTime thru)
{
    for (var day = from.Date; day.Date <= thru.Date; day = day.AddDays(1))
        yield return day;
}

public static IEnumerable<DateTime> EachMonth(DateTime from, DateTime thru)
{
    for (var month = from.Date; month.Date <= thru.Date || month.Month == thru.Month; month = month.AddMonths(1))
        yield return month;
}

public static IEnumerable<DateTime> EachDayTo(this DateTime dateFrom, DateTime dateTo)
{
    return EachDay(dateFrom, dateTo);
}

public static IEnumerable<DateTime> EachMonthTo(this DateTime dateFrom, DateTime dateTo)
{
    return EachMonth(dateFrom, dateTo);
}

【讨论】:

  • EachDayToEachMonthTo 的意义何在?我想我在这里遗漏了一些东西。
  • @Alisson 这些是在 dateFrom 对象上工作的扩展方法 :) 所以您可以在创建的 DateTime 对象上更流畅地使用它们(仅使用 . after instance)。更多关于扩展方法在这里:docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…
【解决方案5】:

1 年后,可能对某人有所帮助,

这个版本包含一个谓词,更加灵活。

用法

var today = DateTime.UtcNow;
var birthday = new DateTime(2018, 01, 01);

每天到我的生日

var toBirthday = today.RangeTo(birthday);  

每月到我的生日,步骤 2 个月

var toBirthday = today.RangeTo(birthday, x => x.AddMonths(2));

每年到我的生日

var toBirthday = today.RangeTo(birthday, x => x.AddYears(1));

改用RangeFrom

// same result
var fromToday = birthday.RangeFrom(today);
var toBirthday = today.RangeTo(birthday);

实施

public static class DateTimeExtensions 
{

    public static IEnumerable<DateTime> RangeTo(this DateTime from, DateTime to, Func<DateTime, DateTime> step = null)
    {
        if (step == null)
        {
            step = x => x.AddDays(1);
        }

        while (from < to)
        {
            yield return from;
            from = step(from);
        }
    }

    public static IEnumerable<DateTime> RangeFrom(this DateTime to, DateTime from, Func<DateTime, DateTime> step = null)
    {
        return from.RangeTo(to, step);
    }
}

附加功能

如果fromDate &gt; toDate,你可以抛出异常,但我更喜欢返回一个空范围而不是[]

【讨论】:

  • 哇——这真的很全面。谢谢艾哈迈德!
【解决方案6】:
DateTime startDate = new DateTime(2009, 3, 10);
DateTime stopDate = new DateTime(2009, 3, 26);
int interval = 3;

for (DateTime dateTime=startDate;
     dateTime < stopDate; 
     dateTime += TimeSpan.FromDays(interval))
{

}

【讨论】:

    【解决方案7】:

    根据问题你可以试试这个...

    // looping between date range    
    while (startDate <= endDate)
    {
        //here will be your code block...
    
        startDate = startDate.AddDays(1);
    }
    

    谢谢......

    【讨论】:

      【解决方案8】:
      DateTime begindate = Convert.ToDateTime("01/Jan/2018");
      DateTime enddate = Convert.ToDateTime("12 Feb 2018");
       while (begindate < enddate)
       {
          begindate= begindate.AddDays(1);
          Console.WriteLine(begindate + "  " + enddate);
       }
      

      【讨论】:

        【解决方案9】:
        DateTime startDate = new DateTime(2009, 3, 10);
        DateTime stopDate = new DateTime(2009, 3, 26);
        int interval = 3;
        
        while ((startDate = startDate.AddDays(interval)) <= stopDate)
        {
            // do your thing
        }
        

        【讨论】:

        • 请注意,这不包括开始日期,因为它会在 while 第一次运行时添加一天。
        【解决方案10】:

        这是我 2020 年的 2 美分。

        Enumerable.Range(0, (endDate - startDate).Days + 1)
        .ToList()
        .Select(a => startDate.AddDays(a));
        

        【讨论】:

        • 这太棒了。 ?
        【解决方案11】:

        您可以考虑编写一个迭代器,它允许您使用普通的“for”循环语法,如“++”。我在 StackOverflow 上搜索并发现了一个类似的问题 answered here,它提供了有关使 DateTime 可迭代的指针。

        【讨论】:

          【解决方案12】:

          您可以使用DateTime.AddDays() 函数将您的DayInterval 添加到StartDate 并检查以确保它小于EndDate

          【讨论】:

            【解决方案13】:

            你必须小心不要错过循环中更好的解决方案的日期。

            这为您提供了 startdate 的第一个日期,并在递增它之前在循环中使用它,它将处理所有日期,包括 enddate 的最后日期,因此

            所以上面的答案是正确的。

            while (startdate <= enddate)
            {
                // do something with the startdate
                startdate = startdate.adddays(interval);
            }
            

            【讨论】:

              【解决方案14】:

              你可以用这个。

               DateTime dt0 = new DateTime(2009, 3, 10);
               DateTime dt1 = new DateTime(2009, 3, 26);
              
               for (; dt0.Date <= dt1.Date; dt0=dt0.AddDays(3))
               {
                  //Console.WriteLine(dt0.Date.ToString("yyyy-MM-dd"));
                  //take action
               }
              

              【讨论】:

              • 真的很简洁。不错!
              【解决方案15】:

              每 15 分钟迭代一次

              DateTime startDate = DateTime.Parse("2018-06-24 06:00");
                      DateTime endDate = DateTime.Parse("2018-06-24 11:45");
              
                      while (startDate.AddMinutes(15) <= endDate)
                      {
              
                          Console.WriteLine(startDate.ToString("yyyy-MM-dd HH:mm"));
                          startDate = startDate.AddMinutes(15);
                      }
              

              【讨论】:

                【解决方案16】:

                @jacob-sobus 和 @mquander 和 @Yogurt 不完全正确。如果我需要第二天我会等待 00:00 时间

                    public static IEnumerable<DateTime> EachDay(DateTime from, DateTime thru)
                    {
                        for (var day = from.Date; day.Date <= thru.Date; day = day.NextDay())
                            yield return day;
                    }
                
                    public static IEnumerable<DateTime> EachMonth(DateTime from, DateTime thru)
                    {
                        for (var month = from.Date; month.Date <= thru.Date || month.Year == thru.Year && month.Month == thru.Month; month = month.NextMonth())
                            yield return month;
                    }
                
                    public static IEnumerable<DateTime> EachYear(DateTime from, DateTime thru)
                    {
                        for (var year = from.Date; year.Date <= thru.Date || year.Year == thru.Year; year = year.NextYear())
                            yield return year;
                    }
                
                    public static DateTime NextDay(this DateTime date)
                    {
                        return date.AddTicks(TimeSpan.TicksPerDay - date.TimeOfDay.Ticks);
                    }
                
                    public static DateTime NextMonth(this DateTime date)
                    {
                        return date.AddTicks(TimeSpan.TicksPerDay * DateTime.DaysInMonth(date.Year, date.Month) - (date.TimeOfDay.Ticks + TimeSpan.TicksPerDay * (date.Day - 1)));
                    }
                
                    public static DateTime NextYear(this DateTime date)
                    {
                        var yearTicks = (new DateTime(date.Year + 1, 1, 1) - new DateTime(date.Year, 1, 1)).Ticks;
                        var ticks = (date - new DateTime(date.Year, 1, 1)).Ticks;
                        return date.AddTicks(yearTicks - ticks);
                    }
                
                    public static IEnumerable<DateTime> EachDayTo(this DateTime dateFrom, DateTime dateTo)
                    {
                        return EachDay(dateFrom, dateTo);
                    }
                
                    public static IEnumerable<DateTime> EachMonthTo(this DateTime dateFrom, DateTime dateTo)
                    {
                        return EachMonth(dateFrom, dateTo);
                    }
                
                    public static IEnumerable<DateTime> EachYearTo(this DateTime dateFrom, DateTime dateTo)
                    {
                        return EachYear(dateFrom, dateTo);
                    }
                

                【讨论】:

                  【解决方案17】:

                  如果您将日期转换为 OADate,您可以像处理任何 double 号码一样循环遍历它们。

                  DateTime startDate = new DateTime(2022, 1, 1);
                  DateTime endDate = new DateTime(2022, 12, 31);
                  
                  for (double loopDate = startDate.ToOADate(); loopDate <= endDate.ToOADate(); loopDate++)
                  {
                      DateTime selectedDate;
                      selectedDate = DateTime.FromOADate(loopDate);
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2011-02-19
                    • 1970-01-01
                    • 2011-05-19
                    • 2020-03-06
                    • 1970-01-01
                    • 2023-02-17
                    • 1970-01-01
                    • 2021-12-30
                    相关资源
                    最近更新 更多