HTP uses time information present in HTTP headers to determine the clock offset between two machines. It can be used to synchronize the local clock using a trusted HTTP(S) server, or to determine the time of the remote machine.
Important
If NTP is available, use it instead. I developed this application to be able to synchronize my computer's clock in a network that blocked NTP packets.
Download the binary for your platform from the releases page.
Or install it with go
:
go install github.com/danroc/htp/cmd/htp@latest
To build the main application, run:
go build ./cmd/htp
Suppose that T is the correct time (remote time) and our local time is offset by θ (thus local time is T + θ).
To approximate θ, we perform these steps:
- (A, local) sends a request to (B, remote) at t₀ (local clock)
- (B) receives and answers (A)'s request at t₁ (remote clock)
- (A) receives (B)'s answer at t₂ (local clock)
These steps are represented in the following diagram:
t₁
(B) --------^--------> T
/ \
/ \
(A) -----^-----v-----> T + θ
t₀ t₂
Bringing t₁ to the local time (between t₀ and t₂):
t₀ < t₁ + θ < t₂ ⇒ t₀ - t₁ < θ < t₂ - t₁
So,
- θ > t₀ - t₁
- θ < t₂ - t₁
But we must use ⌊t₁⌋ instead of t₁ in our calculations because it is the only time information present in the HTTP response header.
Since t₁ ∈ [⌊t₁⌋, ⌊t₁⌋ + 1), then:
- θ > t₀ - ⌊t₁⌋ - 1
- θ < t₂ - ⌊t₁⌋
Observe that the closer t₁ is to ⌊t₁⌋ or ⌊t₁⌋ + 1, smaller is the error in the second or first equation above, respectively.
We can repeat the above procedure to improve our estimate of θ:
- θ⁻ = MAX(θ⁻, t₀ - ⌊t₁⌋ - 1)
- θ⁺ = MIN(θ⁺, t₂ - ⌊t₁⌋)
- θ = (θ⁺ + θ⁻)/2
The ideal delay d to wait before sending the next request is calculated so that the next value of t₁ is close to a "full" second:
t₂ + d + (t₂ - t₀)/2 - θ = ⌊t₁⌋ + k, k ∈ ℤ
⇒ d = ⌊t₁⌋ + k + θ - t₂ - (t₂ - t₀)/2 mod 1
⇒ d = θ - t₂ - (t₂ - t₀)/2 mod 1
Where:
- (t₂ - t₀) is an estimation of the round-trip time (RTT).
- - θ converts from local to remote time.
-
One-liner:
date -s "$(curl -fsSLI https://www.google.com | grep -i "Date: " | cut -d" " -f2-)"