Problems with date time and infinite loops - c#

I know there probably is a really an obvious answer to this question but why am I getting an infinite loop with this code?
(laterDate1 is later date than dateTime1 and laterDate2 is a later date than dateTime2)
while (dateTime1.CompareTo(laterDate1) <= 0)
{
DateTime dateTime2 = otherDateTime;
while (dateTime2.CompareTo(laterDate2) <= 0)
{
dateTime2.AddDays(1);
}
dateTime1.AddDays(1);
}
Thanks in advance for your help. (My brain is not working today)

dateTime1.AddDays(1); does not modify dateTime1. It returns new DateTime instance. You have to assign it back to your variable:
dateTime1 = dateTime1.AddDays(1);
The same applies to dateTime2.AddDays(2):
dateTime2 = dateTime2.AddDays(1);
btw, DateTime is a struct and is immutable, so every state-changing method returns new instance, instead of modifying the one you're calling it on. You should remember about that while working with DateTime.

Related

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));
}

C# DateTime evaluation problem

So I'm trying to figure out what I'm doing wrong with this logic. It seems straightforward and my breakpoints indicate that the evaulation in the 'if' statement is resolving as True, but sum.ppStart et al aren't getting 14 days added to them.
It's probably something simple, but any help would be appreciated.
//Determine the start/end days of each week of the pay period and retrieve a list of those entries
DateTime[] weeks = timeTools.calcPP(0);
DateTime today = DateTime.Now.Date;
if (today > weeks[3])
{
weeks[0].AddDays(14);
weeks[3].AddDays(14);
weeks[4].AddDays(14);
}
sum.ppStart = weeks[0];
sum.ppEnd = weeks[3];
sum.payDate = weeks[4];
AddDays returns a new instance of DateTime, the existing value is not changed, it is an immutable structure. When using the function, capture the result
DateTime myDate = ...
myDate = myDate.AddDays(14);
That is because you're not using the result of the AddDays method. The signature is
public DateTime AddDays(double days)
or so (see link). You need to do this:
weeks[0] = weeks[0].AddDays(14);
You need to assign the values:
if (today > weeks[3])
{
weeks[0] = weeks[0].AddDays(14);
weeks[3] = weeks[3].AddDays(14);
weeks[4] = weeks[4].AddDays(14);
}

DateTime.Now - first and last minutes of the day

Is there any easy way to get a DateTime's "TimeMin" and "TimeMax"?
TimeMin: The very first moment of the day. There is no DateTime that occurs before this one and still occurs on the same day.
TimeMax: The very last moment of the day. There is no DateTime that occurs after this one and still occurs on the same day.
These values would be helpful for filtering and doing date-related queries.
Here are two extensions I use to do exactly that.
/// <summary>
/// Gets the 12:00:00 instance of a DateTime
/// </summary>
public static DateTime AbsoluteStart(this DateTime dateTime)
{
return dateTime.Date;
}
/// <summary>
/// Gets the 11:59:59 instance of a DateTime
/// </summary>
public static DateTime AbsoluteEnd(this DateTime dateTime)
{
return AbsoluteStart(dateTime).AddDays(1).AddTicks(-1);
}
This allows you to write:
DateTime.Now.AbsoluteEnd() || DateTime.Now.AbsoluteStart()
or
DateTime partyTime = new DateTime(1999, 12, 31);
Console.WriteLine("Start := " + partyTime.AbsoluteStart().ToString());
Console.WriteLine("End := " + partyTime.AbsoluteEnd().ToString());
I'd use the following:
DateTime now = DateTime.Now;
DateTime startOfDay = now.Date;
DateTime endOfDay = startOfDay.AddDays(1);
and use < endOfDay instead of <= endOfDay. This will mean that it will work regardless of whether the precision is minutes, seconds, milliseconds, ticks, or something else. This will prevent bugs like the one we had on StackOverflow (though the advice was ignored).
Note that it is important to only call DateTime.Now once if you want the start and end of the same day.
try
//midnight this morning
DateTime timeMin = DateTime.Now.Date;
//one tick before midnight tonight
DateTime timeMax = DateTime.Now.Date.AddDays(1).AddTicks(-1)
If you are using this for filtering, as your comments suggest, it is probably a good idea to save DateTime.Now into a variable, just in case the date ticks over between the two calls. Very unlikely but call it enough times and it will inevitably happen one day (night rather).
DateTime currentDateTime = DateTime.Now;
DateTime timeMin = currentDateTime.Date;
DateTime timeMax = currentDateTime.Date.AddDays(1).AddTicks(-1)
One small tweak to hunter's solution above...
I use the following extension method to get the end of the day:
public static DateTime EndOfDay(this DateTime input) {
return input.Date == DateTime.MinValue.Date ? input.Date.AddDays(1).AddTicks(-1) : input.Date.AddTicks(-1).AddDays(1);
}
This should handle cases where the DateTime is either DateTime.MinValue or DateTime.MaxValue. If you call AddDays(1) on DateTime.MaxValue, you will get an exception. Similarly, calling AddTicks(-1) on DateTime.MinValue will also throw an exception.
You must be careful to use
(new DateTime()).AddDays(1).AddTicks(-1);
when it is passed to stored procedure.
It could happen that the value will be approximated to next day.
Like other answerers, I'm not quite sure what you're asking for, but incase you want the smallest possible time and the largest possible time, (not just in a day), then there's DateTime.MinValue and DateTime.MaxValue which return 1/1/0001 12:00:00 AM
and 12/31/9999 11:59:59 PM respectively.
I would advise that you look at this answer:
How can I specify the latest time of day with DateTime
If your original DateTimes also potentially include times, using the AddDays() method will add a full 24 hours, which may not be precisely what you want.
public static DateTime ToEndOfDay(this DateTime time)
{
var endOfDaySpan = TimeSpan.FromDays(1).Subtract(TimeSpan.FromMilliseconds(1));
return time.Date.Add(endOfDaySpan);
}
Please note that if you're passing this time to sql server you should use
dateTime.Date.AddDays(1).AddMilliseconds(-3);
See:
How do I get the last possible time of a particular day
DateTime.Today.AddDays(1).AddSeconds(-1);
Not very exact, but fixed my problems. Now we can use AddMilliseconds, AddTicks and etc. I think it will just vary on what would satisfy your need.

Variable Context Question

In the following code snippet, if I leave out the line of code that is surrounded by the /////'s, I get an error that reads: "Use of unassigned local variable CurrentDate". It seems a bit silly for me to just give CurrentDate an arbitrary value, is there a better way around this?
DateTime CurrentDate;
///////////////////////////
CurrentDate = DateTime.Now;
///////////////////////////
if(1==1)
{
CurrentDate = DateTime.Now.AddDays(1);
}
if(CurrentDate == DateTime.Now)
{
...
}
Don't do if (1 == 1)?
Seriously though if the compiler is giving you this error it's usually either because your code is wrong or it's because it's too complex and could be better expressed in another way where you don't need to access possibly unassigned variables.
Can you come up with a real world example where you get this error where there isn't an obvious solution by making a simple refactoring? This would make your question more answerable.
Having said that if you do run into one of these situations there are a few other approaches you could use:
DateTime CurrentDate = DateTime.MaxValue;
DateTime CurrentDate = default(DateTime);
DateTime? CurrentDate = null;
I like the last option because it expresses what you mean - that you don't know the value. It makes the code a little more verbose though as you have an extra level of redirection every time you wish to access a value. You can use the time spent typing .Value to consider whether or not you have correctly handled the situation where it could be null.
Also: Have you considered that the value of DateTime.Now could change between the first and second calls? That final if statement looks like it won't do what you intended.
You could do this:
DateTime CurrentDate;
if(1==1)
{
CurrentDate = DateTime.Now.AddDays(1);
}
else
{
///////////////////////////
CurrentDate = DateTime.Now;
///////////////////////////
}
if(CurrentDate == DateTime.Now)
{
...
}
This will eliminate the compiler error.
NOTE: in VS2008 this will compile:
if(1==1)
{
CurrentDate = DateTime.Now.AddDays(1);
}
//else
//{
/////////////////////////////
//CurrentDate = DateTime.Now;
/////////////////////////////
//}
if(CurrentDate == DateTime.Now)
{
//
}
why dont just assigned directly
DateTime CurrentDate = DateTime.Now;
The example is a bit convoluted, but, no, there isn't a better way around that.
You have to assign a value to a variable heading into a conditional block, even if you are sure that the block will always execute (the 1=1 in your example)
However, I would recommend against DateTime.Now as the initialization value, because it by some mirracle, the block does not execute, the situation should be easily detectable, and DateTime.Now sound way more real than DateTime.MinValue
I always set my objects to null so that it throws a null reference exception if a value is not created. However as Hans pointed out null doesn't work in this situation because in their infinite wisdom Microsoft decided to make DateTime not nullable. As such I normally use DateTime.MinValue since it gives me a specific value to check for and other than time traveling will always be in the past unlike DateTime.MaxValue which is coming up here for some of you archaic 32bit peeps.
Example
DateTime CurrentDate;
///////////////////////////
CurrentDate = DateTime.MinValue;
///////////////////////////
if(1==1)
{
CurrentDate = DateTime.Now.AddDays(1);
}
if(CurrentDate == DateTime.Now)
{
...
}

Constructing a DateTime one step at a time

I am trying to construct a DateTime in C# one step at a time, as in, the whole date not being in the constructor. I'm not understanding what is wrong though.
DateTime d = new DateTime((long)0);
d.AddYears(2000);
with that d.Years will still be equal to 1 though. Also, I must store the date as a long. So I can't just build the date with a huge constructor and I also can't have a persisting DateTime instance, so I dump it to a long and then restore it and I start with a value of 0. Am I suppose to start with a different value than zero?
what exactly is wrong?
A DateTime structure is immutable, meaning that its properties cannot change.
The AddYears method returns a new DateTime that you must use:
DateTime d = new DateTime((long)0);
d = d.AddYears(2000);
Probably off-topic, but if you need to persist your DateTime as a long then why not persist the value returned by its Ticks property.
You can then restore your DateTime instance by using the constructor that takes a ticks parameter:
// stage 1
DateTime dt = DateTime.MinValue.AddYears(2009);
PersistTicksToSomewhere(dt.Ticks);
// stage 2
long ticks = GetPersistedTicksFromSomewhere();
DateTime dt = new DateTime(ticks).AddMonths(8);
PersistTicksToSomewhere(dt.Ticks);
// stage 3
long ticks = GetPersistedTicksFromSomewhere();
DateTime dt = new DateTime(ticks).AddDays(20);
PersistTicksToSomewhere(dt.Ticks);
// etc etc
There are 12 different overloads for the DateTime constructor. There should be at least one you can adapt for your use.
This:
DateTime d = new DateTime(2000,0,0);
is better than:
DateTime d = new DateTime((long)0);
d = d.AddYears(2000);
Just construct as much of the date as you can up front and put in zeros for the other parameters.
DateTime is immutable so you must change it as so
DateTime d = new DateTime();
d d.AddYears(2000);
However this will instantiate a new DateTime 99.9% of the time this is fine but if it's nested in a loop that runs forever you're better off using one of the many DateTime constructors. Use the same rule of thumb as string and StringBuilder.

Categories