Storing dates in a list using c# - c#

I have two textboxes and a button, both textbox have calender attach to them. I want to store the dates which are between the first textbox and second textbox in a list, I am invoking following method on button click.
private void CollectDates()
{
DateTime StartDate = Convert.ToDateTime(txtFromDate.Text);
DateTime EndDate = Convert.ToDateTime(txtTillDate.Text);
List<DateTime> datelist = new List<DateTime>();
for (StartDate = Convert.ToDateTime(txtFromDate.Text); StartDate < Convert.ToDateTime(txtTillDate.Text); StartDate.AddDays(1))
{
datelist.Add(StartDate);
}
}
But I am getting error after storing the first date in the list: Exception of type 'System.OutOfMemoryException' was thrown.
I think my loop is running endlessly, any help will be appreciated.

DateTime.AddDays() does not change the datetime you must assign its return value. Like
StartDate = StartDate.AddDays(1)

It is indeed an infinite loop. You're stating that if the start date is less than the end date, add start date to the list. It'll keep doing this for infinity as start date should always (in theory) be less than the end date. The add days function isn't assigned to a variable so it never gets added to the start date.
Also another piece of advice with .Net datetime is to use the in-built compare function.
DateTime Compare function
Hope that helps!

Try this:
private void CollectDates()
{
DateTime StartDate = Convert.ToDateTime(txtFromDate.Text);
DateTime EndDate = Convert.ToDateTime(txtTillDate.Text);
List<DateTime> dateList = new List<DateTime>();
DateTime currentDate = StartDate;
while(currentDate <= EndDate)
{
dateList.Add(currentDate);
currentDate.AddDays(1);
}
}

use this
for (int i =0; i<(EndDate-StartDate).Days; i++)
{
datelist.Add(StartDate.AddDays(i));
}

you might want to try linq:
Enumerable.Range(0, (int)endDate.Subtract(startDate).TotalDays)
.Select(d => startDate.AddDays(d))
.ToList()

Related

How to get dates between two dates in C#

I would like to get dates between two dates. Instead of expected 9 different dates, I get 875287 and run out of memory. What would be the problem with the code below?
StartDate value is 01/04/2016 00:00:00
EndDate value is 10/04/2016 00:00:00
var selectedDates = new List<DateTime?>();
for (var date = StartDate; date <= EndDate; date.Value.AddDays(1))
{
selectedDates.Add(date);
}
You aren't assigning the value of date.Value.AddDays(1) to anything, so it ends up in an infinite loop. You'd need to change your code so that date is set to the result of AddDays.
for (var date = StartDate; date <= EndDate; date = date.AddDays(1))
{
selectedDates.Add(date);
}
LINQ solution (let's generate selectedDates):
var selectedDates = Enumerable
.Range(0, int.MaxValue)
.Select(index => new DateTime?(StartDate.AddDays(index)))
.TakeWhile(date => date <= EndDate)
.ToList();
As far as I can see, since AddDays method returns a new instance of a DateTime, it does not change the current instance since DateTime is immutable.
Looks like your date is DateTime?, you can change this part as;
for (var date = StartDate; date <= EndDate; date = date.Value.AddDays(1))
{
selectedDates.Add(date);
}
As usr pointed, this might be affected on DST. You might wanna check Dmitry's answer as well.
A shorter notation using Linq's Range method uses the ability to already figure out the number of days using the TimeSpan.Days property after subtracting start from end.
Assuming the start is before end you'd end up with:
DateTime StartDate = new DateTime(1979, 10, 4);
DateTime EndDate = new DateTime(2016, 10, 4);
var dates = Enumerable.Range(0, (EndDate - StartDate).Days + 1)
.Select(day => StartDate.AddDays(day))
If you need it to be Nullable, add:
.Cast<DateTime?>()
If you need this to be a List, add:
.ToList()
It's probably quite a bit more efficient than the other LINQ based solution.
Decided to change it up with a do/while
var selectedDates = new List<DateTime?>();
DateTime? StartDate = DateTime.Parse("01/04/2016 00:00:00");
DateTime? EndDate = DateTime.Parse("10/04/2016 00:00:00");
do
{
selectedDates.Add(StartDate);
StartDate = StartDate.Value.AddDays(1);
}while(StartDate < EndDate);

How do I populate a dropdown list with the past 30 days of dates

I am trying to populate a Dropdown list with the past 30 dates and I am receiving the error:
An exception of type 'System.OutOfMemoryException' occurred in mscorlib.dll but was not handled in user code
This is my function to fill the Drop Down List:
public void FillDates(int NumDaysBack)
{
for (DateTime d = DateTime.Now.AddDays(-NumDaysBack); d < DateTime.Now; d.AddDays(1))
{
ddMiscDateList.Items.Add(d.ToShortDateString());
}
ddMiscDateList.Items.Add("Other");
}
I am calling this function on load and using 30 for NumDaysBack. How can I write this more efficiently to not receive this error?
DateTime.AddDays() returns new instance of DateTime. It doesn't change d variable. Because of it you have infinite loop.
You can fix it
public void FillDates(int NumDaysBack)
{
for (DateTime d = DateTime.Now.AddDays(-NumDaysBack); d < DateTime.Now; d = d.AddDays(1))
{
ddMiscDateList.Items.Add(d.ToShortDateString());
}
ddMiscDateList.Items.Add("Other");
}
public void FillDates(int NumDaysBack)
{
for (DateTime d = DateTime.Now.AddDays(-NumDaysBack); d < DateTime.Now; d = d.AddDays(1))
//----------------------------------------------------------------------^^^^-fixed here
{
ddMiscDateList.Items.Add(d.ToShortDateString());
}
ddMiscDateList.Items.Add("Other");
}
When you call d.AddDays(1) it returns new instance of DateTime (without updating d)
Invoking d.AddDays(1) you are getting a new instance of DateTime i.e. you are not applying any changes to your DateTime d object. Therefore your loop never terminates and you end up running out of memory.
The solution is to write d = d.AddDays(1) instead.
From the MSDN documentation:
Returns a new DateTime that adds the specified number of days to the value of this instance.
Also, if you're only interested in arithmetic (in your case addition) on actual days, then you may want to omit the actual time part and instead use:
DateTime.Now.Date
or simplified:
DateTime.Today
You will still have the time part but it will be set to 00:00:00
DateTime Today Property:
An object that is set to today's date, with the time component set to 00:00:00.
Because it returns the current date without the current time, the Today property is suitable for use in applications that work with dates only.
Conversely if you only want to use the time of the day use DateTime.TimeOfDay which returns a DateTime object without the current day.
When generating sequences sometimes Enumerable.Range can be a good alternative.
Something like.
public void FillDates(int NumDaysBack)
{
ddMiscDateList.Items = Enumerable.Range(0, NumDaysBack).Select(x => DateTime.Now.AddDays(-NumDaysBack + x));
}

Array find all dates before current date

Hello I am currently trying to array.find all the dates before the current date. I have tried both using the datetime.now as well as creating a seperate variable for current date in my struct but i keep getting "Cannot implicitly convert type 'Assignment_3.Program.Hire' to 'System.DateTime". I'm sure the solution is quite simple but as a novice it does escape from me. If you need any more of the code I will be happy to provide
struct Hire
{
public int CustomerNo;
public int DVDNo;
public DateTime HireDate;
public int NoNights;
public DateTime CurrentDate = DateTime.Now;
}
DateTime result = Array.Find(hiredetails, Hire => Hire.HireDate <= Hire.CurrentDate);
Array.Find<T> returns the element matching the criteria. In you case since it is an array of Hire type, it will return element of type Hire, which you cannot assign to DateTime. You can do:
List<DateTime> allDates = hiredetails.Where(hire=> hire.HireDate <= hire.CurrentDate)
.Select(r=> r.HireDate)
.ToList();
You can also return IEnumerable<DateTime> and exclude ToList() from the above statement.
Not really sure if you need this but instead of keeping the current date inside the object you can have that in your local variable and pass that in your query like:
DateTime currentDate = DateTime.Now;
List<DateTime> allDates = hiredetails.Where(hire=> hire.HireDate <= currentDate)
.Select(r=> r.HireDate)
.ToList();
Do not store current date in a structure, use local variable instead, solution would look like:
var currentDate = DateTime.Now;
var result = hiredetails.Select(h => h.HireDate).Where(d => d <= currentDate);

Iterate between two dates in C#

I have two dates:
DateTime fromDate = new DateTime(2013,7,27,12,0,0);
DateTime toDate = new DateTime(2013,7,30,12,0,0);
I want to iterate from fromDate to toDate by incrementing fromDate with a single day and the loop should break when fromDate becomes equal to or greater than the toDate. I have tried this:
while(fromDate < toDate)
{
fromDate.AddDays(1);
}
But this is an infinite loop and won't stop. How can I do this ?
Untested but should work:
for(DateTime date = fromDate; date < toDate; date = date.AddDays(1)) {
}
Modify the comparison to <= if you want to include toDate as well.
DateTime.AddDays indeed adds the specified number of days to the date - but the resulting date is returned as a new DateTime value; the original DateTime value is not changed.
Therefore, make sure you assign the result of the your operation back to the variable you inspect in your loop condition:
while (fromDate < toDate)
{
fromDate = fromDate.AddDays(1);
}

Iterate over each Day between StartDate and EndDate [duplicate]

This question already has answers here:
How do I loop through a date range?
(17 answers)
Closed 6 years ago.
I have a DateTime StartDate and EndDate.
How can I, irrespective of times, iterate across each Day between those two?
Example: StartDate is 7/20/2010 5:10:32 PM and EndDate is 7/29/2010
1:59:12 AM.
I want to be able to iterate across 7/20, 7/21, 7/22 .. 7/29.
for(DateTime date = StartDate; date.Date <= EndDate.Date; date = date.AddDays(1))
{
...
}
The .Date is to make sure you have that last day, like in the example.
An alternative method that might be more reusable is to write an extension method on DateTime and return an IEnumerable.
For example, you can define a class:
public static class MyExtensions
{
public static IEnumerable EachDay(this DateTime start, DateTime end)
{
// Remove time info from start date (we only care about day).
DateTime currentDay = new DateTime(start.Year, start.Month, start.Day);
while (currentDay <= end)
{
yield return currentDay;
currentDay = currentDay.AddDays(1);
}
}
}
Now in the calling code you can do the following:
DateTime start = DateTime.Now;
DateTime end = start.AddDays(20);
foreach (var day in start.EachDay(end))
{
...
}
Another advantage to this approach is that it makes it trivial to add EachWeek, EachMonth etc. These will then all be accessible on DateTime.
You have to be careful about end-date. For example, in
Example: StartDate is 7/20/2010 5:10:32 PM and EndDate is 7/29/2010 1:59:12 AM.
I want to be able to iterate across 7/20, 7/21, 7/22 .. 7/29.
date < endDate will not include 7/29 ever. When you add 1 day to 7/28 5:10 PM - it becomes 7/29 5:10 PM which is higher than 7/29 2 AM.
If that is not what you want then I'd say you do
for (DateTime date = start.Date; date <= end.Date; date += TimeSpan.FromDays(1))
{
Console.WriteLine(date.ToString());
}
or something to that effect.
The loops of #Yuriy Faktorovich, #healsjnr and #mho will all throw a System.ArgumentOutOfRangeException: The added or subtracted value results in an un-representable DateTime
exception if EndDate == DateTime.MaxValue.
To prevent this, add an extra check at the end of the loop
for(DateTime date = StartDate; date.Date <= EndDate.Date; date = date.AddDays(1))
{
...
if (date.Date == DateTime.MaxValue.Date)
{
break;
}
}
(I would have posted this as a comment to #Yuriy Faktorovich's answer, but I lack reputation)
DateTime date = DateTime.Now;
DateTime endDate = date.AddDays(10);
while (date < endDate)
{
Console.WriteLine(date);
date = date.AddDays(1);
}

Categories