1

I am an inexperienced developer fresh out of college. I was handed a Windows Forms Application to work on.

The application previously relied on system time. They wanted me to make it so that we could adjust the time within the application. No problem at all for me, I just added in some number selectors for up to +/- 23hrs, 59 mins, and 59secs.

I then I simply added this offset to the system time and used that as the clock within the application and all was well.

However, it was at this time that I was informed by one of my internal customers (one of the occasional users for this software & a supervisor) that he sometimes changes the time on his PC to the local time, and then when he connects to our network via VPN the time on his PC gets rest to our network time.

This was a problem since if user traveled to another time zone and then changed the time on his PC manually, then set up our application with the time adjusted to match the time of the client's clock at the job site, then when he connected to our network by VPN (for one reason or another), it would reset the time and then the system time plus the offset would no longer match up to the client's time. (asking users not to alter the time is not an option it seems).

In order to solve this problem I took the following steps:

  1. create a new Date object for our internal time (lets call it "RATA time")
  2. Plant time is initially equal to the system time
  3. you can add an offset to that time to match the time at the job site
  4. Then I capture a start time and used a timer to keep track of the seconds that pass and keep adding them to the start time to get the current time and it is unaffected by the system time

VB.NET code:

Private Sub dataTimer_Tick(sender As System.Object, e As System.EventArgs) Handles dataTimer.Tick
        seconds += 1
        time = TimeSpan.FromSeconds(seconds)
        RATAtime = startTime + time '+ offset
        
        formattedRAtaTime = RATAtime.ToString("HH\:mm\:ss")
        lblRataTime.Text = formattedRAtaTime
        lblRunningTime.Text = time.ToString("hh\:mm\:ss")
    End Sub

So what went wrong? Answer: "RATA time" is falling behind the actual time. It's especially bad on a slow computer.

I think the issue is that the timer is not a real time system and only meant to be so accurate. the processor will get to it whenever it gets to it and no necessarily immediately. It may be an issue with not using await and asynch, which is a way to ensure threading is being properly implemented.

What is the best way to go about this? Computers may or may not have internet access while the application is being run.

Extra info: in desperation I even tried reading the time off of a device that this application interacts with, while I was successful in doing so, and parsing it into a date object, when I tried to set RATA time to that value, it was not happening and the debugger was saying there was an issue with threads. That was never an elegant or desirable solution though. Here is that code if anyone feels that that would help:

    Private Sub ParseLoggerTime(response As String)
        Dim loggerTime As Date

        ' Check if the response has the expected format
        If response(0) = "@" AndAlso response.Substring(5, 2) = "LL" AndAlso IsNumeric(response.Substring(7, 12)) AndAlso response(19) = "&" Then
            Dim year As Integer = Convert.ToInt32("20" & response.Substring(7, 2))
            Dim month As Integer = Convert.ToInt32(response.Substring(9, 2))
            Dim day As Integer = Convert.ToInt32(response.Substring(11, 2))
            Dim hour As Integer = Convert.ToInt32(response.Substring(13, 2))
            Dim minute As Integer = Convert.ToInt32(response.Substring(15, 2))
            Dim second As Integer = Convert.ToInt32(response.Substring(17, 2))

            Try
                loggerTime = New Date(year, month, day, hour, minute, second)
                lblLogger.Text = loggerTime.ToString("HH\:mm\:ss") ' Update the label here
                loggerTimeGlobal = loggerTime
            Catch ex As Exception
                ' Handle any potential DateTime creation exception here
                ' You might want to log the error or notify the user
                loggerTime = Date.MinValue ' Set to a default value
                lblLogger.Text = "Error" ' Update the label here with an error message
            End Try
        Else
            ' Handle invalid response format here
            loggerTime = Date.MinValue ' Set to a default value
            lblLogger.Text = "Invalid Format" ' Update the label here with an error message
        End If
    End Sub

The code for setting RATA time = logger time was put in the timer tick handler function/ procedure.

3
  • 1
    Is using the TimeZone/TimeZoneInfo classes an option?
    – T. Sar
    Commented Sep 1, 2023 at 22:57
  • 1
    When you say "he sometimes changes the time on his PC to the local time" do you mean he changes the time zone so that the PC displays the local time (even though the underlying UTC time has not changed)? Or is he literally messing with the UTC time on the PC?
    – John Wu
    Commented Sep 2, 2023 at 2:16
  • I tried to explain to my boss that this user should only be changing the time zone which is a display. However, he actually literally messes with the system time and not simply changing the time zone. I've spent four times the amount of time idiot proofing as I have developing features.
    – mpAppProg
    Commented Sep 2, 2023 at 3:31

4 Answers 4

2

Instead of capturing the start time and using a timer, capture the start time and record the operating system tick count.

StartTime = DateTime.Now; 'Or however you are currently computing it
StartTick = Environment.TickCount

To get the current time, compute the number of elapsed ticks and add it to the start time.

CurrentTime = StartTime.AddMilliseconds(Environment.TickCount - StartTick)
1
  • 1
    Thank you so much John! I will try this as soon as possible and see if it works. I didn't even know that I could use the system tick count. I searched online but perhaps not for the right thing. I found the documentation now by searching for ".NET system time ticks". I really appreciate your help!
    – mpAppProg
    Commented Sep 2, 2023 at 3:28
4

This sounds like you're in a pretty unenviable position, as you're expected to satisfy conflicting stupid requirements.

First off, messing with system time is a bad idea in general, especially when applications have time-sensitive behavior and aren't just displaying time. This implies that neither the original requirement (being able to offset the time within the application) nor the behavior of this internal user are very reasonable.

Second, "not an option to ask users to not set their time" is another stupid requirement. Asking (or telling users about the consequences of their behavior) should always be an option.

But since you're apparently not in a position to nudge incompetent superiors towards reason, you may well be forced to somehow comply with the stupidity at the end of the day.

The system tick may be a not so good idea, as it is possible that it doesn't exactly stay synced with wall clock time. I would rather rely on the system time and let the user set an offset for time display within your application, and document it such that changing the system time while your application is running will naturally change the time displayed within your application and may require the user to set the time offset again.

1
  • Hello Hans I do agree with you. In testing, I did notice occasional fallback of 1-2 seconds even on system ticks. Why is that the case though? a bug in my code? or des the system loose ticks sometimes and then correct itself if connected to the internet?
    – mpAppProg
    Commented Sep 8, 2023 at 13:46
1

IMHO you are approaching this from the wrong angle. As mentioned, the OS already provides a local time zone as an offset to the system time / UTC. Under modern Windows systems, it requires less clicks to change the user's time zone than the system time, and no administrative rights.

So my first recommended approach here would be against reinventing the wheel, and reuse the user's local time provided by the OS. If you try to reimplement the local time shift in the application, you get potentially 3 different times, which becomes obviously error prone. If it is really a requirement to change the time zone directly within the application, then change the local time, don't use your own offset.

My second approach here is to make it more transparent what happens: your application's UI will somewhere show the used (local) time. Show the system time nearby (maybe with some smaller, unobtrusive font), and name both time fields accurately.

If users then start to mess around with UTC and local time, they will then hopefully understand what they are doing - so you and your boss don't have to ask them not to change their system time, they will just learn it by themselves.

5
  • Hello Doc Brown, We adjust the time within the app to match the clocks of the site (power plant or cement factory etc. even if it is inaccurate to their local time. I display the system time and the "plant time" within the application. I know it it easier to just change the time zone instead of messing with the system time but apparently ONE specific, but important user is too accustomed to doing it that way only. IT gave admin rights to allow minute and seconds adjustment wen software didn't have internal time.
    – mpAppProg
    Commented Sep 5, 2023 at 13:45
  • my own offset is implemented because minutes and seconds need to match up. The other issue we have is that one user goes to Columbus Ohio, sets up his computer to Easter time by changing the system time (not just the time zone) and then connects to our network by VPN which resets his system time. For many reasons, users should never be allowed to mess with system time, however one of the internal clients is the one who is quite set in his methods.
    – mpAppProg
    Commented Sep 5, 2023 at 13:52
  • If we find that that happens to be the only way to do things I will need to ask them to revoke those rights and let users change the time zone as they please and use an offset from UTC to represent the exact time (to the second) that is displayed on the clocks at the plant/ factory
    – mpAppProg
    Commented Sep 5, 2023 at 13:54
  • 1
    @mpAppProg: it seems the real problem is that the "internal client" you describe changes the system time, whilst the VPN connect resets it. Your own program isn't involved at this point, right? So your client believes he is allowed to change the system time, but your VPN software has a different opinion on that. That's the issue you need to solve first, and it is nothing you can do inside your own software.
    – Doc Brown
    Commented Sep 5, 2023 at 15:54
  • That is a correct assessment of the situation. the IT manager's policy is that, for security reasons, the network must reset the time to our network time. The internal client probably got used to changing the PC time due to the way that the old software used to work I assume. In order to keep him happy we are relying on system ticks and just calculating the elapsed time accurately at a roughly one second interval. The other internal client who is also a co-client for this software doesn't care much for all the idiot proofing (our users ae all, thus far, our own employees)
    – mpAppProg
    Commented Sep 8, 2023 at 13:44
0

Will just add that the thread exception you got when trying to update the time by using external device is probably (can't be sure without seeing the full exception message) due to the fact the timer you use didn't run on the main GUI thread, and in your code you try to update the GUI by stetting the lblLogger.Text property.

If this is indeed the case, you can look here for the general idea how to: Invoke UI Changes Across Threads on VB .Net

Not the answer you're looking for? Browse other questions tagged or ask your own question.