如何循环遍历一个日期范围?

时间:2022-10-30 10:28:33

I'm not even sure how to do this without using some horrible for loop/counter type solution. Here's the problem:

我甚至不知道如何做到这一点而不使用一些可怕的for循环/counter类型解决方案。问题就在这里:

I'm given two dates, a start date and an end date and on a specified interval I need to take some action. For example: for every date between 3/10/2009 on every third day until 3/26/2009 I need to create an entry in a List. So my inputs would be:

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

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

and my output would be a list that has the following dates:

我的输出是一个有以下日期的列表:

3/13/2009 3/16/2009 3/19/2009 3/22/2009 3/25/2009

3/13/2009 3/16/2009 3/19/2009 3/22/2009 3/25/2009

So how the heck would I do something like this? I thought about using a for loop that would iterate between every day in the range with a separate counter like so:

我该怎么做呢?我想过使用一个for循环,它每天都在范围内迭代,使用一个独立的计数器:

int count = 0;

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

}

But it seems like there could be a better way?

但似乎还有更好的办法呢?

13 个解决方案

#1


367  

Well, you'll need to loop over them one way or the other. I prefer defining a method like this:

你需要以这样或那样的方式循环它们。我更喜欢这样定义一个方法:

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

Then you can use it like this:

然后你可以这样使用:

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

In this manner you could hit every other day, every third day, only weekdays, etc. For example, to return every third day starting with the "start" date, you could just call AddDays(3) in the loop instead of AddDays(1).

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

#2


28  

I have a Range class in MiscUtil which you could find useful. Combined with the various extension methods, you could do:

我有一个叫Range的课程,你们会发现它很有用。结合各种扩展方法,你可以做到:

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

(You may or may not want to exclude the end - I just thought I'd provide it as an example.)

(你可能不想也可能不想把结尾排除在外——我只是想举个例子。)

This is basically a ready-rolled (and more general-purpose) form of mquander's solution.

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

#3


18  

For your example you can try

举个例子,你可以试试。

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

#4


11  

Code from @mquander and @Yogurt The Wise used in extensions:

@mquander和@Yogurt智慧的代码扩展:

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

#5


7  

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

}

#6


4  

1 Year later, may it help someone,

一年后,它会帮助某人,

This version includes a predicate, to be more flexible.

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

Usage

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

Daily to my birthday

var toBirthday = today.RangeTo(birthday);  

Monthly to my birthday, Step 2 months

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

Yearly to my birthday

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

Use RangeFrom instead

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

Implementation

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

Extras

You could throw an Exception if the fromDate > toDate, but I prefer to return an empty range instead []

如果fromDate >到date,您可以抛出一个异常,但我宁愿返回一个空的范围[]

#7


3  

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
}

#8


2  

According to the problem you can try this...

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

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

    startDate = startDate.AddDays(1);
}

thanks......

谢谢……

#9


1  

You might consider writing an iterator instead, which allows you to use normal 'for' loop syntax like '++'. I searched and found a similar question answered here on * which gives pointers on making DateTime iterable.

您可以考虑编写一个迭代器,它允许您使用“for”循环语法,比如“++”。我在*上搜索并找到了一个类似的问题,这个问题给出了使DateTime可迭代的指针。

#10


1  

You can use the DateTime.AddDays() function to add your DayInterval to the StartDate and check to make sure it is less than the EndDate.

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

#11


1  

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

#12


0  

you have to be careful here not to miss the dates when in the loop a better solution would be.

在这里,您必须小心,不要错过循环中更好的解决方案的日期。

this gives you the first date of startdate and use it in the loop before incrementing it and it will process all the dates including the last date of enddate hence <= enddate.

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

so the above answer is the correct one.

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

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

#13


0  

you can use this.

你可以使用这个。

 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
 }

#1


367  

Well, you'll need to loop over them one way or the other. I prefer defining a method like this:

你需要以这样或那样的方式循环它们。我更喜欢这样定义一个方法:

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

Then you can use it like this:

然后你可以这样使用:

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

In this manner you could hit every other day, every third day, only weekdays, etc. For example, to return every third day starting with the "start" date, you could just call AddDays(3) in the loop instead of AddDays(1).

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

#2


28  

I have a Range class in MiscUtil which you could find useful. Combined with the various extension methods, you could do:

我有一个叫Range的课程,你们会发现它很有用。结合各种扩展方法,你可以做到:

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

(You may or may not want to exclude the end - I just thought I'd provide it as an example.)

(你可能不想也可能不想把结尾排除在外——我只是想举个例子。)

This is basically a ready-rolled (and more general-purpose) form of mquander's solution.

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

#3


18  

For your example you can try

举个例子,你可以试试。

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

#4


11  

Code from @mquander and @Yogurt The Wise used in extensions:

@mquander和@Yogurt智慧的代码扩展:

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

#5


7  

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

}

#6


4  

1 Year later, may it help someone,

一年后,它会帮助某人,

This version includes a predicate, to be more flexible.

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

Usage

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

Daily to my birthday

var toBirthday = today.RangeTo(birthday);  

Monthly to my birthday, Step 2 months

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

Yearly to my birthday

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

Use RangeFrom instead

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

Implementation

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

Extras

You could throw an Exception if the fromDate > toDate, but I prefer to return an empty range instead []

如果fromDate >到date,您可以抛出一个异常,但我宁愿返回一个空的范围[]

#7


3  

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
}

#8


2  

According to the problem you can try this...

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

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

    startDate = startDate.AddDays(1);
}

thanks......

谢谢……

#9


1  

You might consider writing an iterator instead, which allows you to use normal 'for' loop syntax like '++'. I searched and found a similar question answered here on * which gives pointers on making DateTime iterable.

您可以考虑编写一个迭代器,它允许您使用“for”循环语法,比如“++”。我在*上搜索并找到了一个类似的问题,这个问题给出了使DateTime可迭代的指针。

#10


1  

You can use the DateTime.AddDays() function to add your DayInterval to the StartDate and check to make sure it is less than the EndDate.

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

#11


1  

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

#12


0  

you have to be careful here not to miss the dates when in the loop a better solution would be.

在这里,您必须小心,不要错过循环中更好的解决方案的日期。

this gives you the first date of startdate and use it in the loop before incrementing it and it will process all the dates including the last date of enddate hence <= enddate.

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

so the above answer is the correct one.

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

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

#13


0  

you can use this.

你可以使用这个。

 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
 }