Bir tarih aralığında nasıl döngü yapabilirim?


198

Hatta döngü / sayaç tipi çözüm için bazı korkunç kullanmadan bunu nasıl emin değilim. Sorun şu:

İki tarih veriyorum, bir başlangıç ​​tarihi ve bir bitiş tarihi ve belirli bir aralıkta bazı işlemler yapmam gerekiyor. Örneğin: 3/10/2009 ile 3/26/2009 arasında her üçüncü günde bir tarih için Listede bir giriş oluşturmam gerekiyor. Yani benim girdileri:

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

ve çıktım aşağıdaki tarihleri ​​içeren bir liste olurdu:

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

Peki böyle bir şeyi nasıl yaparım? Böyle ayrı bir sayaç ile aralıktaki her gün arasında yinelenen bir for döngüsü kullanmayı düşündüm:

int count = 0;

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

}

Ama daha iyi bir yol olabilir gibi görünüyor?


1
Sanırım C # kullanabilirsiniz tarihler için bir veri yapısı vardır.
Anna

Yanıtlar:


471

Bunları şu ya da bu şekilde tekrarlamanız gerekir. Ben böyle bir yöntem tanımlamayı tercih:

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

O zaman bu şekilde kullanabilirsiniz:

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

Bu şekilde "Başlangıç" tarih ile başlayan üç günde dönmek için, Örneğin vb sadece hafta içi, üç günde bir, iki günde bir vurabilecek, sadece diyebiliriz AddDays(3)yerine döngü içinde AddDays(1).


18
Aralık için başka bir parametre bile ekleyebilirsiniz.
Justin Drury

Bu ilk tarihi içerir. Bunu istemiyorsanız, sadece 'var day = from.Date' yerine 'var day = from.Date.AddDays (dayInterval)' olarak değiştirin
SwDevMan81

3
İlginç ve gerçek bir kelime problemi için gerçekten güzel bir çözüm. Bunun dilin birkaç yararlı tekniğini nasıl gösterdiğini seviyorum. Ve bu hatırlatmak için döngü için sadece (int i = 0; ...) (-.
Audrius

9
Bunu datetime için bir genişletme yöntemi yapmak daha da iyi hale getirebilir.
MatteS

1
Günler ve aylar için uzantılarıma cevabımı bak;) Sadece zevk için: D
Jacob Sobus

31

MiscUtil'de yararlı bulabileceğiniz bir Rangesınıfım var . Çeşitli genişletme yöntemleriyle birlikte şunları yapabilirsiniz:

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

(Sonu dışlamak isteyebilir veya istemeyebilirsiniz - sadece örnek olarak vereceğimi düşündüm.)

Bu temel olarak mquander çözeltisinin hazır haddelenmiş (ve daha genel amaçlı) bir şeklidir.


2
Kuşkusuz bu tür şeylerin uzatma yöntemleri olmasını isteyip istemediğinizi sadece bir zevk meselesi. ExcludeEnd()Şirin.
mqp

Elbette, tüm bunları genişletme yöntemlerini kullanmadan yapabilirsiniz. IMO okumak çok daha çirkin ve daha zor olacak :)
Jon Skeet

1
Vay canına - MiscUtil harika bir kaynak - cevabınız için teşekkürler!
onekidney

1
benden başka kimsenin DayInterval'ı bir yapı / sınıf olarak yanlış anlaması durumunda, aslında bu örnekte bir tamsayıdır. soruyu dikkatlice okursanız elbette açıktır, ki ben bilmedim.
marc.d

23

Örneğiniz için deneyebilirsiniz

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

1
Bu aynı şey (yukarıdaki mquander'ın cevabını da sevmeme rağmen) düşünüyordum ama çok hızlı bir şekilde gönderilen güzel bir kod örneğini nasıl alacağınızı anlayamıyorum!
TLiebe

3
Sanırım StartDate.AddDays (DayInterval); bir kez bu döngüde iki kez değil.
Abdul Saboor

15

@Mquander ve @Yogurt kodları Uzantılarda kullanılan bilge:

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

Amaç nedir EachDayTove EachMonthTo? Sanırım burada bir şey kaçırdım.
Alisson

@Alisson, dateFrom nesnesinde çalışan uzantı yöntemleridir :) Böylece, oluşturulan DateTime nesnelerinde zaten daha akıcı bir şekilde kullanabilirsiniz (sadece. After örneğini kullanarak). Uzantı yöntemleri hakkında daha fazla bilgi için: docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…
Jacob Sobus

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

}

8

1 yıl sonra, birine yardım edebilir mi,

Bu sürüm daha esnek olmak için bir yüklem içerir .

kullanım

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

Günlük doğum günüme

var toBirthday = today.RangeTo(birthday);  

Doğum günüme aylık, Adım 2 ay

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

Yıllık doğum günüm

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

RangeFromBunun yerine kullan

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

uygulama

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

Ekstralar

İsterseniz bir İstisna atabilirsiniz fromDate > toDate, ancak bunun yerine boş bir aralık döndürmeyi tercih ederim[]


Vay canına - bu gerçekten kapsamlı. Teşekkürler Ahmad!
onekidney

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
}

İlk whileçalıştırmada bir gün eklediğinden, bunun başlangıç ​​tarihini içermediğini unutmayın .
John Washam

2

Soruna göre bunu deneyebilirsiniz ...

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

    startDate = startDate.AddDays(1);
}

Teşekkürler......


2
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

Bunun yerine, '++' gibi normal 'for' döngü sözdizimini kullanmanızı sağlayan bir yineleyici yazmayı düşünebilirsiniz. Ben arama ve burada DateTime yinelenebilir hale işaretçiler verir StackOverflow üzerinde cevap benzer bir soru bulundu .


1

Sen kullanabilirsiniz DateTime.AddDays()senin eklemek için fonksiyonu DayIntervaliçin StartDateve altında olduğundan emin olmak için kontrol EndDate.


0

burada döngüde daha iyi bir çözüm olacağını tarihleri ​​kaçırmamak için dikkatli olmalısınız.

bu, başlangıç ​​tarihinin ilk tarihini verir ve artırmadan önce döngüde kullanır ve bitiş tarihinin son tarihi de dahil olmak üzere tüm tarihleri ​​işleyecektir, bu nedenle <= bitiş tarihi.

bu yüzden yukarıdaki cevap doğru cevaptır.

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

0

bunu kullanabilirsiniz.

 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
 }

Bu gerçekten kısa ve öz. Güzel!
onekidney

0

15 dakikada bir tekrarla

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

@ jacob-sobus ve @mquander ve @Yogurt tam olarak doğru değil .. Ertesi güne ihtiyacım olursa 00:00 çoğunlukla bekliyorum

    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

İşte 2020'de 2 sentim.

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

Bu harika. 👍
onekidney
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.