tddyballgm
tddyballgm

Reputation: 57

Calculating time with hours and minutes only

I am attempting to create a timesheet calculator which takes calculates the time an employee works and I am close, with one problem.

As I perform the calculation, I only want hours and minutes to display. I am able to get that done, but that causes an issue. If the employee punches out before a full minute is elapsed, that minute is not included in the calculation.

For example, if an emp punches in at 12:00:30 and punches out at 5:00:29, that last minute is not counted in the calculation, so the time shows as 4:59 instead of 5:00.

How do I get the calculation to be based on the hours and minutes and exclude seconds completely?

This is the code I have:

    private void btnPunchOut_Click(object sender, EventArgs e)
    {

        DateTime stopTime = DateTime.Now;
        lblPunchOutTime.Text = stopTime.ToShortTimeString();
        TimeSpan timeWorked = new TimeSpan();
        timeWorked = stopTime - startTime;                  
        lblTimeWorked.Text = timeWorked.ToString(@"hh\:mm");
    }

Upvotes: 0

Views: 1786

Answers (2)

Scott Hannen
Scott Hannen

Reputation: 29207

If you want a calculation that really ignores the seconds, the clearest way to accomplish that is to get rid of the seconds on both the start time and the end time. It might not seem accurate because it allows a difference of one second to become a difference of one minute. But that could still be a valid business rule, that you want to subtract according the the minutes that appeared on the clock rather than the actual elapsed seconds.

In other words,

1:00:01 is adjusted to 1:00:00.
1:00:59 is adjusted to 1:00:00.
1:01:00 is "adjusted" to 1:01:00.
1:01:01 is adjusted to 1:01:00.

You can accomplish that with an extension like this:

public static class TimespanExtensions
{
    public static TimeSpan TrimToMinutes(this TimeSpan input)
    {
        return TimeSpan.FromMinutes(Math.Truncate(input.TotalMinutes));
    }
}

(I'm sure there's a more efficient way of truncating the seconds, but at least this is clear.)

Now instead of having to figure out how to calculate the difference while rounding seconds or adding seconds, you just trim the seconds before calculating the difference. Here's a unit test:

[TestMethod]
public void NumberOfMinutesIgnoresSeconds()
{
    var startTime = TimeSpan.FromSeconds(59).TrimToMinutes();
    var endTime = TimeSpan.FromSeconds(60).TrimToMinutes();
    Assert.AreEqual(1, (endTime - startTime).TotalMinutes);
}

One Timespan represents 59 seconds, and the next one is 60, or the first second of the next minute. But if you trim the seconds and then calculate the difference you get exactly one minute.

In the context of your code,

DateTime stopTime = DateTime.Now;
lblPunchOutTime.Text = stopTime.ToShortTimeString();
var timeWorked = stopTime.TrimToMinutes() - startTime.TrimToMinutes();                  
lblTimeWorked.Text = timeWorked.ToString(@"hh\:mm");

Upvotes: 1

Grantly
Grantly

Reputation: 2556

Use TimeSpan.TotalSeconds perhaps...And then add 30 seconds or more, before you convert it to hours by dividing by 3600.

As in

lblTimeWorked.Text = ((timeWorked.TotalSeconds+30)/3600).ToString("0.00") + " hours";

Use Timespan.TotalHours if you want the hours.

But if you want to be accurate, you should create a separate class dedicated to calculating the hours worked by a staff member. Then you can encapsulate lots of business rules in the dedicated class. Staff have entitlements and overtime, expenses or penalty rates - so this can get complex if done properly.

Upvotes: 1

Related Questions