Wednesday, March 30, 2011

How do you iterate through every day of the year?

Given a start date of 1/1/2009 and an end date of 12/31/2009, how can I iterate through each date and retrieve a DateTime value using c#?

Thanks!

From stackoverflow
  • DateTime dateTime = new DateTime(2009, 1, 1);    
    
    while(dateTime.Year < 2010)
        {
    
          dateTime = dateTime.AddDays(1);
        }
    
    Ray : Add days returns a DateTime rather than increasing the DateTime it operates on.
  • I would use a loop that looks like this

    for(DateTime date = begin; date <= end; date = date.AddDays(1))
    {
    }
    

    Set begin and end accordingly

    Stuart Branham : Since we don't know what begin and end are in the context of this code block, either could be correct. ;)
  • Set two variables:

    DateTime lowValue = DateTime.Parse("1/1/2009");
    DateTime highValue = DateTime.Parse("12/31/2009");
    

    Then, add a day to the low value until it is equal to highvalue:

    while (lowValue <= highValue)
    {
       //Do stuff here
       lowValue = lowValue.AddDays(1);
    }
    

    Or something like that.

    John Sheehan : fixed your assignment and casting bugs.
    John Sheehan : and off-by-one bug
  • DateTime current = DateTime.Parse("1/1/2009");
    DateTime nextYear = current.AddYears(1);
    do
    {
        Console.WriteLine(current);
        current = current.AddDays(1);
    } while (current < nextYear) ;
    
  • int day; for (int i = 1; i<365;i++) { day++; }

    Sorry, couldn't resist.

  • I'd use MiscUtil and its extension methods:

    foreach(DateTime date in 1.January(2009)
                             .To(31.December(2009))
                             .Step(1.Days())
    {
        Console.WriteLine(date);
    }
    
  • Another option implementing the Iterator design pattern:

    This may sound unnecessary, but I depending on how to you use this functionality, you may also implement the Iterator design pattern.

    Think on this. Suppose that everything works just fine, and you copy/paste all over the place the "for" sentence. And suddenly as part of the requirements, you have to iterate all the days but skip some of them ( like in calendar, skip holydays, weekends, custom etc. )

    You would have to create a new "snipped" and use Calendar instead. Then search and replace all your for's.

    In OOP, this could be achieved using the Iterator pattern.

    From Wikpedia:

    In object-oriented programming, the Iterator pattern is a design pattern in which iterators are used to access the elements of an aggregate object sequentially without exposing its underlying representation. An Iterator object encapsulates the internal structure of how the iteration occurs.

    So the idea is to use a construct like this:

            DateTime fromDate = DateTime.Parse("1/1/2009");
            DateTime toDate   = DateTime.Parse("12/31/2009");
    
            // Create an instance of the collection class
            DateTimeEnumerator dateTimeRange = 
                                  new DateTimeEnumerator( fromDate, toDate );
    
    
            // Iterate with foreach
            foreach (DateTime day in dateTimeRange )
            {
                System.Console.Write(day + " ");
            }
    

    And then if needed you could create subclasses to implement different algorithms, one that uses AddDay(1), other that uses AddDay( 7 ) or other that simple uses Calendar instead. Etc. etc.

    The idea is to lower the coupling between objects.

    Again, this would be overkill for most of the cases, but if the iteration forms a relevant part of a system ( let's say , you are creating some kind of whatever notification, for an enterprise, and should adhere to different globalizations

    The basic implementation of course would use the for.

    public class DateTimeEnumerator : System.Collections.IEnumerable
    {
        private final DateTime begin;
        private final DateTime end;
    
        public DateTimeEnumerator ( DateTime begin , DateTime end ) 
        {
            // probably create a defensive copy here... 
            this.begin = begin;
            this.end = end;
        }
        public System.Collections.IEnumerator GetEnumerator()
        {
            for(DateTime date = begin; date < end; date = date.AddDays(1))
            {
                yield return date;
            }
        }
    }
    

    Just an idea :)

0 comments:

Post a Comment