22

I need my software to communicate with an NTP server to determine the local clock offset. I have tried using the org.apache.commons.net.ntp package, but its implementation is rather poor when running on Windows, because of the use of System.currentTimeMillis() to determine the time before and after the NTP packet exchange. As you may or may not know, this value is only updated when the system clock ticks, which on most modern Win2k3 servers is at 64Hz or every 15.625ms. This greatly limits the accuracy of the clock offset calculation.

Ntpd uses the CPU high-frequency timer to interpolate between system clock ticks, and achieve much higher resolution time. Do you know of a Java implementation that uses this or a similar technique? Or do you know of any other NTP implementation other than Apache's?

Matt Howells
  • 40,310
  • 20
  • 83
  • 102

5 Answers5

11

there is a NTP Java implementation on support.ntp.org

dfa
  • 114,442
  • 31
  • 189
  • 228
10

Since this question ranks very high on Google for "Java NTP client":

Android has a nice, compact Apache-licensed implementation of a Simple NTP client: android.net.SntpClient.

It would need to be modified to run on non-Android java, but this should be trivial, since the code is about 100 lines of code plus another 100 lines of detailed comments, with no external dependencies except the Android system clock - and by chance, it is ready to accept relative timers like nanoTime() since it already uses such a relative timer.

Jan Schejbal
  • 4,000
  • 19
  • 40
  • 1
    How do you replace `SystemClock.elapsedRealtime();` ? – Bhargav Mar 11 '16 at 05:08
  • 1
    `SntpClient` is annotated with `@hide`, so we can't use it (cleanly). – Kevin Robatel May 28 '20 at 09:55
  • @KevinRobatel The idea isn't directly using it; the reason why I mentioned the license is that you can include a private "forked" copy of it (with package name adjusted, and any other changes you need like a different timer). That's the approach I took when I had to use it. – Jan Schejbal May 28 '20 at 19:37
4

I have written a java implementation (Java 7) that you can use: SntpClient

Adrien Clerc
  • 2,636
  • 1
  • 21
  • 26
user2179737
  • 493
  • 3
  • 6
4

I know this is an old question but I notice that all the answers does not explain how to use those libraries. In this answer, we will go through a basic implementation and its logic behind.

A simple way to implement a NTP client is using Apache Commons Net library. This library will provide a NTPUDPClient class to manage connectionless NTP requests and return a TimeInfo instance. This instance should compute the offset between our system's time and the NTP server's time. Lets try to implement it here:

  1. Add the Apache Commons Net library to your project.
<dependency>
  <groupId>commons-net</groupId>
  <artifactId>commons-net</artifactId>
  <version>3.6</version>
</dependency>
  1. Create a new instance of the NTPUDPClient class.
  2. Setup the default timeout and the InetAddress of the NTP Server.
  3. Call the NTPUDPClient.getTime() method to retrieve a TimeInfo instance with the time information from the specified server.
  4. Call computeDetails() method to compute and validate details of the NTP message packet.
  5. Finally, get the offset and calculate an atomic time.

Here we have a basic implementation:

import java.net.InetAddress;
import java.util.Date;
import org.apache.commons.net.ntp.NTPUDPClient; 
import org.apache.commons.net.ntp.TimeInfo;

public class NTPClient {
  private static final String SERVER_NAME = "pool.ntp.org";

  private volatile TimeInfo timeInfo;
  private volatile Long offset;

  public static void main() throws Exception {

    NTPUDPClient client = new NTPUDPClient();
    // We want to timeout if a response takes longer than 10 seconds
    client.setDefaultTimeout(10_000);

    InetAddress inetAddress = InetAddress.getByName(SERVER_NAME);
    TimeInfo timeInfo = client.getTime(inetAddress);
    timeInfo.computeDetails();
    if (timeInfo.getOffset() != null) {
        this.timeInfo = timeInfo;
        this.offset = timeInfo.getOffset();
    }

    // This system NTP time
    TimeStamp systemNtpTime = TimeStamp.getCurrentTime();
    System.out.println("System time:\t" + systemNtpTime + "  " + systemNtpTime.toDateString());

    // Calculate the remote server NTP time
    long currentTime = System.currentTimeMillis();
    TimeStamp atomicNtpTime = TimeStamp.getNtpTime(currentTime + offset).getTime()

    System.out.println("Atomic time:\t" + atomicNtpTime + "  " + atomicNtpTime.toDateString());
  }

  public boolean isComputed()
  {
    return timeInfo != null && offset != null;
  }
}

You will get something like that:

System time:    dfaa2c15.2083126e  Thu, Nov 29 2018 18:12:53.127
Atomic time:    dfaa2c15.210624dd  Thu, Nov 29 2018 18:12:53.129
Teocci
  • 7,189
  • 1
  • 50
  • 48
  • it worked for me, in my case i needed Today date from server and not from system. If any one change system time my code failed. This code is great for me. – vidy Sep 25 '20 at 07:03
3

If you're using Java 5 or above, can you use System.nanoTime() to perform a more accurate measurement of time offsets ? You'd have to modify your existing NTP code, but you should have the source for it, and I wouldn't expect this to be difficult.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • Yes, System.nanoTime() accesses the high-frequency timer, and I would expect this to be used for timestamping in a decent Java NTP implementation. However, this is non-trivial so I am hoping someone else has already done and debugged it. – Matt Howells May 29 '09 at 10:15
  • Yes. I couldn't find any obvious implementations though. A chance for fame and respect, maybe ? :-) – Brian Agnew May 29 '09 at 10:18
  • 1
    System.nanoTime() can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time so cannot be used to compare local system time to absolute time from a NTP server. – CodeMonkey Nov 30 '16 at 23:30
  • It can be used to calculate the time at any moment given the NTP time from a previous moment and the elapsed time between the two moments calculated using `System.nanoTime()` – Mohamed Ragab Mar 21 '19 at 06:14