Return DB results within Date Range - c#

In my view, I have an input and select tags for the user to enter a start and end date.
When submitted, The controller will search the Model/Database and return entries within the above range.
In my DB, the start and end dates are written as "nvarchars" and in my controller they are taken as strings
Code and Images for reference:
public ActionResult timePeriod(string time)
{
//Start: month, day, year End: month, day, year --> Numeric values
string[] times = time.Split(',');
string start = times[0] + " " + times[1] + " " + times[2];
string end = times[3] + " " + times[4] + " " + times[5];
//Sample code to test the start date
viewModel.Tasks = db.Tasks.Where(s => s.StartTime.Contains(start)).ToList();
}
a snippet of the Database values:
Are there any LINQ expression to do this?

As the dates are strings, you've nothing better other than using what you have suggested already:
viewModel.Tasks = db.Tasks.Where(s => s.StartTime.Equals(start)).ToList();
I would use Equals as that will be quicker for you. Using Contains is basically like doing a T-SQL LIKE which is much slower.
SELECT *
FROM Table
WHERE StartDate LIKE 'blah'
Using Equals will result in the following equivalent:
SELECT *
FROM Table
WHERE StartDate = 'blah'
Which is much more efficient.

Related

Sum hours from different formatted dates. C#

I have a problem. I need to sum hours worked in an office in a code. The dates i get from SQL server thats no problem but i have different formats. For example: 2019. 09. 23. 14:54:23, 2019.09.23 14:54:23 or 2019-09-23 14:54:23; And i want to sum hours worked in result. No matter the year. Heres the example:
try
{
string betölt = "SELECT * from munkaorak where";
if (cbTech.Text != "")
{
betölt += " Munkaszam='" + cbMunka.Text + "' AND Részfolyamat='" + cbRész.Text + "' AND TechKod='" + cbTech.Text + "'";
}
else if (cbRész.Text != "")
{
betölt += " Munkaszam='" + cbMunka.Text + "' AND Részfolyamat='" + cbRész.Text + "'";
}
else if(cbMunka.Text !="")
{
betölt += " Munkaszam='" + cbMunka.Text + "'";
}
betölt += " order by ID DESC";
MySqlCommand name = new MySqlCommand(betölt, kapcsolat);
kapcsolat.Open();
olvasó = name.ExecuteReader();
int összora = 0;
if (olvasó.HasRows)
{
while (olvasó.Read())
{
if (olvasó.GetString(7) != "Befejezés: ")
{
string[] aha = olvasó.GetString(6).Split(' ');
string kezdes = aha[4];
string[] kezd = kezdes.Split(':');
int kezdoido = Convert.ToInt32(kezd[0]) * 60 * 60 + Convert.ToInt32(kezd[1]) * 60 + Convert.ToInt32(kezd[2]);
int befejezoido = 0;
string aha22 = "";
if (olvasó.GetString(7).IndexOf('-') >= 0)
{
string[] aha2 = olvasó.GetString(7).Split(' ');
string befejezes = aha2[1];
string[] bef = befejezes.Split(':');
aha22 = aha2[0].Split('-')[2];
befejezoido = Convert.ToInt32(bef[0]) * 60 * 60 + Convert.ToInt32(bef[1]) * 60 + Convert.ToInt32(bef[2]);
}
else
{
string[] aha2 = olvasó.GetString(7).Split(' ');
string befejezes = aha2[4];
string[] bef = befejezes.Split(':');
aha22 = aha2[3];
befejezoido = Convert.ToInt32(bef[0]) * 60 * 60 + Convert.ToInt32(bef[1]) * 60 + Convert.ToInt32(bef[2]);
}
string dolgozott = "";
if (aha[3].Replace(".", "") == aha22.Replace(".", ""))
{
dolgozott = mpbolora(befejezoido - kezdoido);
összora += befejezoido - kezdoido;
}
else
{
dolgozott = mpbolora((86400 - kezdoido) + befejezoido);
összora += (86400 - kezdoido) + befejezoido;
}
string validalo = "";
try
{
string[] validal = olvasó.GetString(9).Split(' ');
validalo = validal[0] + " " + validal[1] + " " + validal[2] + validal[3] + validal[4] + " " + validal[5];
}
catch
{
validalo = olvasó.GetString(9);
}
string munkafolyamat = olvasó.GetString(3) + "-" + olvasó.GetString(4) + "-" + olvasó.GetString(5);
string[] sorok = { olvasó.GetString(2), dolgozott, olvasó.GetString(6).Replace("Kezdés: ", ""), olvasó.GetString(7).Replace("Befejezés: ", ""), olvasó.GetString(8), validalo, munkafolyamat };
var lv = new ListViewItem(sorok);
lvStat.Items.Add(lv);
}
}
}
else
{
kapcsolat.Close();
MessageBox.Show("Nincs adat!", "Figyelem");
}
kapcsolat.Close();
lblÖssz.Text = "Összesen ledolgozott órák: " + mpbolora(összora);
}
catch (Exception a)
{
MessageBox.Show(a.Message);
kapcsolat.Close();
}
kapcsolat.Close();
It worked but when different formats appeared its not working because '-' or spaces. Please help!
In C#, there is a bunch of methods provided to convert strings that contain date times in many formats into a unified DateTime object. These methods can recognize quite a few standard date time formats, and if yours differ from them, you can even provide your own.
DateTime.Parse() - Converts a string to a DateTime object. If operation fails, it'll thrown an exception.
DateTime.TryParse() - Converts a string to a DateTime object only if possible. Returns true if successful, and false if it fails.
DateTime.TryParseExact() - Converts a string that is in the specified format into a DateTime object. Returns true if successful, and false otherwise.
In your case, you can use DateTime.TryParse() (which is recommended over simply using DateTime.Parse() unless you're absolutely sure the format is correct) like so:
var dtStr1 = " 2019. 09. 23. 14:54:23";
var dtStr2 = "2019.09.23 14:54:23";
var dtStr3 = "2019-09-23 14:54:23";
DateTime.TryParse(dtStr1, out DateTime dt1);
DateTime.TryParse(dtStr2, out DateTime dt2);
DateTime.TryParse(dtStr3, out DateTime dt3);
Once converted to a DateTime object, it no longer has a format associated with it. It's a structure, and hence only has member variables and methods. So to calculate total hours etc. you can use provided methods.
Say you want to calculate time between day's work start and end. You can convert those into DateTime objects, then subtract one from the others which will give you a TimeSpam object.
var dtStrStart = "2019.09.23 08:23:12";
var dtStrEnd = "2019.09.23 16:17:28";
DateTime.TryParse(dtStrStart, out DateTime dtStart);
DateTime.TryParse(dtStrEnd, out DateTime dtEnd);
var diff = dtEnd - dtStart;
Now the TimeSpan object, which is diff here, will give you a bunch of properties with difference in hours, minutes etc.
The TimeSpan.Days, TimeSpan.Minutes etc will give you the time in days, minutes etc.
Console.WriteLine(diff.Days);
Console.WriteLine(diff.Hours);
Console.WriteLine(diff.Minutes);
Console.WriteLine(diff.Seconds);
Console.WriteLine(diff.Milliseconds);
Output:
0
7
54
16
0
The TimeSpan.TotalMinutes etc will give you the entire time period in respective units.
Console.WriteLine(diff.TotalDays);
Console.WriteLine(diff.TotalHours);
Console.WriteLine(diff.TotalMinutes);
Console.WriteLine(diff.TotalSeconds);
Console.WriteLine(diff.TotalMilliseconds);
Output:
0.329351851851852
7.90444444444444
474.266666666667
28456
28456000
And conversely, when you're storing data in the database, you must again use a standard format, such as datetime or datetime2. It's advised you use datetime2, more info here.
Your code should look more like this:
try
{
MySqlCommand name = new MySqlCommand("SELECT * from munkaorak WHERE Munkaszam=#m", kapcsolat);
name.Parameters.AddWithValue("#m", cbMunka.Text);
if (cbRész.Text != "")
{
name.CommandText += " AND Részfolyamat=#r";
name.Parameters.AddWithValue("#r", cbRész.Text);
}
if (cbTech.Text != "")
{
name.CommandText += " AND TechKod=#t";
name.Parameters.AddWithValue("#t", cbTech.Text);
}
name.CommandText += " order by ID DESC"; //is it really necessary?
MySqlDataAdapter da = new MySqlDataAdapter(name);
DataTable dt = new DataTable();
da.Fill(dt);
foreach(DataRow ro in dt.Rows){
string fromStr = ro["YOUR_FROM_DATE_COLUMN_NAME"].ToString();
//cope with dates in varying formats
//by replacing all non-numeric chars with nothing
fromStr = Regex.Replace(fromStr, #"[^0-9]", "");
//now our dates of [2019. 09. 23. 14:54:23], [2019.09.23 14:54:23] or [2019-09-23 14:54:23]
//just become 20190923145423
DateTime fromDt = DateTime.ParseExact(fromStr, "yyyyMMddHHmmss", CultureInfo.InvariantCulture);
string toStr = ro["YOUR_TO_DATE_COLUMN_NAME"].ToString();
toStr = Regex.Replace(toStr, #"[^0-9]", "");
DateTime toDt = DateTime.ParseExact(toStr, "yyyyMMddHHmmss", CultureInfo.InvariantCulture);
//total hours worked
(toDt - fromDt).TotalHours;
}
}
Hopefully that looks a lot simpler
Here you see no..:
Risky SQL injection hack possibility - don't concatenate values into your SQL, ever. Always concatenate a parameter in and then give a value to the parameter. Always
Difficult to read, lengthy string concatenation - looks terrible, always avoid it if you can
DB Connection opening and closing - micromanaging the database connection isn't necessary when using a dataadapter because it opens and closes for you
DataReader code full of magic numbers - GetString(7), hmmm.. was that the time in or time out? GetInt(4) - was it the age? The year? Here we get rid of all the datareader GetXX calls with their column ordinals and fill a DataTable (something like a 2D array) with rows that can be indexed by string names. It's still not as good as it can be (strongly typed DataTables are better) but it's a huge leap better than filling code with magic numbers, and working with everything in the most obscure, weakly typed way possible
Awkward time handling - it's gone in favour of Date parsing, because pulling strings to bits number by number, converting them to int, multiplying them by seconds and hours so they can be manipulated is tedious and hard to read - do away with it all by parsing these strings to the data types that they should have been stored as in the first place; you need to record the date and times that things happen at. Try your best to get that DB converted so these things are stored properly, and until then convert your strings to DateTime
Diffing dates using seconds: utilising TimeSpan calculations means no need to convert things to seconds, do crude math, drop all notions of time zones, or daylight savings changes etc; by using dates subtracted from each other you get a time period between those dates that takes things like daylight saving clock changes into account. Or even the ability to have one date that is tomorrow, or X days into the future. Might not matter for this app, but one day it could..
If you have MySQL 8 you can do the regex replace in the DB. Could even get the DB to diff and sum the dates.. We can't really make any recommendations on this point though because we don't know the column names

graphing non sequential data C# and mysql

I'm trying to display in a graph (Winforms/C#) the total amount from one column vs unit of time (in this case month) - so it would be a amount vs time graph. The problem is that the user would like the freedom of lets say - choosing the totals for January and June and compare them in a single graph (so the total for the month of January would be represented as a bar next to June's total's bar). I already capture the selected months (also, I have the graph control on the for) within a list but where I am really stuck is to build the mysql statement and its something like this
selectdataforGraph = "SELECT SUM(Amount_Net) AS Total FROM testingproject.incomeinformation WHERE date";
foreach (int month in selectedMonth) {
selectdataforGraph += "between '" + selected_year+ "-" + month +
"'-1 AND '" + selected_year + "-"+month+ "-31' AND";
}
I know it has some space missing and some quotation mark problems - already ran the query and I figured as much but I don't think the in-between would work because I don't know how to AND the next part of it so if a user picks May then August would be between 2007-5-01 and 2007-5-30 AND 2007-8-01 and 2007-8-30???
EDIT: didn't seem MySQL was your DB...
Definitely use a parameterized query! However... to fit in with what you have and so you can test it quickly...
I think I would use DATEPART rather than BETWEEN....
var selectdataforGraph = "SELECT SUM(Amount_Net) AS Total FROM testingproject.incomeinformation WHERE ";
var monthList = string.Join(",", selectedMonth);
selectdataforGraph += " YEAR(date) = " + selected_year;
selectdataforGraph += " AND MONTH(date) in (" + monthList + ")";

C# If statement where date is this month

string month = DateTime.Now.Month.ToString();
string CommandText = "SELECT slocref.slocname, partstuff.quantity, partstuff.currency, partstuff.postingdate" + " FROM partstuff INNER JOIN slocref ON partstuff.sloc = slocref.slocvalue";
This is the code to get date and month.
if (Regex.IsMatch(rdr["postingdate"].ToString(), "0" + month + "*"))
{
if (rdr["slocname"].ToString() == "Answer/Slatwall")
{
string quantity = rdr["quantity"].ToString();
string currency = rdr["currency"].ToString();
answertotalmonth += float.Parse(currency);
label100.Text = "$" + answertotalmonth.ToString("#,##0.00");
}
}
This is just an example of the code that is run by the if statement.
But the if statement needs to get all of the July information and add it up. So from 07/01/2012 to 07/31/2012. I cannot change the SQL because it messes up the rest of the program. I tried to get the current date, add the 0 in front of it, then use a wildcard.
Need a little direction on this if statement.
Let me clarify this post. The "postingdate" value comes from FileHelpers. Importing a text file by fixed width into these values. The postingdate value looks like "07/16/12"
So, I want to get this current month, and then if a postingdate value has that month's value, run the if statement code.
Why would you do this?
if (Regex.IsMatch(rdr["postingdate"].ToString(), "0" + month + "*"))
If rdr["postingdate"] is supposed to be a date, convert it to a date time and do a sensible comparison.
if(DateTime.TryParse(rdr["postingdate"].ToString(), rdrDateTime))
{
// proceed as planned
if (rdrDate.Month == DateTime.Now.Month)
{
// and so on.
}
}
Not sure I understand you problem correctly but why don't you just match the DataTime's month property:
if( date.Month == month)
{
//your code...
}
Also like mentioned above, you can parse the text as a date. But if you are just interested in just the month that may not be necessary.
Edit: As mentioned in the comments, you would have to check the year as well. So it would be better to pares as a full DateTime object.

Greater than is not working in CAML query

I want to retrieve records which the users are active n last modified date is greater than lastrun date, i wrote the following CAML but doesnt seem like working. Any help is much appreciated.
camlQuery.ViewXml
= "<View><Query><Where><And><Eq><FieldRef Name='Active'/>"
+ "<Value Type='Boolean'> " + 1 + "</Value></Eq><Gt>"
+ "<FieldRef Name='_DCDateModified'/><Value Type='DateTime'>"
+ lastUpdate + "</Value></Gt></And></Where></Query></View>";
I suppose it could be a Date formatting issue. You could attempt to:
1) explicit exclude of Time portion of DateTime
2) convert in advance your Date
like this:
...<Value IncludeTimeValue='False' Type='DateTime'>" + SPUtility.CreateISO8601DateTimeFromSystemDateTime(lastUpdate) +"</Value>

BindingSource Filter by date

I want to filter values from database based on date.
Date in a database contains values like this: 2008-12-28 18:00:00. And my class has a DateTime variable depending on which I want to filter. Ideally it would work like this:
myBindingSource.Filter = "DATE(myDateField) = myDateTime.Date" + adjusting myDateTime.Date format as needed.
But it throws an EvaluateException: "The expression contains undefined function call DATE()."
Although if I execute the SQL statement directly, I can use the DATE() function in filter.
P.S. I use MYSQL DB with the Connector/Net 5.2
How can I solve this problem?
Thank You all for suggestions.
The getSqlDate function is not needed. You can use String.Format() to format dates:
String.Format("{0:yyyy-MM-dd} 00:00:00", myDateTime)
OR
myDateTime.Date.ToString("yyyy-MM-dd") + " 00:00:00"
You could filter the binding source like this:
myBindingSource.Filter = String.Format("myDateField >= '{0:yyyy-MM-dd}' AND myDateField < '{1:yyyy-MM-dd}'", myDateTime, myDateTime.AddDays(1));
Thank you Tom H.
Yes, i wanted to eliminate the time portion of the datetime in the filter and your suggestion works perfectly.
I`ll leave the complete solution for others:
myBindingSource.Filter = "myDateField >= '" + getSqlDate(myDateTime) + "' AND myDateField < '" + getSqlDate(myDateTime.AddDays(1)) + "'";
where getSqlDate function is:
string getSqlDate(DateTime date) {
string year = "" + date.Year;
string month = (date.Month < 10) ? "0" + date.Month : "" + date.Month;
string day = (date.Day < 10) ? "0" + date.Day : "" + date.Day;
return year + "-" + month + "-" + day + " 00:00:00";
}
A correction to the answer:
Accoring to msdn
,to get the correct date
the mm in
yyyy-mm-dd
would have to be capitalized
like so;
yyyy-MM-dd
to get a correctly formatted date.
Is myDateField the name of the field in the dataset? I think you want an expression like this:
myBindingSource.Filter = "myDateField = " & myDateTime.Date.ToString()
Are you asking how to eliminate the time portion of the datetime in the filter? I'm not too familiar with MySQL, but if you use any kind of function that returns the date portion of a datetime then you are likely to kill any chance of using an index on that column for the query (existing or future index).
Your best bet is to create a filter on the front end that checks for a range that is only for your given filter date. For example:
myBindingSource.Filter = "myDateField >= " & <code to create a string representing 12AM of your date> &
" myDateField < " & <code to create a string for 12AM of the next day>
Sorry for not having exact code, but I'm a SQL developer and my lack of VB/C# skills would require me to take a lot more time to come up with the functions then it would probably take you. :)
For search between two date in DataGridView you can use this code :
BindingSource1.Filter = "F5 >= '" + maskedTextBox1.Text + "' And " + "F5 <= '" + maskedTextBox2.Text + "'";
BindingSource1 : my datagridview datasourc load in BindingSource1 .
F5 : name of your header column in datagridview .
maskedTextBox1 : for get first date .
maskedTextBox2 : for get second date .
Be successfull "Arn_7"
For search between two date in DataGridView you can use this code :
BindingSource1.Filter = "F5 >= '" + maskedTextBox1.Text + "' And " + "F5 <= '" + maskedTextBox2.Text + "'";
BindingSource1 : my datagridview datasourc load in BindingSource1 .
F5 : name of your header column in datagridview .
maskedTextBox1 : for get first date .
maskedTextBox2 : for get second date .
You will need to add signle quotes like this "'2021-09-26'".
myBindingSource.Filter = "myDateField = " + "'" + myDateTime.Date.ToString("yyyy-MM-dd") + "'"

Categories