Android Code Snippet DIY NTP Network Atomic Clock Time

I just ported some NTP stuff from an old program.

Querying an NTP server is surprisingly easy: just send it a 48 byte UDP packet with the first byte = 27 and the rest of them 0.

The NTP server should return your 48 byte packet updated with the last 16 bytes set to two 64-bit timestamps, being when it (i) received your request and (ii) soon-after sent its response.

My code "returns" 4 timestamps NTPTimeStamp(1) thru NTPTimeStamp(4), matching T1..T4 of this command-line utility:

https://kb.meinbergglobal.com/kb/public_utilitiy_programs/ntptest_-_check_ntp_server

except that my timestamps are in Java ticks (ms since 1970) for easy use with DateTime formatting etc.

I did this example with B4J but the same principles work in B4A (as in: I've run similar code successfully there too).

[CODE lang="b4x" highlight="12-17,25,28,40,62-70"]#Region Project Attributes
#MainFormWidth: 300
#MainFormHeight: 300
#End Region

Sub Process_Globals
Private fx As JFX
Private MainForm As Form
Private xui As XUI
Private Button1 As B4XView

Dim UDPSocket1 As UDPSocket

Dim NTPPort As Int = 123
Dim NTP1970 As Long = ((1970 - 1900) * 365 + 17).As(Long) * 86400

Dim NTPTimeStamp(5) As Double 'to match T1..T4 of Meinberg NTPTEST utility
End Sub

Sub AppStart (Form1 As Form, Args() As String)
MainForm = Form1
MainForm.RootPane.LoadLayout("Layout1")
MainForm.Show

UDPSocket1.Initialize("UDP", NTPPort, 8000)
End Sub

Sub SendNtpRequest(NTPServerName As String)
Dim data(48) As Byte
data(0) = 27

Dim Packet As UDPPacket
Packet.Initialize(data, NTPServerName, NTPPort)

NTPTimeStamp(4) = 0 'so can tell if received reply
NTPTimeStamp(1) = DateTime.Now
UDPSocket1.Send(Packet)
End Sub

Sub UDP_PacketArrived (Packet As UDPPacket)
If Packet.Length < 48 Then Return

NTPTimeStamp(4) = DateTime.Now

Dim StartFrom As Int = Packet.Offset + 32
For ServerTimeStamp = 2 To 3
Dim Temp As Long = 0
For I = StartFrom To StartFrom + 6 '7 bytes (32 bits seconds + 24 bits fraction)
Temp = Bit.ShiftLeftLong(Temp, 8) + Bit.And(Packet.Data(I), 0xFF)
Next

Dim NTPSeconds As Double = Temp / 0x1000000 'shift binary point 24 bits left
Dim JavaTicks As Double = (NTPSeconds - NTP1970) * 1000

NTPTimeStamp(ServerTimeStamp) = JavaTicks

StartFrom = StartFrom + 8 'next 64-bit timestamp
Next
End Sub

Sub Button1_Click
Dim NTPServerName As String = "au.pool.ntp.org"

SendNtpRequest(NTPServerName)
Sleep(2000)

If NTPTimeStamp(4) = 0 Then
Log("No reply from " & NTPServerName)
Return
End If

Log(NTPServerName)
For I = 1 To 4
Log("T" & I & " = " & NumberFormat2(NTPTimeStamp(I), 1, 3, 3, False))
Next

Dim LocalTimeMiddle As Double = (NTPTimeStamp(1) + NTPTimeStamp(4)) / 2
Dim ServerTimeMiddle As Double= (NTPTimeStamp(2) + NTPTimeStamp(3)) / 2
Dim DeviceToNTPOffset As Double = ServerTimeMiddle - LocalTimeMiddle

If DeviceToNTPOffset < 0 Then
Dim Direction As String = "ahead of"
Else
Dim Direction As String = "behind"
End If

Log( _
"Device clock is " & _
NumberFormat2(Abs(DeviceToNTPOffset), 1, 1, 1, False) & _
" ms " & Direction & " NTP server time (roundtrip " & _
NumberFormat2(NTPTimeStamp(4) - NTPTimeStamp(1), 1, 1, 1, False) & _
" ms)" _
)

DateTime.TimeFormat = "hh:mm:ss.SSS"
Dim N As Long = DateTime.Now
Log("Device clock = " & DateTime.Time(N))
Log("NTP clock = " & DateTime.Time(N + DeviceToNTPOffset))
End Sub[/CODE]
 
Last edited:
Sample run. Don't panic about the long roundtrip times: I am at a location with internet supplied wirelessly via Vodafone. When I get back home tomorrow, I'll update the sample using tic.ntp.telstra.net which usually pings around 5 ms.

[CODE lang="html" title="Log output" highlight="8,16"]Waiting for debugger to connect...
Program started.
au.pool.ntp.org
T1 = 1708868547753.000
T2 = 1708868548012.398
T3 = 1708868548012.410
T4 = 1708868548126.000
Device clock is 72.9 ms behind NTP server time (roundtrip 373.0 ms)
Device clock = 12:42:29.854
NTP clock = 12:42:29.926
au.pool.ntp.org
T1 = 1708868553886.000
T2 = 1708868554102.279
T3 = 1708868554102.287
T4 = 1708868554216.000
Device clock is 51.3 ms behind NTP server time (roundtrip 330.0 ms)
Device clock = 12:42:35.894
NTP clock = 12:42:35.945[/CODE]
 
tic.ntp.telstra.net which usually pings around 5 ms.

4.8 ms ?

[CODE lang="b4x" title="ntptest tic.ntp.telstra.net" highlight="25"]Precise system time is supported and used
Host tic.ntp.telstra.net
Request packet: mode 3 (client)
version 4, leap 3, stratum 0, poll 6, prec -18 (3.81 us)
root delay: 00000000 (0.000000 s)
root dispersion: 00000000 (0.000000 s/s)
reference id: 00000000 ("....")
Ref time: 00000000.00000000 2036-02-07 06:28:16.000000000
Org time (T1): 00000000.00000000 2036-02-07 06:28:16.000000000
Rcv time (T2): 00000000.00000000 2036-02-07 06:28:16.000000000
Xmt time (T3): E9818916.238F6DC6 2024-02-22 08:49:26.138907299
Curr time (T4): E9818916.238F6DC6 2024-02-22 08:49:26.138907299

Response packet: mode 4 (server)
version 4, leap 0, stratum 2, poll 6, prec -24 (59.60 ns)
root delay: 000000AF (0.002670 s)
root dispersion: 0000054B (0.020676 s/s)
reference id: 27B48E6E (110.142.180.39)
Ref time: E9818835.534C027A 2024-02-22 08:45:41.325378565
Org time (T1): E9818916.238F6DC6 2024-02-22 08:49:26.138907299
Rcv time (T2): E9818916.2D1D6CF4 2024-02-22 08:49:26.176230248
Xmt time (T3): E9818916.2D1E13C9 2024-02-22 08:49:26.176240192
Curr time (T4): E9818916.24CA0572 2024-02-22 08:49:26.143707599

turnaround: 4800.300 us (T4 - T1)
server latency: 9.944 us (T3 - T2)
computed delay: 4790.356 us ((T4 - T1) - (T3 - T2))
computed offset: 34927.771 us (((T2 - T1) + (T3 - T4)) / 2)[/CODE]
 
1708872137550.png
 
Back
Top