How to query query an NTP Time Server in C#.
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace CheckTimeServer.Console
{
public static class Program
{
public static async Task Main(string[] args)
{
//
// Example usage:
//
var networkTime = await GetNetworkTime();
if (networkTime.HasValue)
{
var localZone = TimeZoneInfo.Local;
System.Console.WriteLine("Network time: {0} ({1})", networkTime.Value,
localZone.IsDaylightSavingTime(networkTime.Value)
? localZone.DaylightName
: localZone.StandardName);
}
else
{
System.Console.WriteLine("Could not retrieve network time.");
}
System.Console.ReadKey();
}
private static async Task<DateTime?> GetNetworkTime(string ntpServer = "pool.ntp.org")
{
// https://stackoverflow.com/questions/1193955/how-to-query-an-ntp-server-using-c
if (ntpServer == null)
{
throw new ArgumentNullException(nameof(ntpServer));
}
try
{
const int daysTo1900 = 1900 * 365 + 95; // 95 = offset for leap-years etc.
const long ticksPerSecond = 10000000L;
const long ticksPerDay = 24 * 60 * 60 * ticksPerSecond;
const long ticksTo1900 = daysTo1900 * ticksPerDay;
var ntpData = new byte[48];
ntpData[0] = 0x1B; // LeapIndicator = 0 (no warning), VersionNum = 3 (IPv4 only), Mode = 3 (Client Mode)
var addresses = Dns.GetHostEntry(ntpServer).AddressList;
var ipEndPoint = new IPEndPoint(addresses[0], 123);
// ReSharper disable once RedundantAssignment
var pingDuration = Stopwatch.GetTimestamp(); // temp access (JIT-Compiler need some time at first call)
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
{
await socket.ConnectAsync(ipEndPoint);
socket.ReceiveTimeout = 5000;
socket.Send(ntpData);
pingDuration = Stopwatch.GetTimestamp(); // after Send-Method to reduce WinSocket API-Call time
socket.Receive(ntpData);
pingDuration = Stopwatch.GetTimestamp() - pingDuration;
}
var pingTicks = pingDuration * ticksPerSecond / Stopwatch.Frequency;
// optional: display response-time
// Console.WriteLine("{0:N2} ms", new TimeSpan(pingTicks).TotalMilliseconds);
var intPart = (long) ntpData[40] << 24 | (long) ntpData[41] << 16 | (long) ntpData[42] << 8 | ntpData[43];
var fractPart = (long) ntpData[44] << 24 | (long) ntpData[45] << 16 | (long) ntpData[46] << 8 | ntpData[47];
var netTicks = intPart * ticksPerSecond + (fractPart * ticksPerSecond >> 32);
var networkDateTime = new DateTime(ticksTo1900 + netTicks + pingTicks / 2);
return networkDateTime.ToLocalTime(); // without ToLocalTime() = faster
}
catch
{
// fail
return null;
}
}
}
}