web-dev-qa-db-ja.com

日付範囲をループするにはどうすればよいですか?

ループ/カウンタ型の恐ろしいソリューションを使用せずにこれを行う方法もわかりません。問題は次のとおりです。

開始日と終了日という2つの日付が指定されており、指定された間隔で何らかのアクションを実行する必要があります。たとえば、2009年3月26日までの3日ごとの2009年3月10日から2009年3月26日までのすべての日付について、リストにエントリを作成する必要があります。したがって、私の入力は次のようになります。

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

}

しかし、もっと良い方法があるように思えますか?

175
onekidney

まあ、あなたはそれらを何らかの方法でループする必要があります。私はこのようなメソッドを定義することを好みます:

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

この方法で、1日おき、3日おき、平日のみなどをヒットできます。たとえば、「開始」日から3日ごとに戻るには、AddDays(3)の代わりにループでAddDays(1)を呼び出すだけです。

428
mqp

MiscUtilRangeクラスがあり、便利だと思います。さまざまな拡張メソッドと組み合わせて、次のことができます。

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

(終了を除外する場合もしない場合もあります。例として提供したいと思っただけです。)

これは基本的に、既製の(およびより汎用的な)mquanderのソリューションの形式です。

28
Jon Skeet

あなたの例では、試すことができます

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);
}
19
Adriaan Stander

拡張機能で使用される@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);
}
12
Jacob Sobus

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
amd
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
gilbertc
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
}
3
devnull

問題に応じて、これを試すことができます...

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

    startDate = startDate.AddDays(1);
}

ありがとう......

2
Rejwanul Reja

代わりにイテレータを記述することを検討してください。これにより、「++」のような通常の「for」ループ構文を使用できます。検索して、同様の質問を見つけました answered ここでStackOverflowでDateTimeを反復可能にするための指針を与えます。

1
REDace0

DateTime.AddDays()関数を使用してDayIntervalStartDateに追加し、EndDateより小さいことを確認できます。

1
TLiebe
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);
}
1
Sunil Joshi

ここでは、ループ内でより良い解決策となる日付を逃さないように注意する必要があります。

これにより、startdateの最初の日付が得られ、それをインクリメントする前にループで使用すると、enddateの最終日を含むすべての日付が処理されるため、<= enddateとなります。

したがって、上記の答えは正しいものです。

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

これを使用できます。

 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
 }
0
porya ras

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

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);
        }
0
McNiel Viray