I'd like to make a measurement of the difference between a local clock, and a remote processor running an NTP server.
I can get the tx_time of the response, as shown below, but a better estimate would include some estimate of the network delays. There are other fields in the NTP response message which should be used, as well.
import ntplib
from time import ctime,time
addr_remote = '128.128.204.207'
c = ntplib.NTPClient()
remote = c.request(addr_remote)
local = time()
print("REMOTE: " + ctime(remote.tx_time) + " <reference clock> ")
print("LOCAL: " + ctime(local) + " delta: " + str(local - remote.tx_time ))
If I look at "remote":
for attr in dir(remote):
print("remote.%s = %r" % (attr, getattr(remote, attr)))
I see:
remote.delay = 0.0
remote.dest_time = 1531863145.9309998
remote.dest_timestamp = 3740851945.9309998
remote.from_data = <bound method NTPPacket.from_data of <ntplib.NTPStats object at 0x000000000265B2E8>>
remote.leap = 0
remote.mode = 4
remote.offset = -1.8789582252502441
remote.orig_time = 1531863145.9309998
remote.orig_timestamp = 3740851945.9309998
remote.poll = 0
remote.precision = -7
remote.recv_time = 1531863144.0520415
remote.recv_timestamp = 3740851944.0520415
remote.ref_id = 0
remote.ref_time = 0.0
remote.ref_timestamp = 2208988800.0
remote.root_delay = 0.0
remote.root_dispersion = 0.0
remote.stratum = 9
remote.to_data = <bound method NTPPacket.to_data of <ntplib.NTPStats object at 0x000000000265B2E8>>
remote.tx_time = 1531863144.0520415
remote.tx_timestamp = 3740851944.0520415
So, how do I use these:
to remove the network delays, and get a better estimate of the clock difference?
The NTP client sends a packet with its local time orig_time
, which the NTP server receives at the server time recv_time
. The server then replies at server time tx_time
and the client receives that reply at local time dest_time
.
The round trip delay
is calculated as recv_time - orig_time + dest_time - tx_time
, and the offset between the clocks is offset = (recv_time - orig_time + tx_time - dest_time) / 2
.
Assuming the two NTP packets take consistent paths, the correct adjusted time is simply dest_time + offset
, which is equivalent to tx_time + delay/2
.
I found this answer while trying to syncing my client computer to NTP time and checking that it actually synced. Based on @Vic, this means that the client clock (compared to the server NTP clock) is always off by:
dest_time + offset = tx_time + delay/2
dest_time - tx_time = delay/2 - offset
i.e.
correction = delay/2 - offset
As @Vic said, packets may take different routes going to and coming from, but in average correction
should give you your clock offset (I think). Even by syncing with time.nist.gov
with os.system('w32tm /resync/nowait')
, my computer is always off by 40ms, somehow. Comments welcome!
This is my code.
import ntplib
from datetime import datetime, timezone
def get_ntp_time():
ntp_pool = ['pool.ntp.org', 'time.nist.gov']
def call_ntp(serverAddress):
call = ntplib.NTPClient()
return call.request(server, version=3)
for server in ntp_pool:
response = call_ntp(server)
print(f"server: {server}")
print(f"request packet sent (as LOCAL client time, orig_time): {datetime.fromtimestamp(response.orig_time, timezone.utc)}")
print(f"request packet received (as NTP server time, recv_time): {datetime.fromtimestamp(response.recv_time, timezone.utc)}")
print(f"response packet sent (as NTP server time, tx_time): {datetime.fromtimestamp(response.tx_time, timezone.utc)}")
print(f"response packet received (as LOCAL client time, dest_time): {datetime.fromtimestamp(response.dest_time, timezone.utc)}")
print(f'round trip duration: {response.delay} s')
print(f'* adjusted time, tx_time + delay/2: {datetime.fromtimestamp(response.tx_time + response.delay/2, timezone.utc)}')
print(f'* adjusted time, dest_time + offset: {datetime.fromtimestamp(response.dest_time + response.offset, timezone.utc)}')
print(f'correction to client: {response.delay/2 - response.offset} s\n')
# for attr in dir(response):
# if not attr .startswith('_'):
# print("response.%s = %r" % (attr, getattr(response, attr)))
print('-')
get_ntp_time()
Response:
server: pool.ntp.org
request packet sent (as LOCAL client time, orig_time): 2021-04-23 16:14:46.544797+00:00
request packet received (as NTP server time, recv_time): 2021-04-23 16:14:46.535852+00:00
response packet sent (as NTP server time, tx_time): 2021-04-23 16:14:46.535862+00:00
response packet received (as LOCAL client time, dest_time): 2021-04-23 16:14:46.579710+00:00
round trip duration: 0.03490257263183594 s
* adjusted time, tx_time + delay/2: 2021-04-23 16:14:46.553314+00:00
* adjusted time, dest_time + offset: 2021-04-23 16:14:46.553314+00:00
correction to client: 0.04384756088256836 s
-
server: time.nist.gov
request packet sent (as LOCAL client time, orig_time): 2021-04-23 16:14:46.642192+00:00
request packet received (as NTP server time, recv_time): 2021-04-23 16:14:46.641157+00:00
response packet sent (as NTP server time, tx_time): 2021-04-23 16:14:46.641158+00:00
response packet received (as LOCAL client time, dest_time): 2021-04-23 16:14:46.689054+00:00
round trip duration: 0.04686117172241211 s
* adjusted time, tx_time + delay/2: 2021-04-23 16:14:46.664588+00:00
* adjusted time, dest_time + offset: 2021-04-23 16:14:46.664588+00:00
correction to client: 0.0478968620300293 s
-
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With