C# .Net Linq and converting datetime to formatted sting - c#

I have the query
var result = (from myView in db.loginSessions
where myView.machine.ToUpper().Equals(machine.ToUpper())
&& myView.start >= myStart
&& myView.end <= myEnd
orderby myView.start
select new loginSessionList {
Id = myView.id,
Machine = myView.machine.ToUpper(),
Start = myView.start.ToString("u"),
End = myView.end.ToString("u"),
User = myView.username
}).ToList();
I get ArgumentOutOfRange exceptions on the datetime conversions. I have tried different ToString conversion strings. I have tried the other To... date->string conversions offered by Intellisence. I have tried Convert.string(myView.start). Nothing has worked. I have googled and have found advice using all the things I have tried. Do I have to post-process the generated list?
What have I missed?

I have 3 rules for dealing with DateTimes that served me well:
Always store, retreive and transmit the UTC value. Translating into the proper local Timezone is the job of ToString(), wich asks Windows for the users timezone. You do not want to add timezones to your troubles.
Avoid store, retreive or transmission of DateTimes as strings. Keep it in proper types whenever possible
If you can not follow rule 2 (like when you deal with Serialsiation), at least pick a fixed Culture Format and String encoding on all endpoints. You do not want to get different Cultures or faulty implied Encodings to your existing troubles

So, the answer to my issue had nothing to do with Linq or .Net. #JoeEnos put me on the right track as mentioned in my comment to his comment. I had created a class to receive each row of query result. The date fields were initially DateTime types but I started having issues. I changed those fields to string and then ended up asking my question above.
Back when the receiving class still had the DateTime fields, all of the fields had lowercase names. I must have applied some sort of code formatting that CamelCased the field names. This meant that after serializing the results the CamelCased names could not be found and the javascript didn't care.
I fixed the field names in my js code, changed the field data types back to DateTime and all is good.
Thanks

Related

Is it good way to handle exception. i.e. using Try Block When You can actually handle the exception and recover from it?

User can enter dates in a format using / or - as a separator.
The following try block works for / but fails for - and vice versa:
Try
{
caseData.AddRange(
JsonConvert.DeserializeObject<List<CaseInfo>>(
jObject["caseData"].ToString(),
new JsonSerializerSettings { DateFormatString = "d/M/yyyy" }));
}
Catch(Exception)
{
caseData.AddRange(
JsonConvert.DeserializeObject<List<CaseInfo>>(
jObject["caseData"].ToString(),
new JsonSerializerSettings { DateFormatString = "d-M-yyyy" }));
}
Short answer: No.
A try-catch structure is pretty expensive in terms of resources. From a design point of view, it feels wrong too; an exception should be just that: an exception - something unusual, probably an error. The way you are using it here is just to check which of two valid formats to use.
In essence, what you are doing here is using exception handling as a computationally expensive if-else operation.
A better solution might be to try to extract the contents of jObject["caseData"] first, and check it's format explicitly to know which option to use. Once you know that, you can use a regular if-else structure to decide how to deserialize it.
Something like:
var dateText = jObject["caseData"].ToString();
var matchingFormat = dateText.Contains("/") ? "d/M/yyyy" : "d-M-yyyy";
caseData.AddRange(
JsonConvert.DeserializeObject<List<CaseInfo>>(
jObject["caseData"].ToString(),
new JsonSerializerSettings { DateFormatString = matchingFormat }));
Note: This assumes you are reasonably sure you can trust that the input will be in one of the two formats. You might want to add some more validation, especially if the date field is something that end-users can manipulate freely.
What #Kjartan said plus the following.
The DateFormatString solution may not work well if you have multiple date fields and the user inputs multiple dates in different formats.
Here are some options that I you could consider, all with pros and cons:
Have separate fields for year, month and day for each date;
Make the API accept only dates in a given format and make the provider of the source json deal with this;
Pre-parse the source data and format all dates;
Make CaseInfo store dates as string and provide accessors which make the conversion;
Create a custom JsonConverter, maybe based on DateTimeConverterBase, and mark your problematic properties with [JsonConverter(typeof(MyResilientDataFormatJsonConverter))].
General note: Parsing dates gets difficult quickly if you support multiple formats and/or cultures. For example: Is today 10/09/2019 or 09/10/2019?

How can I query Neo4j for nodes between dates in the standard web based client?

I have some nodes in a collection with a Date Time:
I query this using the C# cypher client thus:
GraphClient _client = new GraphClient(new Uri(url));
DateTime dt;
_client.Cypher
.Match("(e:LineStop)")
.Where((LineStop e) => e.AddedToDataWarehouse == false && e.TimeCreated >= dt)
.AndWhere((LineStop e) => e.Duration >0)
.Return<LineStop>("e")
.Results;
This works.
How can I do the same thing using the standard web based Neo4j Graph client? I can't seem to get the syntax to work at all.
All of the existing Q&As seem to talk about structuring the data differently to be more graph like and use shortestPath. I can't do this. The data already exists. I did not design this system nor do I have the abillity to change it.
I was told by the person that did design this system (a contractor who is no longer with the company) that Neo4j now supports dates(as opposed to stringfying them). On some level it must, or else how does the C# code work, right?
The C# code is treating the Dates as strings, if you look at what is being sent over the wire (using Fiddler), you'll see the JSON has it all escaped. Importantly, it's treating it as ISO format, which is sortable. If you chose to store them using US/UK format, you'd quickly find the comparison doesn't work.
The comparison is being done by Neo4j - example cypher showing the situation you have is here:
MATCH (n) RETURN
CASE WHEN ("2017-03-19T08:12:17.9680461+00:00" > "2017-03-20T08:12:17.9680461+00:00") = true
THEN "TRUE"
ELSE "FALSE"
END
If you put that into your browser, you'll get FALSE.
Your query isn't working as you are doing a string comparison and '2017-03-17' is not the same as the actual string you have created. Of the two options below - the adding of a property is the best route - and doesn't involve changing the structure of the graph, but obviously depends on the ability to set a property on the node.
If you can't add extra properties to the objects
To do a 'Between' style approach -
You have to pass in a fully defined DateTimeOffset string example: 2017-03-19T08:12:17.9680461+00:00
To do an equality comparison (with just the date specificied)
Use STARTS WITH as #InverseFalcon said
This is awkward as a full DTOffset string is long and unwieldy :/
If you can add a property
I would add a Ticks version of the DateTime properties, i.e. have a property called TimeCreatedTicks which is simply the .Ticks property of the TimeCreated property. This is my general route for storing Dates.
For manual querying this is still a pain as you need to know the Ticks for a given date - and that (for me at least) normally involves going to LinqPad and running new DateTime(2017,3,17).Ticks.Dump()
It looks like you need a string split function:
match (l.LineStop)-[:Creates]->(ls.LineStop)
where l.Name = 'M-E' AND
split(ls.TimeCreated, 'T')[0] = '2017-03-17'
return l, ls limit 100
In this case a STARTS WITH predicate should do the trick:
match (l.LineStop)-[:Creates]->(ls.LineStop)
where l.Name = 'M-E' AND ls.TimeCreated starts with '2017-03-17'
return l, ls limit 100

formatting dates incorrectly, trying to understand the reason

sorry if this question is a little ... strange, but I am a little lost to what is happening and how to control it. What I need to better understand is the following:
I have an ASP MVC application that works with Linq-To-SQL and an MSSQL server. The application is an inside (office only) website, and I am mentioning that so it wont sound that strange when I say that we wanted to ignore browser language, culture, date, whatever... settings and always display the date in the format "dd/MM/yyyy". Always.
So, now that I am testing a specific form in the website I encounter something very, very strange.
The first strange thing is that the date is not displayed on the screen correctly. Let me elaborate, I have a simple view that gets some data, read from the database, inside a model. So, as I fought for sometime with teaching the datetime object to display in a certain way on server level (meaning giving it an attribute like [Display(..)] or [DataType(...)] didn't force the date to look the way I want, so I simply wrote the following:
<input id="BirthDate" name="BirthDate" type="text" value="<%= Model.BirthDate.HasValue ? Model.BirthDate.Value.ToString("dd/MM/yyyy") : "" %>" class="text-box datepicker" />
However, even though I am specifically formatting the date to display "dd/MM/yyyy" in the input, it doesnt. When the browser settings are Dutch, the value inside this box is displayed with 'dd-MM-yyyy'.
I can somehow accept that, the browser is a smart guy(or gal) and identifies that the value in the box is a date and applies formatting according to the selected language settings. I don't know how to tell it not to screw with my dates, but I can get to believe that this is what happens. HOWEVER, what I am finding a lot difficult to accept is that THE Date formatting somehow goes back to the database. This sentance didnt really mean anything so I am explaining again. I have a table that has a few columns, one of them being a varchar(100). Super, and because of some very interesting designing, that field can contain text, dates and whatever.
So, because the field is a string, and later on I simply display it in a paragraph and dont need to do the whole dance of casting it to a DateTime object and then formatting it back when it gets in the view (which works so perfectly as I previously mentioned) I simply save it in the table in the correct format (dd/MM/yyyy).
Yea, but not really. My code would look like that:
var date = DateTime.Now;
db.EmployeeHistory log = new EmployeeHistory();
log.ActionType = 1;
log.EmployeeId = 1671;
log.At = date;
log.Context = "A TEST";
log.ObjectTitle = "Who cares";
log.EmployeeHistoryChangesSets.Add(new EmployeeHistoryChangesSet()
{ PropertyName = "TEST PROPERTY", NewValue = date.ToString("dd/MM/yyyy"), OldValue = date.ToString() });
dataContext.EmployeeHistories.InsertOnSubmit(log);
dataContext.SubmitChanges();
This is a of course a test, one that didnt make me happy at all. Because, if you are paying attention, there is a field in the database which is mapped to a string (varchar(...)) and then I am taking the Date, make it a string with the .ToString() method while formatting it into a "dd/MM/yyyy" format. So I am not using dates (well I am using a Date object to get the date, but I am converting it to a string) I am using only strings.
And somehow, for some reason that is truly escaping me, the string/date is saved in the database in the format: 'dd-MM-yyyy'. I really didnt expect it to behave in such a way. At first I was going to accept my fate, even though I was having a really hard time accepting that the database will take the liberty to format my input even though IT IS a string.
So, further testing showed me that the Date.ToString("dd/MM/yyyy") method actually returns the date in 'dd-MM-yyyy', depending on the browser language settings. Meaning that if I change my settings and it works correctly again ("dd/MM/yyyy").
So, my question is, what am I missing? Why is the .ToString() method not formatting the date correctly? Is my analisys correct or am I up and to the right on this one? If there is a good reason for that (even though I cant come up with one), should I just create my own extension method for DateTime class and implement the formatting mannualy or is there a better way?
I am really sorry for the long post (again). I would appreciate some clarity, as the whole project will behave this way. Thanks in advance

C#: Dateformat in C# for Inserting to sql server

I have a textbox with date format dd/MM/yyyy that I want to convert to the format yyyy-MM-dd to insert it into a database.
I tried
Convert.DateTime/DateTime.ParseExact
but it always give me the system's default date format.
I don't know any other method to convert it in C#...
You shouldn't be converting it to a string at all to insert it into your database. (I'm surprised at all the other answers which are recommending this approach.)
Instead, you should be using parameterized SQL, and set the value of the parameter to the DateTime value you've got. You should be using parameterized SQL anyway to avoid SQL injection attacks, and to keep your code and data separate. The fact that it avoids unnecessary string conversions (each of which is a potential pain point) is yet another benefit.
This part of your question suggests you've got a fundamental misconception:
I used Convert.DateTime/DateTime.ParseExact it always give me system date format.
Those methods will give you a DateTime. A DateTime doesn't have a format. When you call ToString you just get the default format for the current culture, but that's not part of the value. It's like with numbers - 16 and 0x10 are the same number, and the int doesn't "know" whether it's in decimal or hex; it's a meaningless concept.
All of this goes beyond your immediate problem, towards trying to keep your code base clean in terms of types. You should keep data in its most appropriate form for as much of the time as you possibly can, and make sure you understand exactly what that data means at all points. Conversions to other types (such as strings) for communication should be done only at API/system boundaries, and avoided even there if possible (e.g. using parameterized SQL as in this case).
There are many methods but none so useful and logical than using Parametrized SQL. Here's the Wikipedia page! For more information on Parametrized SQL statements, Visit this Coding Horror page!
There is actually no need to change it. This is just the display format, but the 'DateTime' object inside stays the same. Depending on how you want to insert, you can just use:
string dateValue = DateTime.Now.ToString("yyyy-MM-dd");
And insert this in your query string.
EDIT
But as Jon Skeet commented, building your query string manually like this should never be done. A cleaner approach like parameterized SQL or utilizing NHibernate should be your first concern.
Hope this works!
DateTime variable= Convert.ToDateTime(your date);
You can format it like this:
string sDateTime = Convert.ToDateTime(txtTextBox.Text).ToString("yyyy-MM-dd");
Edit
There are many ways to skin a cat when it comes to preparing information for entry into a database. My solution here answers the OP directly, however I very much acknowledge that there are better ways to do this.
I'd suggest reading through Jon Skeet's post on this page as well, as he raises some extremely valid points regarding the approach of the OP.
Hope that helps.

Data Annotation Phone Number Conversion

I want to gracefully convert phone number input from my users into a specific phone number format.
I would like convert this with a dataAnnotation, Just as
[dataType(dataType.Date)] displays a dateTime as a string
Ie:
0205938472 into +61205938472
02 0593 8472 into +61205938472
0593 8472 into +61205938472 (I will assume the area code from where
they live or if its a mobile)
02-0593-8472 into +61205938472
Etc, I also want to convert the other direction:
+61205938472 into 02 0593 8472 (Or whatever format i choose)
I want to do this to promote readability for the user but retain a strict data type in the database.
Questions
Is using a dataAnnotation in this manner considered bad practice?
How would I actually write the dataAnnotation( /However you would do it)?
(please include some code)
Edit: to clarify, i do not want someone to write the extension for me, I would just like an example of key pieces of code and implementation.
Please Note
These are Australia, New Zealand and internationally formatted
numbers being stored as internationally formatted numbers.
And International Formatted numbers being converted to Australia, New Zealand or internationally formatted depending on the user's location (which i can determine)
Depending on the UI you're using, you might be able to do this using a:
ASP.NET: Custom binding code (see example)
ASP.NET MVC: ModelBinder
WPF: CustomBinder
Windows Forms: Custom Converters/Editors
As parsing and formatting usually happens in the UI layer, I doubt you will find a solution that works at the data/model layer and which will work universally or which can do more than just validation.
In the data annotations namespace, there is a DataType.PhoneNumber which you can attach to your properties. Though you, yourself, remain responsible to do the parsing and the formatting using the appropriate display technology.
Data annotations and datatype are used for validation, not for converting values. The datatype is mostly used so that the validation knows where to start guessing.
2. That is asking too much for someone to code an extension like that, especially without showing any effort.
You can use DataTypeAttribute like so:
[DataType(DataType.PhoneNumber)]
public string PhoneNumber{get; set;}

Categories

Resources