4

I try to use the following code to obtain time from public time server.

package aaa;

import java.util.Arrays;
import java.util.List;

import org.apache.commons.net.TimeTCPClient;

public final class Main
{
    public static java.util.Date getNTPDate() {
        List<String> hosts = Arrays.asList("0.pool.ntp.org");

        for (String host : hosts) {
            TimeTCPClient client = new TimeTCPClient();
            // We want to timeout if a response takes longer than 5 seconds
            client.setDefaultTimeout(5000);
            try {
                client.connect(host);
                java.util.Date ntpDate = client.getDate();
                client.disconnect();
                // Just to be extra caution.
                if (ntpDate != null) {
                    return ntpDate;
                }
            }
            catch (java.net.SocketException exp) {
                exp.printStackTrace();
            }
            catch (java.io.IOException exp) {
                exp.printStackTrace();
            }
        }
        return null;
    }

    public static final void main(String[] args)
    {
        System.out.println(getNTPDate());
    }

}

However, all the time, I am getting java.net.ConnectException: Connection timed out: connect

I had tried to google for several different time server. However, non of them work. I was wondering, is the problem lies on my code, or the server I choose?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875

3 Answers3

9

NTP is a different protocol than the time protocol. NTP servers only talk over port UDP/123. Time servers use TCP/37 (which TimeTCPClient appears to implement correctly).

If you want to get a remote time, use an appropriate server (ntp.xs4all.nl appears to be listening on the time port).

Friek
  • 1,533
  • 11
  • 13
5

You can use the correct approach:

import java.io.IOException;
import java.net.InetAddress;
import java.util.Date;

import org.apache.commons.net.ntp.NTPUDPClient;
import org.apache.commons.net.ntp.TimeInfo;

public final class PublicServerTime {

    public static Date getNTPDate() {

        String[] hosts = new String[]{
            "ntp02.oal.ul.pt", "ntp04.oal.ul.pt",
            "ntp.xs4all.nl"};

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

        for (String host : hosts) {

            try {
                InetAddress hostAddr = InetAddress.getByName(host);
                System.out.println("> " + hostAddr.getHostName() + "/" + hostAddr.getHostAddress());
                TimeInfo info = client.getTime(hostAddr);
                Date date = new Date(info.getReturnTime());
                return date;

            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }

        client.close();

        return null;

    }


    public static final void main(String[] args) {

        System.out.println(getNTPDate());

    }
marcolopes
  • 9,232
  • 14
  • 54
  • 65
  • 5
    This is not completely right. `Date date = new Date(info.getReturnTime());` should be `Date date = new Date(info.getMessage().getTransmitTimeStamp().getTime());` in order to get the returned time and not the system time. [Source](http://stackoverflow.com/a/14356839/2302499) (tested and confirmed). – berbt May 07 '14 at 21:30
  • 1
    Thanks for the remark! I never experienced problems, because i assume its returning "the REMOTE system time at which time message packet was received by local machine!". In this context, the "time at which time message packet was received by local machine" is more accurate than the "the transmit timestamp"... or I'm i missing something?! – marcolopes May 08 '14 at 00:37
  • I guess there's little chance that the server will take more than a fraction of a second to process your request (the highest difference I got between both values was 1sec). But, in the case it does, I'd say one should prefer the later (returned time value), otherwise the rest of the code may be running 'in the past'. – berbt May 08 '14 at 01:35
  • NTPUDPClient is no longer available in the latest version of Apache Commons-Net. – René Jörg Spies May 24 '20 at 14:08
0

Source:

public class NTPService {

    private final static Logger logger = Logger.getLogger(NTPService.class);
    private final static int TIMEOUT = 5000;
    private final static List<String> hostList = 
                                   Arrays.asList("time.windows.com", "nl.pool.ntp.org");

    private final NTPUDPClient client = new NTPUDPClient();

    public NTPService() {
        client.setDefaultTimeout(TIMEOUT);
    }

    public LocalDateTime getNTPDateTime() {
        for (final String host : hostList) {
            final LocalDateTime localDateTime = getNTPDateTime(host);
            if (null != localDateTime) {
                return localDateTime;
            }
        }
        return null;
    }

    private LocalDateTime getNTPDateTime(final String host) {
        try {
            client.open();
            return convertToLocalDateTime(
                    TimeStamp.getNtpTime(client.getTime(InetAddress.getByName(host))
                                  .getReturnTime()).getTime());
        } catch (final Exception exp) {
            logger.warn(String.format("%s: failed to update NTP", host), exp);
            return null;
        } finally {
            if (client.isOpen()) {
                client.close();
            }
        }
    }

    private LocalDateTime convertToLocalDateTime(final long value) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(value),
               ZoneId.systemDefault());
    }
}

Usage:

System.out.println(DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss").
                   format(new NTPService().getNTPDateTime()));
Oleks
  • 1,011
  • 1
  • 14
  • 25