none
C# totaling calculated work time in just hours and minutes RRS feed

  • Question

  • I am trying to design a timesheet solution which will take a punch-in and a punch-out time (DateTime.Now) and then take those to calculate the amount of time an employee has worked.  I am able to capture the punch-in and punch-out, calculate and display the time, but the problem is when the calculation occurs, the calculation is based on the seconds and I want it to be just hours and minutes.  So if the employee punched in at 12:00 and punched out at 12:01, unless the employee has worked over 60 seconds, the time calculated will show 0:00, when I want it to show 0:01.

    Any suggestions on how I eliminate the seconds from the calculation?  (The code I have is written below)

            private void btnPunchIn_Click(object sender, EventArgs e)
            {
                DateTime startTime = DateTime.Now;
                lblPunchInTime.Text = startTime.ToShortTimeString(); 
            }

            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 = (string.Format("{0:0}:{1:00}", (int)timeWorked.TotalHours, timeWorked.Minutes));
                    
      
            }

    Friday, January 12, 2018 11:06 PM

Answers

  • Are you in the Central Time Zone? If not, OK, but if you are, why would you jump through those hoops to declare the time (DateTime.Now.ToToUniversalTime().AddHours(-6))?

    >>I have both variables declared at the Form level, and I have the punchIn variable only referencing the Form level declaration in the punchIn click event via the lblPunchInTime.Text = punchIn.ToShortTimeString(); and it works fine.  If I try to do that same thing with the punchOut click event code, the calculated hours is 00:00.  But if I have punchOut = DateTime.Now.ToUniversalTime().AddHours(-6); in the punchOut click event, it works fine.  How is that possible?  Why do I have to 're-declare' (and I am pretty sure that is the wrong terminology) the punchOut variable in the punchOut button click event code?  Or why don't I need that in the punchIn button click event code?<<

    When you initially declare the punchIn and punchOut global variables with a value, you are just giving them a starting/default value after you've declared them (but you don't have to).  But, in your button clicks, you want to reset those variables to NOW (use the terminology set or re-set ... you are *not* re-declaring them). The reason it seemed to work in the PunchIn Click is because you've only done it once. In other words, you start up the application, and click the two buttons. But, if you were to click the two buttons again (without restarting the application), the punchIn value would never change from the value it had when the Form first started. This is not really the functionality you had in mind (or, it shouldn't be anyway, because from a User's viewpoint that would not be the expected behavior for a PunchIn button). So you really need to re-set in the PunchIn Click.

    Here's another thing that might help you better conceptualize the global variables. They can all be accessed with "this." ... in fact, that's the preferred syntax to use for precisely this reason ... to avoid confusion between global variables and local variables (and also static variables ... but that's another kettle of fish, so let's not bother about static for now).

    So, in your Click events, you should be referring to those DateTimes like so:

    private void btnPunchIn_Click(object sender, EventArgs e)
    {
        this.punchIn = DateTime.Now;
        this.lblPunchInTime.Text = this.punchIn.ToShortTimeString();          
    }
    
    private void btnPunchOut_Click(object sender, EventArgs e)
    {
        this.punchOut = DateTime.Now;
        this.lblPunchOutTime.Text = this.punchOut.ToShortTimeString();
        TimeSpan timeWorked = new TimeSpan();
        timeWorked = this.punchOut - this.punchIn;
    
        int elapsedMinutes;
        if (this.punchOut.Minute >= this.punchIn.Minute)
            elapsedMinutes = this.punchOut.Minute - this.punchIn.Minute;
        else
        {
            int secondsTo60 = 60 - this.punchIn.Minute;
            elapsedMinutes = this.punchOut.Minute + secondsTo60;
        }
        this.lblTimeWorked.Text = string.Format("{0:00}:{1:00}", (int)timeWorked.TotalHours, elapsedMinutes);
    }
    


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    • Marked as answer by tddyballgm Monday, January 15, 2018 9:30 PM
    Monday, January 15, 2018 6:24 AM
    Moderator

All replies

  • You need to make use of TotalMinutes and Math.Round and cast to int. Try this:

    lblTimeWorked.Text = string.Format("{0:0}:{1:00}", (int)timeWorked.TotalHours, (int)Math.Round(timeWorked.TotalMinutes));
    


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Saturday, January 13, 2018 5:44 AM
    Moderator
  • Thank you the reply and help.  I made the change but it still did not calculate correctly.  I punched in at 10:12:10 and punched out at 10:13:23 and it calculated 2 minutes of work time.

    I am not sure what I did wrong or am doing wrong, but I can't help but wonder if there is a way to completely eliminate the seconds from the process, from the very beginning.  In my mind, if the seconds are never part of the variables, then they can't effect the calculation of time.  But for the life of me I can't figure out how to eliminate the seconds.  

    Wouldn't that make things easier and straight forward?

    If I can't eliminate the seconds from the whole process, then my guess is I will have to figure out some code to take them into account so I can accurately calculate time worked.  There are hundreds of time and attendance software solutions out there, so it's obviously possible, but I just can't seem to account for the seconds.

    Thanks!

    Saturday, January 13, 2018 4:19 PM
  • Sorry ... I guess I was assuming you wanted to round up. But, I see what you want now. This should do the trick:

    lblTimeWorked.Text = string.Format("{0:0}:{1:00}", (int)timeWorked.TotalHours, Math.Abs(stopTime.Minute - startTime.Minute));

    EDIT: Ooops, wait a minute ... that's not quite right either. Give me a few minutes ...


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com



    Saturday, January 13, 2018 5:24 PM
    Moderator
  • It appears you are a goddess!!!  I have tested 3 different scenarios, and so far each worked as I was hoping!!!  I will continue to test, but this looks like it should work.  THANK YOU!!!!

    As a follow up, is it not possible to eliminate the seconds from the calculation?  or is that what the absolute value is essentially doing?

    Saturday, January 13, 2018 5:34 PM
  • Thanks, but I goofed ... it won't work if your startTime is a few minutes before the hour and your stopTime is a few minutes after the hour. In other words, your startTime Minute is *greater than* than your stopTime Minute. I *think* this might work (but I haven't tested it under that scenario).

    int elapsedMinutes;
    if (stopTime.Minute >= startTime.Minute)
        elapsedMinutes = stopTime.Minute - startTime.Minute;
    else
    {
        int secondsTo60 = 60 - startTime.Minute;
        elapsedMinutes = stopTime.Minute + secondsTo60;
    }
    lblTimeWorked.Text = string.Format("{0:0}:{1:00}", (int)timeWorked.TotalHours, elapsedMinutes);

    We *are* eliminating the seconds, which is why were simply using the startTime.Minute and stopTime.Minute to calculate the Minute part.


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com


    Saturday, January 13, 2018 5:45 PM
    Moderator
  • You are correct.  I test it with the punch-in at 11:57 and the punch-out at 12:01, and it calculated to 55 min.

    I will try and test your additional code, but I am not sure that will work.  I have tested something similar and no matter what I did, it included the seconds in the calculation so if I punched-in at 12:00:30 and punched-out at 12:01:20, it would calculate as zero minutes because it is technically less than a minute.  Hopefully your code will work, but everything I have tried so far has failed because the seconds are always part of the calculation.

    I will keep you posted.  But I really appreciate all your help.

    Saturday, January 13, 2018 6:04 PM
  • Unfortunately, it did not work.  When I punched in and out on the same minute (12:05:10 , 12:05:15), it calculated the time to 1 minute when it should be zero.  I thought that was due to the >= in stopTime.Minute >= startTime.Minute, but when I removed the equal sign, and did the punch in and out on the same minute again, it calculated to 0:60.

    Saturday, January 13, 2018 6:11 PM
  • Check this method too:

    int total_minutes = (int)Math.Floor( ( endTime - startTime).TotalMinutes);
    int hours = total_minutes / 60;
    int minutes = total_minutes % 60;
    
    string result = string.Format( "{0:00}:{1:00}", hours, minutes );
    

    Saturday, January 13, 2018 7:18 PM
  • I will work on it some more, but the result I got was 0:00.  I even punched-in just before 2:00, and punched out after 2:00, but did not get the desired result.
    Saturday, January 13, 2018 8:19 PM
  • If you want to count incomplete minutes too, then use Ceiling instead of Floor.

    Saturday, January 13, 2018 8:46 PM
  • Unfortunately, it did not work.  When I punched in and out on the same minute (12:05:10 , 12:05:15), it calculated the time to 1 minute when it should be zero.  I thought that was due to the >= in stopTime.Minute >= startTime.Minute, but when I removed the equal sign, and did the punch in and out on the same minute again, it calculated to 0:60.


    That's very strange ... I did the same punch-in, punch-out that you did, using my code example, with the >=, and I get 0. I can't see how it can be any different than that. The .Minute property for both times are 5 (and the property is an int, so there's no rounding or anything). And the last time I checked, 5-5 is 0!!   ;0)   Maybe you have a typo in your code? Can you post that little bit of it?

    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com


    Saturday, January 13, 2018 9:11 PM
    Moderator
  • I had int minutes = total_minutes / 60; instead of total_minutes % 60 and so far that seems to have worked.  I did a punch in and out within 10 seconds of each other and the result was 0:00, which is what I want.  I will be doing more testing to see if it works in multiple scenarios, but right now I am hopeful!  
    Sunday, January 14, 2018 5:27 AM
  • OK, so you're talking about Viorel's suggestion, not mine. My suggestion had no /60 or %60 ... just straight subtraction,  which seems to work fine for me. This one:

    int elapsedMinutes;
    if (stopTime.Minute >= startTime.Minute)
        elapsedMinutes = stopTime.Minute - startTime.Minute;
    else
    {
        int secondsTo60 = 60 - startTime.Minute;
        elapsedMinutes = stopTime.Minute + secondsTo60;
    }
    lblTimeWorked.Text = string.Format("{0:0}:{1:00}", (int)timeWorked.TotalHours, elapsedMinutes);


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Sunday, January 14, 2018 6:03 AM
    Moderator
  • I noticed there were two solutions offered after trying Viorel's solution.

    Your code seems to work so far.  I did a punch-in and punch-out on the same minute and it calculated to 0:00, then I did a punch-in at 12:40:30 and a punch-out at 12:40:10 and it did calculate to 1 minute worked, which is nice!

    I am not really sure what I did wrong the first time, but it seems to be working as I hoped now.  Next, I will test it with a punch-in just before the hour and a punch-out just after the hour to see the result.

    You have been amazing, thank you.  I will let you know how the next set of punches work.  Thanks!

    Sunday, January 14, 2018 6:49 AM
  • When I tried the before and after hour punch, it was off by a minute and I am not sure why.  It seemed to work within the same hour, but before and after the hour, it added a minute.  Here is the code:

    namespace frmTimeSheet
    {
        public partial class Form1 : Form
        {
            DateTime startTime = DateTime.Now;
            DateTime stopTime = DateTime.Now;
            

            public Form1()
            {
                InitializeComponent();
            }

            private void btnPunchIn_Click(object sender, EventArgs e)
            {
                DateTime startTime = DateTime.Now;
                lblPunchInTime.Text = startTime.ToShortTimeString();
                lbleSecondSolutionIn.Text = startTime.ToShortTimeString();
            }

            private void btnPunchOut_Click(object sender, EventArgs e)
            {
                DateTime stopTime = DateTime.Now;
                lblPunchOutTime.Text = stopTime.ToShortTimeString();
                TimeSpan timeWorked = new TimeSpan();
                timeWorked = stopTime - startTime;

                int elapsedMinutes;
                if (stopTime.Minute >= startTime.Minute)
                    elapsedMinutes = stopTime.Minute - startTime.Minute;
                else
                {
                    int secondsTo60 = 60 - startTime.Minute;
                    elapsedMinutes = stopTime.Minute + secondsTo60;
                }
                lblTimeWorked.Text = string.Format("{0:0}:{1:00}", (int)timeWorked.TotalHours, elapsedMinutes);

            }
        }
    }

    Sunday, January 14, 2018 7:09 AM
  • To Viorel:  I could have sworn, your solution was working as I wanted, but now it seems to be off that minute.  If I use Floor, it shorts a minute, if I use Ceiling, it calculates one minute too much.
    • Edited by tddyballgm Sunday, January 14, 2018 7:22 AM
    Sunday, January 14, 2018 7:21 AM
  • BonnieB, I have tested your code multiple times with different times - within the same hour, within the same minute, just before and just after the hour, punch-outs before and after the seconds of the punch in and all seem to be working well.

    I am extremely optimistic right now and incredibly grateful for all your help.  I will continue to test your solution to confirm it works as expected all the time, but I am feeling good about it!  Thanks again and I will give you an update soon.

    Thank you!!

    Sunday, January 14, 2018 8:08 AM
  • There's a slight problem with your code ... I thought it used to cause compiler errors, but maybe I'm misremembering. Anyway, you have defined startTime and stopTime as variables that are scoped to the Form (which *is* correct, they *should* be). But then, in both Click handlers, you're defining it scoped local to the method (which is *not* correct)!! That is *definitely* going to cause erroneous results!!

    public partial class Form1 : Form
    {
        // this is correct
        DateTime startTime = DateTime.Now;
        DateTime stopTime = DateTime.Now;
             
    // .....
    
        private void btnPunchIn_Click(object sender, EventArgs e)
        {
            // this is not
            DateTime startTime = DateTime.Now;   
    
    // ....
    
        private void btnPunchOut_Click(object sender, EventArgs e)
        {
            // this is not
            DateTime stopTime = DateTime.Now;        


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com


    Sunday, January 14, 2018 3:33 PM
    Moderator
  • You mean something as this (I'm on CET and when I did run it, it was  17:35

    The problem with this is that some workers will never reach their total hours if it is used for very short jobs. But that is not about the calculation but the system.


    Success Cor

    Sunday, January 14, 2018 4:38 PM
  • Cor, he doesn't want the total minutes clocked-in. He wants it in hours : minutes, which is why a Timespan is used to determine TotalHours. The problem is when you try to calculate the additional Minutes (*after* the Hours) using any of the TimeSpan Minute properties ... it doesn't work quite how he wanted it to work. Which is why those Minutes needed to be calculated differently. I still think it's best to simply work with the startTime.Minute and the endTime.Minute to determine that.
           

    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Sunday, January 14, 2018 8:04 PM
    Moderator
  • Bonnie,

    But when you use the timespan you are in fact calculating in ticks. Everybody did it, therefore I tried to show to do it with actual hours and minutes. If I use this code I get:

                DateTime Clocked = new DateTime(1, 1, 1, 16, 30, 0);
                int MinutsDone =  (DateTime.Now.Hour * 60 + DateTime.Now.Minute) - (Clocked.Hour * 60 + Clocked.Minute);
                int Hours =  MinutsDone / 60 ;
                int Minutes = MinutsDone - Hours * 60;
                Console.WriteLine(Hours.ToString() + ":" + Minutes.ToString("00"));
                Console.ReadKey();

    5:40 (it is now 21:40) Here. (Only in English AM/PM is used).

    Maybe it is there an easier way by setting minutes to hours. We are here in Europe used to decimal, hours is the last measurement which is in the old way. I never understood how you Americans can so easily measure with those for us strange quantities. :-)


    Success Cor



    Sunday, January 14, 2018 8:44 PM
  • Bonnie, That is interesting you mention the scope issue with the variables, because I may be even more wrong than I thought.  I originally have the variables declared in each button control, but the startTime was not accessible in the stopTime control, so I made both 'global' for access.  I thought with the global access, each variable would be initialized when the application opened up, but when I clicked the button, the actual punch time would then be updated and put into the variable.

    My goal is to make this code as bullet proof as possible, so how do I correctly handle it?  Do I create local variables in each button control and somehow access the Form level variables?

    I guess my big question is, why is it not correct to have the variables declared in each button control?  What kind of time calculation error will I encounter?


    • Edited by tddyballgm Sunday, January 14, 2018 9:24 PM
    Sunday, January 14, 2018 9:24 PM
  • OK, Cor ... now that you've "finished" your code example to calculate the Hours too, then it works just as specified. Maybe you meant to leave that incomplete as an "exercise" ... ;0)

    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Sunday, January 14, 2018 11:49 PM
    Moderator
  • Bonnie, That is interesting you mention the scope issue with the variables, because I may be even more wrong than I thought.  I originally have the variables declared in each button control, but the startTime was not accessible in the stopTime control, so I made both 'global' for access.  I thought with the global access, each variable would be initialized when the application opened up, but when I clicked the button, the actual punch time would then be updated and put into the variable.


    Scope isn't really all that tricky.

    Any variable that needs to be "persisted" between methods, needs to be scoped "globally" (in this case, scoped to the Form).

    Local variables are scoped to the method in which they are defined. If you define a local variable with the same name as a global variable, it does *not* make them the same variable. They are totally separate variables.

    Consequently, in your code, you were *never* setting the global startTime and stopTime variables ... only the local ones. When it came time to do the calculations in the btnPunchOut_Click(), you were working with a *local* stopTime variable which correctly had DateTime.Now, but the *global* startTime variable, which was never initialized to anything, contained the default (DateTime.MinValue). You can see why that would cause problems, because you were doing your calculations with the wrong startTime.

    Does that make sense now?

       

    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Sunday, January 14, 2018 11:55 PM
    Moderator
  • That does make sense, but I am a bit confused at the same time.  In as much as I can grasp the concept of scope, it doesn't seem to work like I am expecting.  I am continuing to play around with the code, but here is something I don't understand. (and my terminology may be off a bit, so apologies in advance)

    I have both variables declared at the Form level, and I have the punchIn variable only referencing the Form level declaration in the punchIn click event via the lblPunchInTime.Text = punchIn.ToShortTimeString(); and it works fine.  If I try to do that same thing with the punchOut click event code, the calculated hours is 00:00.  But if I have punchOut = DateTime.Now.ToUniversalTime().AddHours(-6); in the punchOut click event, it works fine.  How is that possible?  Why do I have to 're-declare' (and I am pretty sure that is the wrong terminology) the punchOut variable in the punchOut button click event code?  Or why don't I need that in the punchIn button click event code?

    That's another thing I don't get.  The concept seems to makes sense to me, but then it doesn't work they way I have it conceptualized in my brain.

    Does that make sense?

    Below is the latest code (which seems to work fine so far).

    namespace frmTimeSheet
    {

        public partial class Form1 : Form
        {
            DateTime punchOut = DateTime.Now.ToUniversalTime().AddHours(-6);
            DateTime punchIn = DateTime.Now.ToUniversalTime().AddHours(-6);
            public Form1()
            {
                InitializeComponent();
            }

            private void btnPunchIn_Click(object sender, EventArgs e)
            {
                lblPunchInTime.Text = punchIn.ToShortTimeString();          
            }

            private void btnPunchOut_Click(object sender, EventArgs e)
            {
               
                punchOut = DateTime.Now.ToUniversalTime().AddHours(-6);
                lblPunchOutTime.Text = punchOut.ToShortTimeString();
                TimeSpan timeWorked = new TimeSpan();
                timeWorked = punchOut - punchIn;

                int elapsedMinutes;
                if (punchOut.Minute >= punchIn.Minute)
                    elapsedMinutes = punchOut.Minute - punchIn.Minute;
                else
                {
                    int secondsTo60 = 60 - punchIn.Minute;
                    elapsedMinutes = punchOut.Minute + secondsTo60;
                }
                lblTimeWorked.Text = string.Format("{0:00}:{1:00}", (int)timeWorked.TotalHours, elapsedMinutes);
                
            }
        }
    }

    Monday, January 15, 2018 2:55 AM
  • Are you in the Central Time Zone? If not, OK, but if you are, why would you jump through those hoops to declare the time (DateTime.Now.ToToUniversalTime().AddHours(-6))?

    >>I have both variables declared at the Form level, and I have the punchIn variable only referencing the Form level declaration in the punchIn click event via the lblPunchInTime.Text = punchIn.ToShortTimeString(); and it works fine.  If I try to do that same thing with the punchOut click event code, the calculated hours is 00:00.  But if I have punchOut = DateTime.Now.ToUniversalTime().AddHours(-6); in the punchOut click event, it works fine.  How is that possible?  Why do I have to 're-declare' (and I am pretty sure that is the wrong terminology) the punchOut variable in the punchOut button click event code?  Or why don't I need that in the punchIn button click event code?<<

    When you initially declare the punchIn and punchOut global variables with a value, you are just giving them a starting/default value after you've declared them (but you don't have to).  But, in your button clicks, you want to reset those variables to NOW (use the terminology set or re-set ... you are *not* re-declaring them). The reason it seemed to work in the PunchIn Click is because you've only done it once. In other words, you start up the application, and click the two buttons. But, if you were to click the two buttons again (without restarting the application), the punchIn value would never change from the value it had when the Form first started. This is not really the functionality you had in mind (or, it shouldn't be anyway, because from a User's viewpoint that would not be the expected behavior for a PunchIn button). So you really need to re-set in the PunchIn Click.

    Here's another thing that might help you better conceptualize the global variables. They can all be accessed with "this." ... in fact, that's the preferred syntax to use for precisely this reason ... to avoid confusion between global variables and local variables (and also static variables ... but that's another kettle of fish, so let's not bother about static for now).

    So, in your Click events, you should be referring to those DateTimes like so:

    private void btnPunchIn_Click(object sender, EventArgs e)
    {
        this.punchIn = DateTime.Now;
        this.lblPunchInTime.Text = this.punchIn.ToShortTimeString();          
    }
    
    private void btnPunchOut_Click(object sender, EventArgs e)
    {
        this.punchOut = DateTime.Now;
        this.lblPunchOutTime.Text = this.punchOut.ToShortTimeString();
        TimeSpan timeWorked = new TimeSpan();
        timeWorked = this.punchOut - this.punchIn;
    
        int elapsedMinutes;
        if (this.punchOut.Minute >= this.punchIn.Minute)
            elapsedMinutes = this.punchOut.Minute - this.punchIn.Minute;
        else
        {
            int secondsTo60 = 60 - this.punchIn.Minute;
            elapsedMinutes = this.punchOut.Minute + secondsTo60;
        }
        this.lblTimeWorked.Text = string.Format("{0:00}:{1:00}", (int)timeWorked.TotalHours, elapsedMinutes);
    }
    


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    • Marked as answer by tddyballgm Monday, January 15, 2018 9:30 PM
    Monday, January 15, 2018 6:24 AM
    Moderator
  • Check another guess:

    DateTime punchIn = . . .
    DateTime punchOut = . . .
    
    DateTime a = new DateTime( punchIn.Year, punchIn.Month, punchIn.Day, punchIn.Hour, punchIn.Minute, 0 );
    DateTime b = new DateTime( punchOut.Year, punchOut.Month, punchOut.Day, punchOut.Hour, punchOut.Minute, 0 );
    
    int total_minutes = (int)( b - a ).TotalMinutes;
    int hours = total_minutes / 60;
    int minutes = total_minutes % 60;
    
    string result = string.Format( "{0:00}:{1:00}", hours, minutes );
    

     

    If still not good, give an example of times.

    Monday, January 15, 2018 6:34 AM
  • Are you in the Central Time Zone? If not, OK, but if you are, why would you jump through those hoops to declare the time (DateTime.Now.ToToUniversalTime().AddHours(-6))?

    I did that because based on what I read, UTC is much more accurate, but when I declared the DateTime.Now.ToUniversal, it was 6 hours ahead, so in order to get it to my local time, Central, I did the .AddHours(-6).

    If I were to use UTC, how else do I get it to my local time?

    Seems the more I try to learn, the more confused I get.  :)  If I declare DateTime punchIn = DateTime.Now.ToUniversalTime(); at the Form level, but then have this.punchIn = DateTime.Now; at the button click event level, am I using the time on my device or UTC?


    • Edited by tddyballgm Monday, January 15, 2018 7:12 AM
    Monday, January 15, 2018 6:58 AM
  • DateTime.Now gives you the local time, the time on your device. There is no point in using DateTime.Now.ToUniversal (which gives you UTC) if you are going to use your local time, Central (by subtracting the 6 hours).

    UTC is not more *accurate*, but it's possible that it's more *appropriate*. But that is *only* if you are going to be storing the dates in a database in another time zone (like in the cloud) and even then it depends on the use case. It still might be fine to store the dates as local time. 

    But definitely, if the application and data is always going to be local, you do not need UTC dates. Don't complicate things for yourself if you don't need to.


    ~~Bonnie DeWitt [C# MVP]

    http://geek-goddess-bonnie.blogspot.com

    Monday, January 15, 2018 3:15 PM
    Moderator
  • Yea funny, talking about an accurate time and than cutting on minutes. 

    When I wrote my reply with my answer I had to think about a fellow employee who did jobs from around 5 minutes. The boss wanted him to clock every separate job. There was a same system like you use, he never reached his hours. 

    However, I get the idea you never did look at the solution I gave. While it completely does what you ask.


    Success Cor

    Monday, January 15, 2018 3:34 PM
  • Cor, I have tried every suggestion provided, and if I couldn't get it to work, odds are it was my error.

    What I am trying to accomplish is an employee getting paid for the hours and minutes the clock shows they are punched in.  The issue I was running in to was, if an employee punched in at 12:00:30 and then punched out at 4:00:20, the total time would calculate to 3:59 when the 'timeclock' shows the employee worked 4 hours.

    Technically, the employee did not work that last full minute, but they still expect to get paid for it, and any company would expect them to get paid for it as well, so I needed a way to eliminate the seconds from the calculation and just look at the hours and minutes.

    Does that make sense?

    I tried to replicate the error I received, but I can't seem to find the entire code you provided.  See - user error, not anyone's code error.  :)

    Bonnie was the first person to suggest a solution and was very good at helping me, so I was pretty much focused on her suggestions.  Which seem to work as I hoped - including a punch past midnight, which I was pleasantly pleased with.


    Monday, January 15, 2018 4:36 PM

  • Does that make sense?


    No in the way you state it you can use all ways using the timespan (which also works passing zero hour while my solution not). 

    But instead of the floor you should use the ceiling (does not exist but 59 seconds creates that). 

                DateTime Clocked = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 19, 30, 0); //19:30
                TimeSpan TimeDone =  Clocked.AddSeconds(59) - DateTime.Now;
                Console.WriteLine(TimeDone.Hours.ToString() + ":" + TimeDone.Minutes.ToString("00"));
                Console.ReadKey();

     

    Success Cor

    Monday, January 15, 2018 5:23 PM
  • When using that code (with Floor), I did not get the result I was expecting.  I punched-in at 2:51:25 and punched-out at 2:52:10.  As an employee looking at the clock, I would think I should have received a minute of work, but instead I was given 0:00

    Start Time                      Stop Time                      Time Worked

    2:51 PM                       2:52 PM                       00:00

    When I tried Ceiling, I punched in at 2:57:25 and punched out at 2:58:30.  I would have expected one minute of work, but I received 2 as a result

    Start Time                      Stop Time                      Time Worked

    2:57 PM                       2:58 PM                       00:02

    I am all for using any solution that works, but for my particular situation, this does not seem to work as I was hoping.  There is a distinct chance I am doing something wrong, but so far I could not get it to produce the desired result.  I really do appreciate all the help and feedback, it has been great!

    NOTE: I tried to paste the image of the actual output, but I received a message saying I could not do that until my account was verified.  I am not sure what that means, so I just typed in the results.


    • Edited by tddyballgm Monday, January 15, 2018 9:09 PM
    Monday, January 15, 2018 9:04 PM