65.9K
CodeProject is changing. Read more.
Home

TimeRanger -- Allows foreaching across a time interval

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.85/5 (9 votes)

Feb 9, 2007

CPOL

1 min read

viewsIcon

42031

downloadIcon

295

A class that allows foreach to enumerate various points within the time interval defined by two DateTime objects

Background

I was working on a data search program the other week. It allows the user to specify start and end DateTime values and searches for data within that range. However, each day's data is stored separately, so the program has to search each day in the range one at a time. It seemed logical to use a foreach to get a DateTime for each day within the range. So I wrote this class to allow me to do that.

The files

The included files are:
TimeRanger.cs
TimeIntervalEnumerators.cs
DateTruncate.cs (which has its own article here)
TimeRangerDemo.cs

Extract them from the zip and add them to your project. (Well, not the demo file unless you want to build the demo.)

Using the code

You can use the TimeRanger class like so:

PIEBALD.Types.TimeRanger tr = new PIEBALD.Types.TimeRanger
(
    System.DateTime.Now.AddDays ( -400 )
,
    System.DateTime.Now.AddDays ( +30 )
) ;

foreach ( System.DateTime dt in tr.Months )
{
    System.Console.WriteLine ( dt ) ;
}

Often you won't need to use TimeRanger; it's convenient for passing a time range to a method and in cases where you want to enumerate the same range multiple times, perhaps with various granularities. In many cases the iterators in TimeIntervalEnumerators.cs will suffice:

foreach
(
    System.DateTime dt in
    PIEBALD.Lib.LibTim.MonthEnumerator
    (
        System.DateTime.Now.AddDays ( -400 )
    ,
        System.DateTime.Now.AddDays ( +30 )
    )
)
{
    System.Console.WriteLine ( dt ) ;
}

Points of Interest

The first version of this used an additional class that implemented IEnumerator, but Russell Morris pointed out iterators (yield methods) that are new in .net 2.0, so I rewrote the code to use them.

For any who want to see how I implemented the iterators (at Russell Morris' suggestion) (note that the iteration will be "backward" if the StartPoint is greater than the EndPoint):

public static System.Collections.Generic.IEnumerable<System.DateTime>
MonthEnumerator
(
    System.DateTime StartPoint
,
    System.DateTime EndPoint
)
{
    System.DateTime current = PIEBALD.Lib.LibTim.DateTruncate 
    ( 
        StartPoint 
    , 
        PIEBALD.Lib.LibTim.TimeGranularity.Month 
    ) ;
            
    if ( StartPoint <= EndPoint )
    {
        if ( current < StartPoint )
        {
            current = current.AddMonths ( 1 ) ;
        }

        while ( current <= EndPoint )
        {
            yield return ( current ) ;
                   
            current = current.AddMonths ( 1 ) ;
        }
    }
    else
    {
        while ( current >= EndPoint )
        {
            yield return ( current ) ;
                   
            current = current.AddMonths ( -1 ) ;
        }
    }
                        
    yield break ;
}

History

First submitted 2007-02-02