Как мне пройти через диапазон дат?

Я даже не знаю, как это сделать, не используя какое-то ужасное решение для типа loop/counter. Здесь проблема:

Мне даны две даты, дата начала и дата окончания, и в указанный промежуток времени мне нужно предпринять некоторые действия. Например: для каждой даты между 3/10/2009 в каждый третий день до 26.03.2009 мне нужно создать запись в списке. Итак, мои входы будут:

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

и мой вывод будет списком, который имеет следующие даты:

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

Так как, черт возьми, я сделаю что-то вроде этого? Я думал об использовании цикла for, который будет перебирать между каждым днем ​​в диапазоне с отдельным счетчиком следующим образом:

int count = 0;

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

}

Но похоже, что может быть лучший способ?

Ответ 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).

Ответ 2

У меня есть класс Range в MiscUtil, который вы можете найти полезным. В сочетании с различными методами расширения вы можете:

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

(Вы можете или не хотите исключать конец - я просто подумал, что я приведу его в качестве примера.)

Это, в основном, готовая (и более общая) форма решения mquander.

Ответ 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);
}

Ответ 4

Код из @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

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

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 > toDate, но я предпочитаю вместо этого возвращать пустой диапазон []

Ответ 7

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

В соответствии с проблемой вы можете попробовать это...

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

    startDate = startDate.AddDays(1);
}

спасибо......

Ответ 9

Вы можете использовать функцию DateTime.AddDays(), чтобы добавить DayInterval в StartDate и проверить, чтобы она была меньше, чем EndDate.

Ответ 10

Вместо этого вы можете вместо этого использовать вместо него итератор, который позволяет использовать обычный синтаксис цикла "для", например "++". Я искал и нашел аналогичный вопрос ответил здесь, на StackOverflow, который дает указатели на то, чтобы сделать DateTime итерабельным.

Ответ 11

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

вы должны быть осторожны, чтобы не пропустить даты, когда в цикле было бы лучшее решение.

это дает вам первую дату startdate и использует ее в цикле, прежде чем увеличивать ее, и будет обрабатывать все даты, включая последнюю дату enddate, следовательно <= enddate.

поэтому приведенный выше ответ правильный.

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

Ответ 13

Вы можете использовать это.

 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
 }

Ответ 14

Повторяйте каждые 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);
        }

Ответ 15

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