Sarah Vessels
Sarah Vessels

Reputation: 31630

C# list of past DateTimes

I have a method that returns the past x days and it currently does the following:

var dates = new List<DateTime>();

for (int i = 0; i < numDays; i++)
{
    dates.Add(DateTime.Today.AddDays(-i));
}

return dates;

I feel like there should be a more compact way of doing this, perhaps using LINQ. Suggestions? Also, if I do keep it the way I have it, is DateTime.Today such that this would be more efficient if I stored it in a variable outside the loop and then called AddDays on that value within the loop?

Edit: LINQ uses lazy evaluation, right? I'm getting crazy images in my head:

return DateTime.AllDaysInTheHistoryOfTimeEver.Where(day =>
    day.BeforeOrOn(DateTime.Today) &&
    day.After(DateTime.Today.AddDays(-numDays))
);

Upvotes: 3

Views: 230

Answers (4)

Jeff Sternal
Jeff Sternal

Reputation: 48583

Marc's answer provides a more persuasive reason to capture the start time, but reflector is one of my guilty pleasures, so I checked and discovered that capturing the start time would also be more efficient (though ... well, you know, unlikely to ever matter, etc..)

When you call DateTime.Today, it returns UtcNow.ToLocalTime() which adds a bit more processing overhead compared to using a date that's already DateTimeKind.Local:

public virtual DateTime ToLocalTime(DateTime time)
{
    if (time.Kind == DateTimeKind.Local)
    {
        return time;
    }
    bool isAmbiguousLocalDst = false;
    long utcOffsetFromUniversalTime = ((CurrentSystemTimeZone) CurrentTimeZone).GetUtcOffsetFromUniversalTime(time, ref isAmbiguousLocalDst);
    return new DateTime(time.Ticks + utcOffsetFromUniversalTime, DateTimeKind.Local, isAmbiguousLocalDst);
}

Upvotes: 1

Pharabus
Pharabus

Reputation: 6062

maybe not linq but you can do it with an iterator, not sure about your exact requirements (i.e. numDays) but the below will get you the last 10 days.

var dates = GetDates(DateTime.Now.AddDays(-10),DateTime.Now);

 public IEnumerable<DateTime> GetDates(DateTime StartingDate, DateTime EndingDate)
        {
            while (StartingDate <= EndingDate)
            {
                yield return StartingDate;
                StartingDate = StartingDate.AddDays(1);
            }
        } 

Upvotes: 1

tafa
tafa

Reputation: 7326

Instead of collecting the values in a list you can return an IEnumerator or IEnumerable and use the yield keyword.

See the MSDN article

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062660

var start = DateTime.Today;
var days = Enumerable.Range(0, numDays).Select(i => start.AddDays(-i)).ToList();

Capturing start first avoids a corner-case of running it at around midnight.

Upvotes: 12

Related Questions