FT8: Time Adjustment Windows 10


Just before Christmas 2019, I performed a demonstration of FT8 at the local radio club. The lack of internet access and zero phone signal made synchronisation of my laptop clock impossible.

Luckily, the free running clock remained within 300 ms of actual time allowing the demonstration to proceed. It is obvious on WSJT-X when the clock on Windows is out of step. The third column ‘DT’ shows the time deviation in seconds. From experience, it seems that FT8 works fine if the timing is reasonably close (within +/- 2.5 s). However, as the clock moves further away from the exact time, the total number of decodes seem to decrease.

Unless I am missing something, I could not find an easy way of manually changing the Windows 10 clock to the nearest second.

 

Solution


What is required is a simple program running on Windows 10 that can read the current time, increment or decrement this by a set amount in ms and then reset the computer with the new time. Fortunately, the Windows 32 Function: ‘GetSystemTime’ returns a structure SYSTEMTIME that includes resolution in milliseconds.

 

typedef struct SYSTEMTIME
{
  WORD wYear;
  WORD wMonth;
  WORD wDayOfWeek;
  WORD wDay;
  WORD wHour;
  WORD wMinute;
  WORD wSecond;
  WORD wMilliseconds;
}

 

My initially attempt using C created a nightmare solution. It turned out to be quite difficult and a pain in the proverbial.  Imagine that the date and time happened to be exactly: 31/12/2020 at 24:59:59 and 999 ms. If you add 1ms to this, the time display changes to 1/1/2021 at 00:00:00 and 000 ms. The incremented time must carry through all the time denominations and take into account leap years and the variation in the number of days in the month!  Of course, this must also occur travelling backwards in time.

The python language includes a ‘time delta’ function in the timedelta library that allows time data to be incremented or decremented as required. That is exactly what is needed. The following code reads the windows clock and sends out the modified time using Window 10 API SetSystemTime’.

The Python Code

import sys
from datetime import date
from datetime import time
from datetime import datetime
from datetime import timedelta
import win32api

print("Time Adjust")
print("input the time change in microseconds (use plus or minus): ")
value = input()
print("Value is: ", value)
c = int(value) * 1000

date_before = datetime.utcnow()
print ("The previous time is" , date_before)
date_after = date_before + timedelta(microseconds=int(c))
print ("The Processed time is" , date_after)

d=date_after.strftime("%f")

time_tuple = ( int(date_after.strftime("%Y")), # Year
               int(date_after.strftime("%m")), # Month
               int(date_after.strftime("%d")), # Day
               int(date_after.strftime("%H")), # Hour
               int(date_after.strftime("%M")), # Minute
               int(date_after.strftime("%S")), # Second
               int(int(d)/1000), # Millisecond
              )

dayOfWeek = datetime(*time_tuple).isocalendar()[2]
t = time_tuple[:2] + (dayOfWeek,) + time_tuple[2:]
win32api.SetSystemTime(*t)
print("\n")
date_after = datetime.utcnow()
print ("The Updated time is" , date_after)

To allow the ‘SetSystemTime’ function to work, the Python code must be run as administrator.  I should point out that Microsoft warns users not to mess with the windows clock. Setting it back into the past could upset some programs. Consider yourself warned – proceed at your own risk.

Luckily, when used intelligently, these codes only change the clock by tiny amounts and so it is unlikely to cause problems. After using this code, when I have finished with FT8, I normally resync the computer time using an internet time server that overwrites any changed settings. Ironically, after doing this, the time accuracy of the computer seems worse than before!

 

The C Code


The second attempt using C proved much easier.  it turns out that there exists an API that converts a SYSTEMTIME array into a FILETIME object.  FILETIME holds a very large integer representing the number of 100 ns time intervals since 1st January 1601 (UTC).  This number is easily modified to reflect the required time change.  Another API converts FILETIME back into SYSTEMTIME which is then ready for updating the clock.  The ‘SetSystemTime’ function only works if the executable file is run as administrator. If an attempt is made to run the program as a user without administrator rights then it will fail and do nothing. The code reports a failure. See below.

Code Failure – Not Administrator

Code Success – Administrator

The steps consist essentially of four Windows API calls with minimal code manipulation.  Hence it stands a good chance of working.  I tested the code under three conditions:  1 ms time cascade, 1 ms time cascade through a leap year and a 1 ms cascade on a year that was not a leap year.  It all worked perfectly – well done Microsoft.  In each case, 1 ms was first added and then subtracted to see what happens.

1 ms Time Cascade – General

1 ms Time Cascade – Leap year

1 ms Time Cascade – No Leap year

The code is nearly all lifted out of Microsoft published documentation.  I claim no originality here.

#include <iostream>
#include <windows.h>
#include <stdio.h>
using namespace std;

SYSTEMTIME st;
FILETIME ft;
long long int time;

void start()
{
    printf("Please input the time in milliseconds that you want to advance or recede your windows clock\n");
    printf("Please be sensible\n");
    // 'time' can be positive or negative
    cin >> time;                  
    printf("\n");

    // Get the System time. 
    GetSystemTime(&st);	

     
    // Print out the Original Date and time of the Computer
    printf(" Original System Time:  ");
    printf("Day %d    %d:%d:%d  %d:%d:%d:  %dms \n", st.wDayOfWeek , st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);


    // Convert from 'SYSTEMTIME' to 'FILETIME'     
    SystemTimeToFileTime(&st, &ft);


    //FILETIME contains the number of 100ns ticks from the year 1601 in a very large integer
    //The integer is in two parts and needs assembling into a 64 bit ULONGLONG type 
    ULONGLONG qwResult = (((ULONGLONG)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;

    
    // Do the Mathematics - add on the number of milliseconds chosen in time
    qwResult += 10000*(ULONGLONG)time;


    //Reassemble the two parts of FILETIME
    ft.dwLowDateTime = (DWORD)(qwResult & 0xFFFFFFFF);
    ft.dwHighDateTime = (DWORD)(qwResult >> 32);


    // Convert from 'FILETIME' to 'SYSTEMTIME'
    FileTimeToSystemTime(&ft, &st);


    // Print out the Modified Date and time of the Computer
    printf(" Modified Sytem Time    ");
    printf("Day %d    %d:%d:%d  %d:%d:%d:  %dms \n", st.wDayOfWeek, st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);


    // Set the WINDOWS time function
    int p = SetSystemTime(&st);
    if (p == 0)
    {
        // Fail - The program can only set WINDOWS time if it is run in administrator mode. 
        GetSystemTime(&st);
        printf("\nFailed - The system time remains: %d:%d:%d  %d:%d:%d: %dms\n", st.wDay, st.wMonth, st.wYear,
        st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
        printf("This could be a failure to update the time or more likely this program is not run in ");
        printf("administrator mode - right click on the file and use:  Run as Administrator");
    }
    else
    {
        //Success
        GetSystemTime(&st);
        printf("Success -The actual system time is: %d:%d:%d  %d:%d:%d: %dms\n", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
    }
}


int main()
{
    while (1)
    {
        start();
        printf("\n\nStart over again\n");
    }
    return 0;
}

 

 


 

73 Chris

 

Back to top of page