Is this AddMonths(number) a valid way of adding month in C#? - c#

I know you can add months using AddMonths(number), but I was debugging code that doesn't assign the AddMonths(number) to a DateTime variable directly.
var dat = new DateTime(2015, 12, 31);
//I am sure this will add 6 months
dat = dat.AddMonths(6);
//I am not sure what this code does
dat.AddMonths(6);
Is the last sentence incorrect? I think it does nothing, but I am not sure.
If so, I want to understand why it does nothing and why is not marked as incorrect code in Visual Studio.
In .NET fiddle, it does nothing.

If you check the definition of the AddMonths methods, you will find the following:
public DateTime AddMonths (int months);
which means that the method is returning a new DateTime with added months.
The second call is just calling the AddMonths on the returned DateTime and you don't use the new returned value that's why it seems like nothing happened, so there is nothing invalid.
Try to run the below code, I think it will make everything more clear
using System;
public class Program
{
public static void Main()
{
var dat = new DateTime(2015, 12, 31);
//I am sure this will add 6 months
dat = dat.AddMonths(6);
Console.WriteLine(dat);
Console.WriteLine(dat.AddMonths(6));
Console.WriteLine(dat);
}
}
As a conclusion I will add that it doesn't make sense to call the DateTime.AddMonths(x) method without working with the returned value as it is not changing the DateTime that you are passing to it.

There are two line of code in the question: one with an assignment and one without. This line:
dat.AddMonths(6);
with no assignment, still creates a brand new DateTime value for six months after the existing dat value, just like the other line with the assignment. But then it throws the new DateTime value away. The value is returned from the method, but there's nothing waiting to receive it.

Related

List stored in a session wrapper remains with Count 0 although method called to add item into it

I am a beginner, learning ASP.Net, so apologies in advance if the codes are really messy, I am also still learning the sessions and some of the terms in .Net. Anyway, I am using session to retain values during postback. However, I think I am not coding them properly, I am having difficulty understanding the whole session in a list concept thingy, I understand how session works, but session and generic list is so confusing. Anyway, this is the code.
public class MySessionWrapper
{
private MySessionWrapper()
{
}
private static List<DateTime> _Week_1;
public static List<DateTime> A_Week_1
{
get
{
_Week_1 = (List<DateTime>) HttpContext.Current.Session["A_Week_1"];
if(_Week_1 == null)
{
_Week_1 = new List<DateTime>();
}
return (List<DateTime>)_Week_1;
}
}
public static void AddWeek1(DateTime add_date)
{
A_Week_1.Add(add_date);
}
}
//and I am calling it from here using something like this
if (weeknum == 1)
{
MySessionWrapper.AddWeek1(date1);
}
The thing is, I noticed that the MySessionWrapper.AddWeek1 method remains as 0 although there are values hitting the weeknum == 1. It goes to the session wrapper class does not add the value at all into the List. I would really need some guidance on understanding session with generic list and could someone point what exactly am I doing wrong here.
Hi guys, I have edited the code again like what Gaurav pointed out, but I am getting stuck again, this time the list has already been initialized but with a certain number of count in it. Maybe I can explain better what I want to do.
I have a drop down list that contains the months. So, if a user selects February, the program would actually divide the dates within the month into respective weeks, weekofDay being Monday. So for example, in February, it should be
Months -- Week Start Date ---- Week End Date
Week1 - 2/1/2019 12:00:00 AM - 2/3/2019 12:00:00 AM
Week2 - 2/4/2019 12:00:00 AM - 2/10/2019 12:00:00 AM
Week3 - 2/11/2019 12:00:00 AM - 2/17/2019 12:00:00 AM
Week4 - 2/18/2019 12:00:00 AM - 2/24/2019 12:00:00 AM
Week5 - 2/25/2019 12:00:00 AM - 2/28/2019 12:00:00 AM
So, this now works fine after the page load and I choose February, but again I would like to see for March and the page gets refreshed but the Week Start Dates remains at February ones, the Week End Dates gets updated accordingly.
Is this something to do with the sessions ?
I recommend rewriting your method like so:
public static List<DateTime> A_Week_1
{
get
{
var week1 = (List<DateTime>)HttpContext.Current.Session["A_Week_1"];
if(week1 == null)
{
week1 = new List<DateTime>();
HttpContext.Current.Session["A_Week_1"] = week1;
}
return week1;
}
}
I've ditched private static List<DateTime> _Week_1; since it's not useful or necessary.
If you need to, you can add a setter method to "reset" the value:
public static List<DateTime> A_Week_1
{
get
{
var week1 = (List<DateTime>)HttpContext.Current.Session["A_Week_1"];
if(week1 == null)
{
week1 = new List<DateTime>();
HttpContext.Current.Session["A_Week_1"] = week1;
}
return week1;
}
set
{
HttpContext.Current.Session["A_Week_1"] = value;
}
}
Then you can either reset it by setting A_Week_1 = null (thereby forcing the getter to create a new list next time you access the getter), or you can manually set it to a new list (e.g. A_Week_1 = new List<DateTime>();).
Of course, you could also "reset" by simply clearing the list: A_Week_1.Clear();

Restrict DateTime with a minimum date and time (not fall below 00:00)

I am using DateTime and it's methods like DateTime.AddMinutes etc.
Is there a way to make DateTime throw an Exception when adding a negative number of minutes/seconds etc that make the time fall beneath 00:00 and not turn the time to 23:59?
At Domain Model Level
At the domain model you could a Decorator/Wrapper class. Just use a class that has a private DateTime object and pass through every method of that object that remains unaltered and implement those that are altered, essentially just by writing:
public bool Equals(DateTime dt){
return this.dateTime.Equals(DateTime dt);
}
There are however a couple of issues with this:
In the above example you might want to compare your DateTime object with itself, but that won't be possible.
DateTime has certain attributes eg. its serializable that you may lose until adding a fair bit of time to this.
At Controller Level
Assuming you are implementing this in an applicatino with MVC setup, you probably have some validation within your controller. That should be able to handle these cases.
I'd recommend this approach, as you can reject any case where the Date part of the datetime does not match or is less than the original date.
You can try a extension method like so:
public static class MyDateTimeChecker
{
public static bool CheckTime(this DateTime dt, int minutes)
{
if (dt.Day > dt.AddMinutes(minutes).Day)
return false;
else
return true;
}
}
I placed Day since in your question you wanted to know if it would fall bellow 00:00 or back to the previous day at 23:59,so this is one way to go.
Then in your code you can use it like this:
DateTime dt = DateTime.Now;
if(dt.CheckTime(-1440))
{
//if true your negative number was in range
//so use it if you like.
}
else
}
//oops too much
}

Getting a nullrefence exception error c# asp.net mvc [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
I'm trying to build an array of valid id's by checking the last time they were active. I am right at the finish line and I'm getting a null exception error when I find an active device. "thestream" variable has the JSON in it and contains this:
{"domain":"d50fb707f9317","stuff":"comm","thing":"000780000001","m2m_raw":"{\"command\":100,\"current-flow\":25,\"cap-max\":1200,\"cap-remain\":339}","m2m_nestedkey":["System
Characteristics","Diagnostic Information","Diagnostic
Information2","System Settings","Valve
Settings"],"clock":0,"attributes":{"current-flow:clock":"1401480786291382","weight":"150","cap-max":"1200","myname":"valve12","current-flow":"25","command":"100","hello:clock":"1401201915442520","myname:clock":"1401276113497347","cap-remain:clock":"1401480786291382","hello":"there","cap-max:clock":"1401480786291382","command:clock":"1401480786291382","cap-remain":"339","weight:clock":"1401275692557475"}}
My Model has this declaration in it:
public class ListofDevices
{
public long[] Devices { get; set; }
}
It is declared in the controller like this:
var TheList = new ListofDevices();
activeCount is declared and set to zero:
byte activeCount = 0; //(the highest number in here is 36)
All of the code below is in the controller.
JObject CheckIt = JObject.Parse(thestream); // parse the Json as best as we can, given the json we are getting back
string ClockNumString = (string)(((Newtonsoft.Json.Linq.JValue)((((((Newtonsoft.Json.Linq.JContainer)(CheckIt)).Last).First).First).First)).Value);
long ClockNum = Convert.ToInt64(ClockNumString); // convert the string into a number
ClockNum = ClockNum / 1000000; // convert to seconds
TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1); // get the current epoch time
long secondsSinceEpoch = (long)t.TotalSeconds; // convert to seconds for comparison
if ((secondsSinceEpoch - ClockNum) < 60000) {
TheList.Devices[activeCount] = Convert.ToInt64(uniqueitems[i]); // ERROR IS HERE
activeCount++;
}
My crazy Newtonsoft.Json.Linq command is due to the fact that the JSON that is coming back can't be handled any other way. The data I'm getting into ClockNumString is correct. But I'm getting the NullRefenceException error when I try to store the item into the active array, that passes the if statement. It appears to be a type error(?), but I've scoured stackoverflow for assistance and have been working on this all day, but no luck. Any help greatly appreciated.
Devices from TheList as not been initialized, and/or uniqueitems as not been initialized, use new to initialize an object or an array, ie:
TheList.Devices = new long[N];

Increment DateTime Variable

I'm trying to create a loop where my date increments by 1 month while it's in the for loop. Currently It's only displaying today's date. And is not incrementing. I want to change the display date to selected display date instead of today/default
for (int i = 1; i <= 15; i++)
{
DateTime initialdate = InitialDate.DisplayDate;
InitialDate.DisplayDate.AddMonths(1);
initialdate = InitialDate.DisplayDate;
}
I didn't show any of the initialdate being used because I don't think it's necessary.
InitialDate is a DateTimePicker
Initialization of the Datepicker
<DatePicker x:Name="InitialDate"></DatePicker>
Problem : You need to assign the return value of the InitialDate.DisplayDate.AddMonths(1).
From MSDN: DateTime.AddMonths()
Returns a new DateTime that adds the specified number of months to the
value of this instance.
Replace This:
InitialDate.DisplayDate.AddMonths(1);
With This:
InitialDate.DisplayDate = InitialDate.DisplayDate.AddMonths(1);
DateTime.AddMonths doesn't change the value you call it on - it returns a new value. This is true of all the DateTime methods. There's nothing which changes the value in place, which is a good job as it's a value type and changes would be lost anyway if they were made to a copy of the variable (e.g. due to being called on the value returned by a property).
You want:
InitialDate.DisplayDate = InitialDate.DisplayDate.AddMonths(1);
Assuming you use initialdate in the rest of the body of the loop, it would be clearer if you just declared it after the increment:
for (int i = 1; i <= 15; i++)
{
InitialDate.DisplayDate = InitialDate.DisplayDate.AddMonths(1);
DateTime initialDate = InitialDate.DisplayDate;
// Use initialDate here
}
(I've renamed the variable to have a capital D for the sake of convention.)
do this:
DateTime initialdate = InitialDate.DisplayDate.AddMonth(1);
You problem stems from the fact that InitialDate.DisplayDate.AddMonths(1); returns a new DateTime rather than modifying the instance it's being called on. You do nothing with the return value emitted by that call. Instead you want;
InitialDate.DisplayDate = InitialDate.DisplayDate.AddMonths(1);
Just FYI you will see this a lot in C#. I would say more often than not, methods that would change the values of an object return a new instance rather than mutating the instance they're called on.

Checking if Var from LINQ query is Null and returning values older than x

Hello everyone I'm currently having 2 issues with the code below:
Upon return of result1 I'm trying to complete a check to see if it is != null and if it is't it will begin to delete the records selected. The issue is that even when result1 returns nothing and defaults the if statement doesn't pick this up so I guess I'm missing something but what?
I'm wishing to return only values which are over 10 mintues old (this will later be scaled to 12 hours) to do this I'm checking against a.DateTime which is a DateTime value stored in a database. However if i use the <= or >= operators it doesn't work so again what am I missing?
DateTime dateTime = DateTime.Now.Subtract(new TimeSpan(0, 0, 10, 0));
var result1 = (from a in cpuInfo
where a.DateTime <= dateTime
select a).DefaultIfEmpty(null);
if (result1 != null)
{
foreach (TblCPUInfo record1 in result1)
{
localDB.TblCPUInfo.DeleteOnSubmit(record1);
localDB.SubmitChanges();
}
}
Philippe has talked about the sequence side of things - although you don't even need the call to Any(). After all, if there are no changes the loop just won't do anything.
Do you really want to submit the changes on each iteration? It would probably make more sense to do this once at the end. Additionally, you can use DateTime.AddMinutes to make the initial "10 minutes ago" simpler, and if you're only filtering by a Where clause I'd use dot notation.
After all these changes (and making the variable names more useful), the code would look like this:
DateTime tenMinutesAgo = DateTime.Now.AddMinutes(-10);
var entriesToDelete = cpuInfo.Where(entry => entry.DateTime <= tenMinutesAgo);
foreach (var entry in entriesToDelete)
{
localDB.TblCPUInfo.DeleteOnSubmit(entry);
}
localDB.SubmitChanges();
Now, as for why <= isn't working for you... is it possible that you need the UTC time instead of the local time? For example:
DateTime tenMinutesAgo = DateTime.UtcNow.AddMinutes(-10);
If that still isn't working, I suggest you have a look at the generated query and play with it in a SQL tool (e.g. Enterprise Manager or SQL Server Management Studio) to work out why it's not returning any results.
DefaultIfEmpty will return a single item with the content you provided, so in your case a collection with a single value "null".
You should check for elements in the collection using the Any() extension method. In your case:
DateTime dateTime = DateTime.Now.Subtract(new TimeSpan(0, 0, 10, 0));
var result1 = from a in cpuInfo
where a.DateTime <= dateTime
select a;
if (result1.Any())
{
foreach (TblCPUInfo record1 in result1)
{
localDB.TblCPUInfo.DeleteOnSubmit(record1);
localDB.SubmitChanges();
}
}
But if this is really your code, you can skip the Any() check completely, because the foreach loop will not run if there are no elements in result1.

Categories

Resources