How to solve the problem of incorrect System Uptime being reported when a system has been up for a long time

Joe WinogradDeveloper
CERTIFIED EXPERT
50+ years in computers
EE FELLOW 2017 — first ever recipient of Fellow award
MVE 2015,2016,2018
CERTIFIED GOLD EXPERT
DISTINGUISHED EXPERT
Published:
Updated:
The Windows functions GetTickCount and timeGetTime retrieve the number of milliseconds since the system was started. However, the value is stored in a DWORD, which means that it wraps around to zero every 49.7 days. This article shows how to solve that problem by using the GetTickCount64 function.

In an interesting question posted here at Experts Exchange, a member asked for a program/script that would perform a reboot if a Windows system has been up for more than a specified amount of time (in his company's case, the IT standard for this is more than 14 days). He also wants an option so that the user can delay the reboot for a specified amount of time (in his company's case, 15 minutes), but a "nag" dialog would continue to be re-displayed until the user finally agrees to a reboot.


Key to a solution for this is the ability to determine how long it has been since a system was started. Fortunately, Windows knows this and makes it available via function calls. One of the function calls is GetTickCount and is documented here:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms724408(v=vs.85).aspx


Another function is timeGetTime, documented here:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd757629(v=vs.85).aspx


Both of them perform similarly, i.e., returning the elapsed milliseconds since the system was started. Some scripting/programming languages use this capability to make the system uptime available in a built-in variable. For example, the AutoHotkey language has a built-in variable called A_TickCount, which it defines as:

The number of milliseconds since the computer was rebooted.


Using this built-in variable, here's one line of AutoHotkey code that calculates the system uptime in days:


UptimeDays:=(A_TickCount/1000)/(60*60*24)


Well, close, but no cigar! Why? If you read the Microsoft documentation referenced above, you'll see that GetTickCount and timeGetTime both store the value in a DWORD. Because of this, they work for up to 49.7 days only!


To overcome this limitation, Windows provides the GetTickCount64 function, documented here:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms724411(v=vs.85).aspx


This returns the elapsed milliseconds since the system was started, but without the 49.7 day limitation.


If your programming/scripting language doesn't provide that as a built-in variable, you should be able to make a DLL call to get it. For example, in AutoHotkey, this will retrieve it:


TickCount64:=DllCall("Kernel32.dll\GetTickCount64","UInt64")


Here's a working AutoHotkey script that shows everything mentioned above:


BuiltInTC:=A_TickCount
GetTC:=DllCall("Kernel32.dll\GetTickCount","UInt")
timeGT:=DllCall("Winmm.dll\timeGetTime","UInt")
GetTC64:=DllCall("Kernel32.dll\GetTickCount64","UInt64")
MsgBox,,Uptime Tests,BuiltInTC=%BuiltInTC%`nGetTC=%GetTC%`ntimeGT=%timeGT%`nGetTC64=%GetTC64%


I ran that script on a WS2012R2 system that had been up for more than 49.7 days. Here's the result:



On the same WS2012R2 system, I then ran another AutoHotkey script that calculates the uptime in days based on both the A_TickCount built-in variable and a call to the GetTickCount64 function. Here's the result:



Problem solved!  Note that 87.3-37.6=49.7, which shows that, because of the DWORD limitation, the count essentially starts over at zero every 49.7 days — hence, the need to call GetTickCount64.


Here's a complete, tested AutoHotkey script, based on calling GetTickCount64, that satisfies the requirements specified in the first paragraph of this article:


#Warn,UseUnsetLocal ; warning on uninitialized variables
#NoTrayIcon ; do not show an icon in the system tray
#NoEnv ; avoid checking empty variables to see if they are environment variables
#SingleInstance ignore ; leave old instance running
SetBatchLines,-1 ; run at maximum speed
SetFormat,float,0.1 ; uptime in days to one decimal place

; begin params you may want to change
UptimeDaysLimit:=14
NagTimeMinutes:=30
; end params you may want to change

NagTime:=1000*60*NagTimeMinutes ; param to Sleep is in milliseconds
NagAgain:
UptimeMilliseconds:=DllCall("Kernel32.dll\GetTickCount64","UInt64")
UptimeDays:=(UptimeMilliseconds/1000)/(60*60*24)
If (UptimeDays>UptimeDaysLimit)
{
  ; MsgBox options (https://autohotkey.com/docs/commands/MsgBox.htm):
  ; 1 - Buttons are OK and Cancel
  ; 48 - Icon is exclamation
  ; 256 - Second button is default (to avoid accidental Enter key causing a reboot)
  ; 4096 - Dialog is always on top
  MsgBox,4401,System Uptime Warning,Your system has been up for %UptimeDays% days`n`nClick OK to reboot now or Cancel to be reminded again in %NagTimeMinutes% minutes
  IfMsgBox,OK
  {
    ; Shutdown options (https://autohotkey.com/docs/commands/Shutdown.htm):
    ; 0 - Logoff
    ; 1 - Shutdown
    ; 2 - Reboot
    ; 4 - Force
    ; 8 - Power down
    Shutdown,2
  }
  Else
  {
    Sleep,%NagTime%
    Goto,NagAgain
  }
}
ExitApp


I commented the code heavily to serve as documentation for it, but if you have questions about how it works, please post here and I'll be happy to try to answer.


Sidebar:

If you're not familiar with AutoHotkey and this article has piqued your interest in it, this other EE article will help you to get started with it:

AutoHotkey - Getting Started

End Sidebar


As a final comment on the issue of determining system uptime, it has been documented that TickCount functions can be inaccurate in Windows 10 because of the Fast Startup feature, which is enabled by default in W10. You may disable it (when logged in as an admin) as follows:


Control Panel

Power Options

Choose what the power buttons do

Change settings that are currently unavailable


You'll see this:



Un-check the Turn on fast startup (recommended) box, which will be checked by default (if you don't have that box, it means that Hibernation is not enabled).


If you find this article to be helpful, please click the thumbs-up icon below. This lets me know what is valuable for EE members and provides direction for future articles. Thanks very much! Regards, Joe


3
6,676 Views
Joe WinogradDeveloper
CERTIFIED EXPERT
50+ years in computers
EE FELLOW 2017 — first ever recipient of Fellow award
MVE 2015,2016,2018
CERTIFIED GOLD EXPERT
DISTINGUISHED EXPERT

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.