Any reason why a sql converted date is converted wrongly? - c#

I'm using the following code:
sqlcom.CommandText = "SELECT * FROM myTable"
+ " WHERE CAST(myTime AS DATE) >= CAST(#mySTime AS DATE)"
+ " AND CAST(myTime AS DATE) <= CAST(#myETime AS DATE)"
+ "order by myTime ";
sqlcom.Parameters.AddWithValue("#mySTime", stime);
sqlcom.Parameters.AddWithValue("#myETime", etime);
stime and etime are both DateTime columns. The following is an abbreviation of the code that sets them:
sTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 0).AddDays(-1);
eTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 0).AddDays(-1).AddDays(1).AddMilliseconds(-1);
Which for example leads to:
sTime = '2015-10-19 00:00:00';
eTime = '2015-10-19 23:59:59';
when displayed in the debugger (stime and etime have a few other options how they could be set that is why the sql is dynamically taking them in but in this current case the above holds true).
Now when I run the above SQL I get everything even from the current day!
BUT when I change AS DATE to AS DATETIME it works as intended that I just get the LAST day and nothing from today.
Now my question is: Is there any reason why the original sql/date comparison fails? (could it be because of that it is just the millisecond -1 that it rounds it up to the next day? OR is there any other reason there?)

eTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 0).AddDays(-1).AddDays(1).AddMilliseconds(-1);
Why are you using .AddDays(-1).AddDays(1). It seems useless.
.AddMilliseconds(-1)
Your data type is datetime. datetime has an accuracy of 3ms with increments of .000, 003 or .007 seconds.
Therefore, any of these 3 values minus 1 (ms) is always rounded back to the original value:
xxx.000 - .001 = .999 => rounded to .000
xxx.003 - .001 = .002 => rounded to .003
xxx.007 - .001 = .006 => rounded to .007
This seems useless as well.
Round up
'2015-10-19 23:59:59' won't be rounded but '2015-10-19 23:59:59.999' will be round up to '2015-10-20 00:00:00.000' because 999 is surrounded by 997 and 000. 000 is the closest value.
<= 18-10-2015 23:59:59
You will miss any time above 23:59:59.000 and below of equal to 23:59:59.997
CAST(myTime AS DATE)
This will most likely prevent the usage of index on myTime. It should not be used.
It is fine to stick to datetime although datetime2 would be a better choice. If you are looking for value on a specific day, you must look for value between DAY at 00:00:00 and the next day at 00:00:00.
You can find a lot of useful information about date comparison on most of the answer here, including my own anwser: Why does my query search datetime not match?

Related

Round up DateTime

For my SteamBot I want to store the date and the time when the item is tradable again.
Example:
// DateNow = 05.06.2019 13:37:00
(+ 7 days due to Steam's trade policy)
// DateNow+7Days = 12.06.2019 13:37:00
// DateIneed = 13.06.2019 09:00:00
So the DateTime I need is CurrentDateTime + 7 Days + The rest to 9 o'clock
This is how far I come:
var date = DateTime.Now.AddDays(7);
Is there any smart way to always get the DateTime I need?
Language is C#
You can check if it is before 9 o'clock today, then set the time to 9, else add one day and set the time to 9, should be fairly easy I think.
var time = DateTime.Now;
var date = time.Hour <= 9
? time.Date.AddDays(7).AddHours(9)
: time.Date.AddDays(7).AddHours(9).AddDays(1);
The DateTime.Date field exposes just the date of a DateTime, you can then add an arbitrary TimeSpan to that to set the time of a DateTime object to whatever you want;
DateTime.Now.AddDays(7).Date.Add(new TimeSpan(9, 0, 0))
Check it out in action here: https://dotnetfiddle.net/l3X37y
Given the hour of the day may be past 9AM already, it's possible to end up with a DateTime less than 7 days, to counter this you can check if the hour of the day exceeds what you're going to set the DateTime to and add a day if it does, like so;
DateTime dt = DateTime.Now.AddDays(7);
dt = dt.Date.Add(new TimeSpan(dt.Hour >= 9 ? 1 : 0, 9, 0, 0))
See this one in action here: https://dotnetfiddle.net/lfVGis

Change the time forward

I am getting dates from the database and for each date I want to change the time forward starting from the DateTime that was obtained from the database until I get to a given Fixed Time (Y). However, (Y) might be in the next day.
For example if the date from the database is [7/6/2017 5:00:00 AM] and the given Fixed Time is 10:00 PM then I want to get [7/6/2017 10:00:00 PM].
However if the fixed time is 02:00 AM then I want to get [7/7/2017 02:00:00 AM] (notice that the date has increased by one)
Note: The code is running, but I modified the code to make it shorter and make more sense. Thus, there might be syntax or spelling mistakes.
My first solution was something like this:
private DateTime setTimeForeward(DateTime date) {
DateTime today = DateTime.ParseExact(FixedTime, "hh:mm tt", CultureInfo.InvariantCulture);
TimeSpan difference = today.TimeOfDay - date.TimeOfDay;
return date + difference;
}
That didn't work as expected when the fixed time is 02:00 AM. The difference becomes negative( it doesn't go around the clock) and the date will be [7/6/2017 02:00:00 AM].
I ended up with the following code
private DateTime setTimeForeward(DateTime date) {
DateTime today = DateTime.ParseExact(FixedTime "hh:mm tt", CultureInfo.InvariantCulture);
TimeSpan difference = today.TimeOfDay - date.TimeOfDay;
if (difference.Hours < 0) {
difference += new TimeSpan(24, 0, 0);
}
return date + difference;
}
I am not sure if my function is logically correct and I feel like I am overthinking it. Also,I am not sure if there's a better way or a built in function that does what I want for me. Basically, I am looking for a correct and an elegant solution.
Thank you very much in advanced.
In this method, I'm using DateTime fixedTime to represent a time. I don't really care about it's Day, Month, and Year values.
static DateTime GetClosingTime(DateTime fixedTime, DateTime dbTime)
{
var cutoff = new DateTime(dbTime.Year, dbTime.Month, dbTime.Day, fixedTime.Hour, fixedTime.Minute, fixedTime.Second);
if (dbTime < cutoff)
return cutoff;
else
{
cutoff = cutoff.AddDays(1);
return cutoff;
}
}
Here's calling it with your provided example input.
var FixedTime10PM = new DateTime(1, 1, 1, 22, 0, 0);
var FixedTime02AM = new DateTime(1, 1, 1, 2, 0, 0);
var dbTime = new DateTime(2018, 6, 20, 5, 0, 0);
var dt1 = GetClosingTime(FixedTime10PM, dbTime);
var dt2 = GetClosingTime(FixedTime02AM, dbTime);
Console.WriteLine(dt1.ToLongDateString() + " " + dt1.ToLongTimeString());
Console.WriteLine(dt2.ToLongDateString() + " " + dt2.ToLongTimeString());
And here's my output:
EDIT:
Simplified method based on suggestions in comments:
static DateTime GetClosingTime(DateTime fixedTime, DateTime dbTime)
{
var cutoff = new DateTime(dbTime.Year, dbTime.Month, dbTime.Day, fixedTime.Hour, fixedTime.Minute, fixedTime.Second);
return dbTime < cutoff ? cutoff : cutoff.AddDays(1);
}
Your logic is almost right but you shouldn't be checking for difference.Hours because there might be a difference in minutes (or even seconds if you changed the format later).
I adjusted your function and changed some variable names to make them easier to follow:
private DateTime SetTimeForward(DateTime originalDate)
{
TimeSpan newTime = DateTime.ParseExact(FixedTime,
"hh:mm tt",
CultureInfo.InvariantCulture).TimeOfDay;
TimeSpan diff = newTime - originalDate.TimeOfDay;
if (diff.Ticks < 0)
diff = diff.Add(new TimeSpan(24, 0, 0));
return originalDate.Add(diff);
}
Some remarks:
If your FixedTime is really fixed, you might want to store it directly as a TimeSpan so you don't have to parse it every time.
If you parse the FixedTime because it's changeable, you might pass it as a second argument instead:
private DateTime SetTimeForward(DateTime originalDate, string fixedTime)
Or:
private DateTime SetTimeForward(DateTime originalDate, TimeSpan newTime)
The current implementation does not change the date value if the newTime is equal to originalDate.TimeOfDay. I.E., If the originalDate is 7/6/2017 2:00 AM and the FixedTime/newTime is 02:00 AM, the returned date will be equal to the originalDate. If that's not your desired behavior, you might change diff.Ticks < 0 to diff.Ticks <= 0.
Slightly different approach:
private DateTime setTimeForeward(DateTime date)
{
var targetTimeOfDay = TimeSpan.ParseExact(FixedTime, "hh:mm tt", CultureInfo.InvariantCulture);
if (targetTimeOfDay < date.TimeOfDay)
{
date = date.AddDays(1);
}
return date.Date + targetTimeOfDay;
}
I'm getting target time as TimeSpan from the beginning instead of creating DateTime and getting TimeOfDay (which is TimeSpan).
Then I check if the target time of day is lower than time to be modified and if it is I add one day.
I use date.Date + targetTimeOfDay as return value as date.Date will return date with time set to 00:00 and adding target time to it will already set the target hour without calculating the difference.

How do i get the minutes part when i subtract two time values

I want minutes part when i subtract two time values.
I am subtracting current time with 11:30 PM and the result i need in minutes.
I am trying the following code in c#.
TimeSpan eTs = new TimeSpan(23, 30, 00);
int min = System.DateTime.Now.Minute - eTs.Minutes;
but its giving wrong values.
Any help?
Thanks in advance.
It gives wrong value because you are substracting ints. It could even give negative numbers. You should substract the TimeSpan from the DateTime, which gives you another DateTime and use it's Minute property.
var eTs = new TimeSpan(23, 30, 00);
var min = (System.DateTime.Now - eTs).Minute;
EDIT
I am subtracting current time with 11:30 PM and the result i need in
minutes.
No, you are substracting 23 hours and 30 minutes from the current date time.
If you want to know how much minutes have passed since 11:30 PM (what day/month/year), you should:
var min = (System.DateTime.Now - somePastDate).TotalMinutes; //somePastDate must be a DateTime
Do you wanna subtract 2 dateTime and Get the total in minutes try this:
DateTime data = DateTime.Now;
DateTime data2 = DateTime.Now.AddDays(-2);
TimeSpan sub = data - data2;
Console.WriteLine(sub.TotalMinutes);
Or If you wanna subtract minutes from a datetime try this
TimeSpan eTs = new TimeSpan(23, 30, 00);
DateTime data2 = System.DateTime.Now.AddMinutes(-eTs.TotalMinutes);
Console.WriteLine(data2);

How do I subtract a time from another in c#?

I've simplified my code down to this:
string when = "03/03/15 12:00 18:00";
string difference = Convert.ToString(Convert.ToDateTime(when.Substring(when.Length - 5, 5)) - Convert.ToDateTime(when.Substring(when.Length - 10, 10))).substring(difference.Length - 5, 5);
But it's still very complex and also doesn't work :/
Basically I want the string difference to equal 6 because 18 - 12 is 6. It needs to be a little bit more complex because I want to evolve minutes too.
Am I being an idiot? Is it easy?
Just convert your string to a couple of valid DateTime values, and subtract them.
The Hours property will give you a representation of the difference in whole hours, in this case 6.
string when = "03/03/15 12:00 18:00";
string[] portions = when.Split(); // 3 items: "03/03/15", "12:00", "18:00"
string yourDateTimeFormat = "MM/dd/yyHH:mm"; // or "dd/MM/yyHH:mm" if the day is first
// create a valid date from 03/03/15 and 12:00
DateTime fromTime = DateTime.ParseExact(
portions[0] + portions[1], yourDateTimeFormat, CultureInfo.CurrentCulture, DateTimeStyles.None);
// create a valid date from 03/03/15 and 18:00
DateTime toTime = DateTime.ParseExact(
portions[0] + portions[2], yourDateTimeFormat, CultureInfo.CurrentCulture, DateTimeStyles.None);
int differenceInHours = (toTime - fromTime).Hours;
Depending on how much control you have over the input, you may want to add additional logic for checking that the date is valid, or consider using DateTime.TryParseExact instead.

subtract 2 datetime fields to get the days left difference

Would appreciate it if anyone can help me figure out to substract 2 datetime fields to get the days left difference.
This is very easy to do with C#. For comparing DateTimes, we have a class called TimeSpan. The TimeSpan structure, in this case, would be defined as the difference between your two datetimes.
Let's say that your DateTimes are called start and end.
DateTime start = new DateTime(2009, 6, 14);
DateTime end = new DateTime(2009, 12, 14);
We have established our DateTimes to June 14, 2009 and December 14, 2009.
Now, let's find the difference between the two. To do this, we create a TimeSpan:
TimeSpan difference = end - start;
With this TimeSpan object, you can express the difference in times in many different ways. However, you specifically asked for the difference in days, so here's how you can get that:
Console.WriteLine("Difference in days: " + difference.Days);
Thus, the property is called TimeSpan.Days.
Final Code
//establish DateTimes
DateTime start = new DateTime(2009, 6, 14);
DateTime end = new DateTime(2009, 12, 14);
TimeSpan difference = end - start; //create TimeSpan object
Console.WriteLine("Difference in days: " + difference.Days); //Extract days, write to Console.
For more information on using the TimeSpan structure, see this MSDN documentation (especially the C# examples).
Hope I helped!
UPDATE: Some answers have suggested taking doing subtraction in one step, such as with:
int days = (dt2 - dt1).Days;
or
int numDaysDiff = Math.Abs(date2.Subtract(date1).Days);
However, they are the same thing as in my answer, only shortened. This is because the DateTime.Subtract() method and the subtraction operator of DateTimes returns a TimeSpan, from which you can then access the amount of days. I have specifically used the longer approach in my code sample so that you clearly understand what is going on between your DateTime and TimeSpan objects and how it all works. Of course, the other approaches I just mentioned are fine, too.
UPDATE #2:
A very similar question was asked before, and it can be found here. However, the main point of that question was why the code sample (which is essentially equivalent to that of all the answers) sometimes provides an answer which is a day off. I think this is also important to this question.
As the main answer to the other question suggests, you can use this code:
int days = (int)Math.Ceiling(difference.TotalDays);
This code uses Math.Ceiling, which, according to MSDN, is:
Returns the smallest integral value
that is greater than or equal to the
specified double-precision
floating-point number.
How Do You Want to Count the Days?
Thus, we now have an issue with how you want to count the days. Do you want to count part of a day (such as .5 of a day) as:
A full day - this would use Math.Ceiling to round up TimeSpan.TotalDays, so that you're counting started days.
Part of a day - you can just return the TimeSpan.TotalDays (not rounded) as a decimal (in the double datatype)
Nothing - you can ignore that part of a day and just return the TimeSpan.Days.
Here are code samples for the above:
Counting as a full day (using Math.Ceiling() to round up):
//establish DateTimes
DateTime start = new DateTime(2009, 6, 14);
DateTime end = new DateTime(2009, 12, 14);
TimeSpan difference = end - start; //create TimeSpan object
int days = (int)Math.Ceiling(difference.TotalDays); //Extract days, counting parts of a day as a full day (rounding up).
Console.WriteLine("Difference in days: " + days); //Write to Console.
Counting as part of a day (NOT using Math.Ceiling(), instead leaving in decimal form as a part of a day):
//establish DateTimes
DateTime start = new DateTime(2009, 6, 14);
DateTime end = new DateTime(2009, 12, 14);
TimeSpan difference = end - start; //create TimeSpan object
double days = difference.TotalDays; //Extract days, counting parts of a day as a part of a day (leaving in decimal form).
Console.WriteLine("Difference in days: " + days); //Write to Console.
Counting as nothing of a day (rounding down to the number of full days):
//establish DateTimes
DateTime start = new DateTime(2009, 6, 14);
DateTime end = new DateTime(2009, 12, 14);
TimeSpan difference = end - start; //create TimeSpan object
int days = difference.TotalDays; //Extract days, counting parts of a day as nothing (rounding down).
Console.WriteLine("Difference in days: " + days); //Write to Console.
Use
TimeSpan
DateTime departure = new DateTime(2010, 6, 12, 18, 32, 0);
DateTime arrival = new DateTime(2010, 6, 13, 22, 47, 0);
TimeSpan travelTime = arrival - departure;
The easiest way out is, making use of TimeSpan().
This Subtract function will return you the difference between two dates in terms of time span. Now you can fetch fields like days, months etc. To access days you can make use of
Here is the sample code;
VB.Net code;
Dim tsTimeSpan As TimeSpan
Dim ldDate1 as Date
Dim ldDate2 as Date
'Initialize date variables here
tsTimeSpan = ldDate1 .Subtract(ldDate2)
Dim NumberOfDays as integer = tsTimeSpan.days
C#.Net code;
DateTime lDate1;
DateTime lDate2;
TimeSpan tsTimeSpan ;
int NumberOfDays;
//Initialize date variables here
tsTimeSpan = ldDate1 .Subtract(ldDate2);
NumberOfDays = tsTimeSpan.days;
DateTime dt1 = new DateTime(2009,01,01,00,00,00);
DateTime dt2 = new DateTime(2009,12,31,23,59,59);
int days = (dt2 - dt1).Days;
Number of Days Difference
These answers take the number of days as an int from the System.TimeSpan structure that is the result of subtracting two System.DateTime fields...
Quick answer - gets the number of days difference.
int numDaysDiff = date2.Subtract(date1).Days;
Alternate answer - uses Math.Abs to ensure it's not a negative number, just in case the dates might be supplied in either order.
int numDaysDiff = Math.Abs( date2.Subtract(date1).Days );
Some sample data to finish it off using System namespace:
// sample data
DateTime date1 = DateTime.Now;
DateTime date2 = DateTime.Now.AddDays(10);
MSDN References (and more sample code ):
System.TimeSpan structure
System.DateTime structure
System.Math.Abs(..) method
DateTime theDate = DateTime.Today;
int datediff = theDate.Subtract(expiryDate).Negate().Days;
if expiryDate > theDate then you get Negative value: -14
expiryDate is less than theDate then you get positive value: 14
You May obviously want this in a scenario such as
Send a Notification Email 14days before expiry
Send another notification Email 14 days after expiry
You need a difference that could be negative value
You should look at TimeSpan.
To get the exact days ignoring the time section
DateTime d1 = Convert.ToDateTime(DateTime.Now.ToShortDateString());
DateTime d2 = Convert.ToDateTime(DateTime.Now.AddDays(46).ToShortDateString());
var days = Convert.ToInt32(d2.Subtract(d1).TotalDays)

Categories

Resources