DbFunctions DiffDays Gives wrong answer - c#

I want to get a list from DataBase, where MyDate is today or tomarrow.
I wrote the following code.
_Log("Now: " + DateTime.Now.ToString());
var v = db_TS.TS_Test.Where(x => DbFunctions.DiffDays(x.MyDate,DateTime.Now) < 2);
foreach (var item in v.ToList())
{
_Log("MyDate: " + item.MyDate.ToString());
}
The following is logged:
Now: 11/08/2016 10:50:00
MyDate: 27/09/2017 09:35:00
Please help me to find what went wrong in the code?
Thank you

You should be doing DbFunctions.DiffDays(DateTime.Now,x.MyDate) since it's supposed to work like subtracting the first parameter from the second one, so in your case, the DiffDays is returning a negative number.
Summarizing it if you have DbFunctions.DiffDays(date1,date2)
and date1 > date2 the result will be < 0
and date1 < date2 the result will be > 0

Simplest approach is to check year, month, and day with the current date. Month and year should be the same. Day has to be the same for today and one day less for tomorrow:
var v = db_TS.TS_Test.Where(x => x.MyDate.Year == DateTime.Now.Year &&
x.MyDate.Month == DateTime.Now.Month &&
x.MyDate.Day >= DateTime.Now.Day - 1);
Edit
As pointed out this simplistic scenario won't work for edge cases.
Better option is to subtract a date from today and check what's the result in days. If it's tomorrow then the difference is 1 day or 0 if it's today.
var v = db_TS.TS_Test.Where(x => DateTime.Now.Subtract(x.MyDate).Days <= 1);

please check here from more info of datediff function.
Syntax
-- DATEDIFF ( datepart , startdate , enddate )
-- Example usage
SELECT DATEDIFF(DAY, GETDATE(), GETDATE() + 1) AS DayDiff
SELECT DATEDIFF(MINUTE, GETDATE(), GETDATE() + 1) AS MinuteDiff
SELECT DATEDIFF(SECOND, GETDATE(), GETDATE() + 1) AS SecondDiff
SELECT DATEDIFF(WEEK, GETDATE(), GETDATE() + 1) AS WeekDiff
SELECT DATEDIFF(HOUR, GETDATE(), GETDATE() + 1) AS HourDiff
You can play with here

Related

matrix report for leaves

I have no.of days, start date and end date stored in table to store no.of leaves of employees.
I want to create report in which user select start date and end date from calendar and report shows the data depending on date selected. But my problem is if the user select a date which is in between start date and end date, I want accurate no.of days for that particular employee.
for ex. the following data saved in database
no of days 3
start date 02/06/2016
end date 04/06/2016
user selected start date 03/06/2016 and end date 04/06/2016 from calendar.
The expected result is: no. of days 2
Please suggest a sql query or C# code
table structure
leaveId empid leavetypeId noofdays startdate enddate
1 76 1 3 2016-06-02 2016-06-04
query i fired like as follows
select noofdays
from table
where startdate='2016-06-03' and enddate='2016-06-04'
and expected result
noofdays = 2
Try following solution:
DECLARE
#pStartDate DATE = {d '2016-06-01'}, -- p = parameter
#pEndDate DATE = {d '2016-06-12'}
SELECT SUM(DATEDIFF(DAY, x.CommonRangeStartDate, x.CommonRangeEndDate) + 1) AS NumOfCommonDays
FROM (VALUES
(1, {d '2016-06-02'}, {d '2016-06-04'}),
(2, {d '2016-06-02'}, {d '2016-06-02'}),
(3, {d '2016-06-04'}, {d '2016-06-10'}),
(4, {d '2016-06-12'}, {d '2016-06-15'}),
(5, {d '2016-06-14'}, {d '2016-06-17'}),
(6, {d '2016-05-01'}, {d '2016-06-18'})
) s(LeaveID, StartDate, EndDate) -- I assume SD & ED's data type is DATE
CROSS APPLY (
SELECT
CASE WHEN s.StartDate >= #pStartDate THEN s.StartDate ELSE #pStartDate END AS CommonRangeStartDate, -- MAX
CASE WHEN s.EndDate <= #pEndDate THEN s.EndDate ELSE #pEndDate END AS CommonRangeEndDate -- MIN
) x
WHERE s.StartDate <= #pEndDate
AND #pStartDate <= s.EndDate
Note #1: Assumptions: StartDate <= EndDate, #pStartDate <= #EndDate
Note #2: If you want to see details then use SELECT * instead of SELECT SUM

How to find time differences between two time in c#

I have a form that gives me time_in and time_out hours of all staff members. Time_in and time_out also sql tables. Basically form returns the database table values. What I would like to do is to display the work hour of them. Work hour can be get the differences from time_out to time_in. I have two text boxes that display time in and Time_out. The third one should display work hour.
Here is what I have for time_out value for Wednesday:
//Selected TimeOutWednesday
SqlCommand TimeOutWednesdayMain = cs.CreateCommand();
TimeOutWednesdayMain.CommandText = "SELECT CONVERT(VARCHAR(8), time_out, 108) AS time_out FROM job_punch_card WHERE emp_key='" + listBoxNames.SelectedValue.ToString() + "'and punch_day= DATEADD(week, DATEDIFF(day, 0, getdate())/7, 2)";
Object TimeOutWednesdayMainTemp = TimeOutWednesdayMain.ExecuteScalar();
txtTimeInWed.Text = TimeOutWednesdayMainTemp.ToString();
This code gives me time_out for wednesday for the selected user from my listbox. I have the same code for time_in as well. What I couldn't do is to figure out how find the work hour? How can I display their work hour in a label or text box like I have above?
The DateTime types in OS are simples Integer values, you should make a arithmetical operation and get the Hours or TotalHours:
Hours get the integer portion of difference (dont lose parse your textboxes):
DateTime time_in;
DateTime.TryParse(time_in_TextBox.Text, out time_in);
DateTime time_out;
DateTime.TryParse(time_out_TextBox.Text, out time_out);
int hours = (time_in - time_out).Hours;
TotalHours get a double value with the exact difference in DateTimes:
DateTime time_in;
DateTime.TryParse(time_in_TextBox.Text, out time_in);
DateTime time_out;
DateTime.TryParse(time_out_TextBox.Text, out time_out);
double totalHours = (time_in - time_out).TotalHours;
I don't know if you're set on doing the time difference in SQL, but here's how you can do it in C# - though you would need to convert to a datetime object, not just a time (at least in this example).
See https://dotnetfiddle.net/DSuHmH :
using System;
public class Program
{
public static void Main()
{
DateTime startTime = new DateTime(2014, 1, 1, 1, 5, 1);
DateTime endTime = new DateTime(2014, 1, 1, 5, 10, 55);
TimeSpan ts = endTime - startTime;
Console.WriteLine(ts); // returns "04:05:54"
}
}
to specifically get the hours use:
ts.Hours;
To accomplish in sql you can do something like the following - again you'll need to convert your time to a datetime and then you can utilize the datediff function.
See: http://sqlfiddle.com/#!6/b7a7c/7
select convert(datetime, '2014-01-01 ' + startTime, 101),
convert(datetime, '2014-01-01 ' + endTime, 101),
datediff(
hh,
convert(datetime, '2014-01-01 ' + startTime, 101),
convert(datetime, '2014-01-01 ' + endTime, 101)
)
from test
Note that in the examples above i'm using an arbitrary date to accomplish creating a valid datetime
You should be able to do this in one query. This also shows the best practices for dealing with ADO.Net including putting your sql objects in using statements and passing values into your query as a parameter. Additionally you'll have to use ExecuteReader to get more than one value back and you can add checking for retrieving more or less than 1 row.
using (var cs = new SqlConnection("your connection string"))
{
cs.Open();
using (var command = cs.CreateCommand())
{
command.CommandText =
#"SELECT
time_in,
time_out,
DATEDIFF(minute, time_in, time_out) As minutesWorked
FROM job_punch_card
WHERE emp_key=#EMPKEY
and punch_day= DATEADD(week, DATEDIFF(day, 0, getdate())/7, 2)";
command.Parameters.AddWithValue(
"#EMPKEY",
listBoxNames.SelectedValue.ToString());
using (var reader = command.ExecuteReader())
{
if (!reader.HasRows)
{
// There was no match for your key
}
reader.Read();
DateTime timeIn = reader.GetDateTime(0);
DateTime timeOut = reader.GetDateTime(1);
int minutesWorked = reader.GetInt32(2);
if (reader.Read())
{
// There was more than one match on key
}
}
}
}
You can get the time difference, in minutes, using this:
DATEDIFF(MINUTE, #punch_day, #time_out)
This will return the total minutes between the two dates. If you need hours, divide it by 60. If you need days, then divide it by (60*24). Should you need weeks, divide it by (60*24*7). If you need years, divide it by (60*24*365). You get the idea, I hope!
Check out this example:
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SELECT #StartDate = '12/9/2014 11:04am'
SELECT #EndDate = '12/10/2014 1:38pm'
SELECT DATEDIFF(MINUTE, #StartDate, #EndDate) AS TotalMinutes,
DATEDIFF(MINUTE, #StartDate, #EndDate) / 60 AS TotalHours,
DATEDIFF(MINUTE, #StartDate, #EndDate) / (60*24) AS TotalDays

Query to display +- 2 days of data but return only selected date itself

I would like to send a MySQL query where I choose a date from my C# programming comboBox e.g. 04/06/2014. Then result should show +-2days including 04/06/2014 itself. i.e. result will ended up showing data from 02/06/2014 till 06/06/2014 (a total of 5 days) in my dataGridView. My MySQL command below shows only the data for 04/06/2014, can someone kindly correct my code? Any help would be much appreciated!
Note: Assuming the 04/06/2014 will be replaced by my C# code comboBox_stockDates.SelectedItem.ToString()
SELECT Prices_Date, Prices_Time, Prices_Open
FROM tableprices
WHERE Ticker_ID = 732
AND DATE_ADD(STR_TO_DATE('04/06/2014', '%d/%m/%Y'), INTERVAL - 2 DAY)
AND DATE_ADD(STR_TO_DATE('04/06/2014', '%d/%m/%Y'), INTERVAL - 1 DAY)
AND Prices_Date = STR_TO_DATE('04/06/2014', '%d/%m/%Y')
AND DATE_ADD(STR_TO_DATE('04/06/2014', '%d/%m/%Y'), INTERVAL + 1 DAY)
AND DATE_ADD(STR_TO_DATE('04/06/2014', '%d/%m/%Y'), INTERVAL + 2 DAY)
ORDER BY Prices_Date ASC, Prices_Time ASC;
Your SELECT filters only the column Price_Date and current date. This one should work for you:
SELECT Prices_Date,
Prices_Time,
Prices_Open
FROM tableprices
WHERE Ticker_ID = 732
AND Prices_Date >= DATE_ADD (STR_TO_DATE ('04/06/2014', '%d/%m/%Y'), INTERVAL -2 DAY)
AND Prices_Date <= DATE_ADD (STR_TO_DATE ('04/06/2014', '%d/%m/%Y'), INTERVAL +2 DAY)
ORDER BY Prices_Date ASC, Prices_Time ASC;
For using the indexes of your table effectively (if there are any) it's better to convert the dates before the query as Chris suggested.
Any reason you can't do the conversion in C#? Seems cleaner.
Then it'd be a select from table where date greater than or equal and date less than or equal.
C# Code:
var dt = DateTime.ParseExact(comboBox_stockDates.SelectedItem.ToString(), "dd/MM/yyyy", System.Globalization.CultureInfo.InvariantCulture);
var start = dt.AddDays(-2);
var end = dt.AddDays(2);
Then select:
SELECT prices_date,
prices_time,
prices_open
FROM tableprices
WHERE ticker_id = 732
AND ( prices_date >= [startdate]
AND prices_date <= [enddate] )
ORDER BY prices_date ASC,
prices_time ASC;
Will this not work for you?

Sql query with the current date

I've got a simple query where I want to put the current date
var query = #"
SELECT trainid, trainnum
FROM trains
WHERE CONVERT(varchar(10), trainstartdate, 104)=" +
" " +
// so that matches the '104' format
String.Format("{0:dd.MM.YYYY}", DateTime.Now) +
" " +
"ORDER BY trainnum";
But when running I get the error message:
Cannot call methods on numeric. .Net SqlClient Data Provider
How do I specify current date the right way?
Thanks!
Using GETDATE()
Effect:
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value
Using {0:dd.MM.yyyy}
Effect: none
Using CONVERT(varchar(20), GetDate(), 104)
Effect: that works!
Thanks!
Description
I would not convert to a varchar and doing string comparrisson. The performance is much better if you compare trainstartdate using the >= and <.
You can use the T-SQL getDate() method to get the current date.
getDate() returns the current datetime with the time. 2012-02-14 14:51:08.350
DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE())) return only the current date. `2012-02-14 00:00:00.000
DATEADD(dd, 1, DATEDIFF(dd, 0, GETDATE())) returns only the date of tomorow. 2012-02-15 00:00:00.000
Sample
var query = #"
SELECT trainid, trainnum
FROM trains
WHERE trainstartdate >=
-- today
DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
AND trainstartdate <
-- tommorow
DATEADD(dd, 1, DATEDIFF(dd, 0, GETDATE()))
ORDER BY trainnum"
Note:
If you want to be ANSI compliant, CURRENT_TIMESTAMP does the same.
More Information
MSDN - GETDATE (Transact-SQL)
MSDN - DATEDIFF (Transact-SQL)
MSDN - DATEADD (Transact-SQL)
Stackoverflow - CURRENT_TIMESTAMP vs GetDate()
var query = #"
SELECT trainid, trainnum
FROM trains
WHERE CONVERT(varchar(10), trainstartdate, 104)=
CONVERT(varchar(20), GetDate(), 104)
ORDER BY trainnum";
GETDATE() is all you need...
I think
String.Format("{0:dd.MM.YYYY}", DateTime.Now);
is returning the date with a dot, which makes SQL consider it as a number.
Try using
String.Format("{0:MM/dd/yyyy}", DateTime.Now);
with a / instead.
Change the format pattern of YYYY to small-case letters
{0:dd.MM.yyyy}
You need to be aware that GETDATE() returns the current date and time of day, not only today's date.
If you want to return rows matching today's date, you need to extract the date part. There are a number of ways to do this - e.g. with SQL Server 2008 you can use the DATE data type, but one general way that works with earlier versions of SQL Server is the following:
CONVERT(DATETIME, convert(VARCHAR(10),getdate(),101) )
You can then use the query:
SELECT trainid, trainnum
FROM trains
WHERE trainstartdate = CONVERT(DATETIME, convert(VARCHAR(10),getdate(),101) )
which will work provided you are sure that the date/time in the trains.trainstartdate column is a date only (time of day = 0).
If trainstartdate contains the start date/time, you can get all of today's trains as follows:
SELECT trainid, trainnum
FROM trains
WHERE trainstartdate >= CONVERT(DATETIME, convert(VARCHAR(10),getdate(),101) )
AND trainstartdate < DATEADD(dd,1, CONVERT(DATETIME, convert(VARCHAR(10),getdate(),101) ))
By doing it like this rather than converting to a string, you will take advantage of any index there may be on the trainstartdate column.
Try this .. YYYY should be small letter yyyy
String.Format("{0:dd.MM.yyyy}", DateTime.Now)

sql query problem

i want to compare two date and time with each other and
i want to select records that "StartTime" is greater than now time and the "StartDate" is greater than now date.
but output is not correct.thanks in advance.
my tabale'records are:
StartDate StartTime
-------------------------------
1389/07/11 11:04
1389/06/23 21:17
1389/06/23 21:32
1389/06/23 22:10
1389/06/26 12:34
1389/06/27 17:29
1389/06/27 18:13
1389/06/27 20:27
1389/06/28 09:41
1389/07/18 10:46
1389/07/05 22:00
1389/07/15 24:00
output is:
when the query is : (1)
SELECT StartDate, StartTime
FROM Proj
WHERE (StartDate < '1389/07/15 ') AND (StartTime <= '20:20 ')
StartDate StartTime
-------------------------------
1389/07/11 11:04
1389/06/26 12:34
1389/06/28 09:41
1389/07/18 10:46
output is:
when the query is: (2)
SELECT StartDate, StartTime
FROM Proj
WHERE (StartDate > '1389/07/15 ') AND (StartTime >= '20:20 ')
StartDate StartTime
-------------------------------
NULL NULL
the correct output should be:
StartDate StartTime
-------------------------------
1389/07/18 10:46
i use persian date.
Just taking what you have above and the description of your problem, the query should be:
select * from test where date>'2010/10/05' and time>='20:22'
If you post more details about your problem and the schema in which you're working we'll be able to help you more.
I want to select records that "time" is greater than now time and the "date" is greater than now date.
First off to get the current datetime (your now), you can use the SQL function GETDATE().
So if you happen to have a datetime column you could just do
SELECT * FROM Test WHERE LogDateTime >= GETDATE()
This will return every record in the table Test of which the datetime value inside the LogDateTime column is in the future.
Now, although it's a little bit more complicated, the same can be used when you have split the date and the time into separate columns.
SELECT * FROM Test
WHERE CONVERT(datetime, LogDate + ' ' + LogTime) >= GETDATE()
If LogDate or LogTime are nullable columns you could use ISNULL(<columnName>, <defaultvalue>) to be safe.
it solved:
SELECT StartDate, StartTime
FROM Proj
WHERE (StartTime < '20:20 ') AND (StartDate = '1389/07/15') OR
(StartDate > '1389/07/15')

Categories

Resources