Compare two DateTimes with ignoring seconds and milliseconds - c#

I take two object from database. One is a filename with date init and second one is a DateTime object like 2021-08-08 17:32:07.880.
First, I converted filename to datetime with the code shown here:
var fileDate = DateTime.ParseExact(filename, "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
I have to check that the difference between the first date and the second date is 3 hours 15 min or simply 3 hours.
How do I delete seconds and milliseconds of date 2, and compare them?

I'd go similar to MatJ's recommendation:
You've got your file time, and your DB time, which might have seconds and milliseconds on it. If you do the later one minus the earlier one you get a timespan representing the length of time between the datetimes
dBDate - fileDate
Timespans have a TotalMinutes property that is a decimal. A timespan of 5 minutes 45 seconds would have a TotalMinutes of 5.75
So, if we cast that to an int it cuts off the seconds; simples!
var t = (int)((dBDate - fileDate).TotalMinutes);
Now you can compare your t for equality to 180 (3h) or 195 (3h15h

It is very easy to do !
Try following code :
TimeSpan timeSpan = (firstDate - secondDate)
timeSpan.CompareTo(new TimeSpan(3, 15, 0)) // hrs, mins, seconds
This CompareTo method will return 1 if difference between two times is greater than 3 hrs and 15 mins, otherwise, it will return -1
PS:
firstDate and secondDate are in DateTime

Related

How to get day start date in seconds based on current date in seconds

As in the title, I get the current date in seconds and I need to get the start of the day also in seconds, example function
private long? getStartOfDay(long? dateVal){
return ...
}
date with 0 number of seconds will return midnight Jan 1 1970
You mean like this?
private static long? getStartOfDay(long? dateVal) {
return dateVal - dateVal % 86400L;
}
Just truncating down to nearest multiple of 24 * 60 * 60.
Will not work with negative values, so either include a check that will throw an ArgumentOutOfRangeException, or change to ulong.
You are working with Unix date. To get DateTime from seconds:
double seconds = ...
// .Date to get rid of TimeOfDay (Hour, Minute, Second) component
DateTime startDate = DateTime.UnixEpoch.AddSeconds(seconds).Date;
Or if you want to get local time Date
DateTime startDate = DateTime.UnixEpoch.AddSeconds(seconds).ToLocalTime().Date;
To get seconds from DateTime:
DateTime myDate = ...
var seconds = (myDate.ToUniversalTime() - DateTime.UnixEpoch).TotalSeconds;

Get undertime and overtime automatically

Could you please help me? I'm trying to create an attendance system wherein the undertime and overtime will be automatically computed, but there's an error. For example the employee's scheduled out is 11 PM, and their overtime 12 AM which is 1 hour, but the output is 23. Can anyone help me how to compute elapsed time?
string datetime = "12:00 AM"; // this is the time you are going to time out
string OUT = "11:00 PM"; // this is your scheduled out
DateTime d1 = Convert.ToDateTime(datetime);
DateTime d2 = Convert.ToDateTime(OUT);
TimeSpan ts = d2.Subtract(d1);
MessageBox.Show(ts.TotalHours.ToString()); // output is 23 which is wrong, it must be 1 hour overtime only
IMO, in order to fix your problem, you have to work with the actual datetime objects.
Always record actual system datetime without manipulating parts of it.
For your case you should have the fields for record scheduled_work_start, scheduled_work_finished and actual_work_finished
for an instance, say one of the employees starts work at 10-01-2019 14:00:00 (2 PM) and finishes her time at 10-01-2019 23:00:00 (11 PM) and assume she did one hour overtime.
The system should record the actual_work_finished time as 11-01-2019 00:00:00 (12 AM)
When you require to calculate or find out the extra time
calculate:
var over_time_in_hours =
actual_work_finished.Substract(scheduled_work_finished).TotalHours;
Hope this makes sense.
If you print your d1 and d2 times:
d1 time => "09.01.2019 00:00:00".
d2 time => "09.01.2019 23:00:00".
Then 23-0 = 23 is the expected result.
By the way you can achieve your result by adding 1 day to d1 time object and subtract this result from d2 object:
TimeSpan ts = d1.AddDays(1).Subtract(d2);
Console.WriteLine(ts.TotalHours.ToString());
Let's start by naming your variables something that helps us to reason about the code.
// this is the time you are going to time out
DateTime actual = Convert.ToDateTime("12:00 AM");
// this is your scheduled out
DateTime scheduled = Convert.ToDateTime("11:00 PM");
TimeSpan overtime = scheduled.Subtract(actual);
What we find is that you're performing the wrong calculation to start with. This would be the correct calculation:
TimeSpan overtime = actual.Subtract(scheduled);
When we do that though we are now getting -23 hours. This is because your actual time isn't after your scheduled time. For that you need to add a day.
Try this:
// this is the time you are going to time out
DateTime actual = Convert.ToDateTime("12:00 AM").AddDays(1);
// this is your scheduled out
DateTime scheduled = Convert.ToDateTime("11:00 PM");
TimeSpan overtime = actual.Subtract(scheduled);
Then you get the result that you want - i.e. 1 hour.

C# TimeSpan.Milliseconds formated to 2 digits

I have a timer that I want to show minutes:seconds:hundreds of seconds.
Since C# timespan doesn't have a method to get hundreds but only milliseconds, I need to somehow format this.
TimeSpan ts = stopWatch.Elapsed;
currentTime = String.Format("{0:00}:{1:00}:{2:00}", ts.Minutes, ts.Seconds, Math.Round(Convert.ToDecimal(ts.Milliseconds),2));
ClockTextBlock.Text = currentTime;
I've tried with Math.Round and nothing happened. The result is still anywhere from 1-3 digit, like this:
01:12:7
01:12:77
01:12:777
I want format to always be like
01:12:07
01:12:77
You need:
String.Format(#"Time : {0:mm\:ss\.ff}", ts)
Where "ts" is your TimeSpan object. You can also always extend this to include hours etc. The fff stuff is the number of significant digits of the second fractions
You can use a custom TimeSpan format string for that (here we're only displaying the first two digits of the milliseconds with ff, which represent the hundredths):
ClockTextBlock.Text = ts.ToString("mm\\:ss\\:ff");
You could set a DateTime type timezone and plus with Timespan span.
You would get a datetime and format it!
DateTime timezone = new DateTime(1, 1, 1);
TimeSpan span = stopWatch.Elapsed;
ClockTextBlock.Text=(timezone + span).ToString("mm:ss:ff");
Just put the format in toString and it simply will show you the desired format :)
Stopwatch s2 = new Stopwatch();
s2.Start();
Console.WriteLine(s2.Elapsed.ToString(#"hh\:mm\:ss"));
Since a millisecond is 1/1000 of a second, all you need to do is divide the milliseconds by 10 to get 100's of a second. If you are concerned about rounding, then just do it manually before the division.
int hundredths = (int)Math.Round((double)ts.Milliseconds / 10);
currentTime = String.Format("{0}:{1}:{2}", ts.Minutes.ToString(D2), ts.Seconds.ToString(D2), hundredths.ToString(D2);
ClockTextBlock.Text = currentTime;

Subtracting timespan from 24 hours

I'm trying to subtract my potentially negative timespan values from 24 hours to change them into positive values.
As an example case:
I want to find how much time is there till 8:00 AM.
If it's 16:00 PM now, timespan gives me -8 ish value so I want to substract it from 24 to get 16.
I'm trying this but it's giving me this error
The DateTime represented by the string is not supported in calendar
System.Globalization.GregorianCalendar.
What I tried ;
string startTime = String.Format("{0:t}", "8:00");
TimeSpan timeLeft = Convert.ToDateTime(startTime).Subtract(DateTime.Now);
if (timeLeft.TotalMinutes < 0 )
{
timeLeft = Convert.ToDateTime(String.Format("{0:H}","24:00")).Subtract(Convert.ToDateTime(timeLeft.Negate())) ;
}
How can I achieve subtracting my potentially negative timespans from 24 hours?
You are confusing TimeSpan and DateTime. I guess there is an easier way:
var eightOClock = TimeSpan.FromHours(8);
var now = DateTime.Now;
var till8again = now.TimeOfDay > eightOClock
? TimeSpan.FromHours(32) - now.TimeOfDay
: eightOClock - now.TimeOfDay;
So if TimeOfDay is less than eight hours (it's before 8am), we take the difference to 8am. If it's greater than 8am, we take the difference to 32hours, which is 8am tomorrow.
A DateTime is an absolute date, happening at a certain day, month, year... It must not be used to represent a specific hour.
So your attempt to convert "8:00", or "24:00" in a DateTime will forcibly fail.
For this you must use TimeSpan (or eventually an integer if you always work with hours).
You can use for example
if(DateTime.Now.TimeOfDay > TimeSpan.FromHours(8))
To see if it's more or less than 8:00.
TimeOfDay will return you the amount of time elapsed for today since midnight.
DateTime has also a lot of useful methods to Add or Substract time, see https://msdn.microsoft.com/fr-fr/library/system.datetime(v=vs.110).aspx for details
Use TimeSpan, and if the startDate is less the Now, add a day to it and then make the comparison.
TimeSpan startTime = new TimeSpan(8,0,0);
TimeSpan now = DateTime.Now.TimeOfDay;
startTime = startTime < now ? startTime.Add(TimeSpan.FromDays(1)) : startTime;
TimeSpan diff = startTime - now;
Another point: the error is coming from the fact that 24:00 doesn't represent 12:00 midnight. 0:00 represents midnight, and that will be a valid DateTime.

Parsing times above 24 hours in C#

Suppose a time stamp (just time or date and time) where the time can roll over to the next day:
00:00:00 <- midnight
01:00:00 <- 1 AM
23:00:00 <- 11 PM
24:00:00 <- midnight, day + 1
25:00:00 <- 1 AM, day + 1
What would be a way to parse it easily into a C# DateTime that would perform the carry-over to the next day? In other words, "01:00:00" would become "0001-01-01 01:00:00" and "25:00:00" would become "0001-01-02 01:00:00".
EDIT:
I should mention that this fails miserably (i.e FormatException):
DateTime.ParseExact("0001-01-01 25:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
Since you're trying to represent a period of time from an arbitrary point, rather than as a specific date, perhaps you would be better off using the System.TimeSpan class? This allows you to set values of more than 24 hours in the constructor, and can be used with DateTime objects like this:
System.TimeSpan timestamp = new System.TimeSpan(25, 0, 0);
System.DateTime parsedDateTime = new DateTime(0, 0, 0);
parsedDateTime = parsedDateTime.Add(timestamp);
Console.WriteLine(parsedDateTime.ToString("yyyy-MM-dd HH:mm:ss")); //Output as "0001-01-02 01:00:00"
NOTE: Code is untested.
EDIT: In terms of parsing the strings, I can't think of any basic .NET objects that parse strings with values greater than 23 for the hour (since 25 is an invalid hour of the day), but assuming that the format is consistent, you could create a very simple string parsing routine (or even a regular expression) to read the values individually, and load the constructor manually.
If you have an existing DateTime value you can add to, you can always use a TimeSpan:
string dt = "25:00:00";
int hours = int.Parse(dt.Split(':')[0]);
TimeSpan ts = TimeSpan.FromHours(hours);
TimeSpan.Parse() doesn't work directly in this case because it complains (fair enough!) about the 25 in the hour notation.
If you want to code it out... this should be a starting point:
string dateString = "0001-01-01 25:00:00";
string[] parts = dateString.Split(' '); //now have '0001-01-01' and '25:00:00'
string datePart = parts[0]; // '0001-01-01'
string[] timeParts = parts[1].Split(':'); //now have '25', '00', and '00
DateTime initialDate = DateTime.ParseExact(datePart, "yyyy-MM-dd", CultureInfo.InvariantCulture);//use the date as a starting point
//use the add methods to get your desired datetime
int hours = int.Parse(timeParts[0]);
int minutes = int.Parse(timeParts[1]);
int seconds = int.Parse(timeParts[2]);
DateTime resultDate = initialDate.AddHours(hours)
.AddMinutes(minutes)
.AddSeconds(seconds);
Of course, it makes assumptions that the input is formatted properly and is parsable, etc..
In addition, you could definitely use timespan instead of the individual add methods for hour, minute, second as some other answers are..
In case nobody points out an out-of-the-box answer, here is a neat ActionScript class I wrote to parse time inputs (human input)...
https://github.com/appcove/AppStruct/blob/master/Flex/AppStruct/src/AppStruct/TimeInput.as
It would be very simple to port this to C#, and you could tweak the 24 hour logic to result in #days, #hours, #minutes.
Good luck!
You are specifying an invalid date. So not only can you not parse it, you cannot store it!
How about a nice TimeSpan object instead? (It also has a Parse() method.)
Alternatively, use a sscanf()-type function like the one at http://www.blackbeltcoder.com/Articles/strings/a-sscanf-replacement-for-net to extract each number separate. (Best if you have no control over the string format being read.)

Categories