I'm trying to get a certain number of date ranges given a start date. Here's my code:
var startDate = new DateTime(2014, 1, 1);
var dates = new List<DateBlock>();
int counter = 0;
while(counter < 6)
{
if (startDate >= DateTime.UtcNow)
{
dates.Add(new DateBlock
{
StartDate = startDate,
EndDate = startDate.AddDays(30)
});
counter++;
}
startDate = startDate.AddDays(30);
}
var first = dates.First();
dates.Insert(0, new DateBlock
{
StartDate = first.StartDate.AddDays(-30),
EndDate = first.StartDate
});
I'm wondering if there is a better way of doing this?
EDIT: If the start date is 1/1/1 it should loop through and increment by 30 days and only add to the list if the current date is greater than or equal to UtcNow. Also it should keep going into the future until 6 more DateBlock's are added to the list.
-
\$\begingroup\$ So it should only start adding date ranges when the start date is in the future? \$\endgroup\$Mitchell Lee– Mitchell Lee2014年04月05日 14:22:53 +00:00Commented Apr 5, 2014 at 14:22
-
\$\begingroup\$ @MitchellLee Correct. \$\endgroup\$Ryan– Ryan2014年04月05日 14:33:17 +00:00Commented Apr 5, 2014 at 14:33
1 Answer 1
The loop to find the starting date is clearly not needed. This can be done with library object TimeSpan -- like this:
void Main()
{
var startDate = new DateTime(2014, 1, 1);
var dates = new List<DateBlock>();
int priorPeriods = ((DateTime.UtcNow-startDate).Days) / 30;
DateTime dateIndex = startDate.AddDays(priorPeriods*30);
for(int index = 0; index < 6; index++)
{
dates.Add(new DateBlock { StartDate = dateIndex, EndDate = dateIndex.AddDays(30) });
dateIndex = dateIndex.AddDays(30);
}
}
public class DateBlock
{
public DateTime StartDate { get; set;}
public DateTime EndDate { get; set; }
}
You might have to check the edge case (today is exactly divisible by 30) to see it matches requirements.
Here is how you do it with linq (looks cooler, but slower)
void Main()
{
var startDate = new DateTime(2014, 1, 1);
var dates = new List<DateBlock>();
int priorPeriods = ((DateTime.UtcNow-startDate).Days) / 30;
dates = Enumerable.Range(0,6)
.Select(index => new DateBlock {
StartDate = startDate.AddDays((priorPeriods+index)*30),
EndDate =startDate.AddDays((priorPeriods+index+1)*30)
}).ToList();
}
public class DateBlock
{
public DateTime StartDate { get; set;}
public DateTime EndDate { get; set; }
}
-
\$\begingroup\$ Removed my answer (didn't see this post), this is effectively the same thing I was getting at, and the code works. \$\endgroup\$Mitchell Lee– Mitchell Lee2014年04月05日 15:09:13 +00:00Commented Apr 5, 2014 at 15:09
-
\$\begingroup\$ @MitchellLee - I added the linq version for you, not Aggregate but Range \$\endgroup\$Hogan– Hogan2014年04月05日 15:16:31 +00:00Commented Apr 5, 2014 at 15:16
-
\$\begingroup\$ I knew I didn't need the unnecessary loop for prior dates! I checked if the boundary was right on a multiple of 30 and it works. Thanks! \$\endgroup\$Ryan– Ryan2014年04月05日 15:56:26 +00:00Commented Apr 5, 2014 at 15:56
-
\$\begingroup\$ I expect you will have subtle errors.
DateTime
comparisons always compare the entire value:new DateTime(2014, 1, 1)
andDateTime.Now
will not be equal unlessNow
just happens to be midnight- down to the millisecond. UseStartDate.Date == DateTime.Now.Date
for example, which sets the time to midnight - thus essentially comparing only the DATEs. \$\endgroup\$radarbob– radarbob2014年04月15日 03:23:46 +00:00Commented Apr 15, 2014 at 3:23 -
\$\begingroup\$ @radarbob - there are no subtle errors, I tested this code. Look again, I'm using the
Days
field and only adding days to the DateTime inputs. \$\endgroup\$Hogan– Hogan2014年04月15日 04:10:44 +00:00Commented Apr 15, 2014 at 4:10