How to Query an Ntp Server Using C#

How to Query an NTP Server using C#?

Since the old accepted answer got deleted (It was a link to a Google code search results that no longer exist), I figured I could answer this question for future reference :

public static DateTime GetNetworkTime()
{
//default Windows time server
const string ntpServer = "time.windows.com";

// NTP message size - 16 bytes of the digest (RFC 2030)
var ntpData = new byte[48];

//Setting the Leap Indicator, Version Number and Mode values
ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)

var addresses = Dns.GetHostEntry(ntpServer).AddressList;

//The UDP port number assigned to NTP is 123
var ipEndPoint = new IPEndPoint(addresses[0], 123);
//NTP uses UDP

using(var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
{
socket.Connect(ipEndPoint);

//Stops code hang if NTP is blocked
socket.ReceiveTimeout = 3000;

socket.Send(ntpData);
socket.Receive(ntpData);
socket.Close();
}

//Offset to get to the "Transmit Timestamp" field (time at which the reply
//departed the server for the client, in 64-bit timestamp format."
const byte serverReplyTime = 40;

//Get the seconds part
ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);

//Get the seconds fraction
ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);

//Convert From big-endian to little-endian
intPart = SwapEndianness(intPart);
fractPart = SwapEndianness(fractPart);

var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);

//**UTC** time
var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);

return networkDateTime.ToLocalTime();
}

// stackoverflow.com/a/3294698/162671
static uint SwapEndianness(ulong x)
{
return (uint) (((x & 0x000000ff) << 24) +
((x & 0x0000ff00) << 8) +
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24));
}

Note: You will have to add the following namespaces

using System.Net;
using System.Net.Sockets;

Query an NTP Server using C# and windows command line

1) The most likely reason your program is stopping is because of no network response this can be caused by the network blocking for Udp, port 123 etc.

2) You can use the ntpq program to query from command line (NTP)

How to query date at time.windows.com NTP server by using C#.NET code?

Here is code that runs in LINQPad, slightly modified from the original version at https://mschwarztoolkit.svn.codeplex.com/svn/NTP/NtpClient.cs

void Main()
{
var x = NtpClient.GetNetworkTime();
x.Dump();
}

/// <summary>
/// Static class to receive the time from a NTP server.
/// </summary>
public class NtpClient
{
/// <summary>
/// Gets the current DateTime from time-a.nist.gov.
/// </summary>
/// <returns>A DateTime containing the current time.</returns>
public static DateTime GetNetworkTime()
{
return GetNetworkTime("time.windows.com"); // time-a.nist.gov
}

/// <summary>
/// Gets the current DateTime from <paramref name="ntpServer"/>.
/// </summary>
/// <param name="ntpServer">The hostname of the NTP server.</param>
/// <returns>A DateTime containing the current time.</returns>
public static DateTime GetNetworkTime(string ntpServer)
{
IPAddress[] address = Dns.GetHostEntry(ntpServer).AddressList;

if(address == null || address.Length == 0)
throw new ArgumentException("Could not resolve ip address from '" + ntpServer + "'.", "ntpServer");

IPEndPoint ep = new IPEndPoint(address[0], 123);

return GetNetworkTime(ep);
}

/// <summary>
/// Gets the current DateTime form <paramref name="ep"/> IPEndPoint.
/// </summary>
/// <param name="ep">The IPEndPoint to connect to.</param>
/// <returns>A DateTime containing the current time.</returns>
public static DateTime GetNetworkTime(IPEndPoint ep)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

s.Connect(ep);

byte[] ntpData = new byte[48]; // RFC 2030
ntpData[0] = 0x1B;
for (int i = 1; i < 48; i++)
ntpData[i] = 0;

s.Send(ntpData);
s.Receive(ntpData);

byte offsetTransmitTime = 40;
ulong intpart = 0;
ulong fractpart = 0;

for (int i = 0; i <= 3; i++)
intpart = 256 * intpart + ntpData[offsetTransmitTime + i];

for (int i = 4; i <= 7; i++)
fractpart = 256 * fractpart + ntpData[offsetTransmitTime + i];

ulong milliseconds = (intpart * 1000 + (fractpart * 1000) / 0x100000000L);
s.Close();

TimeSpan timeSpan = TimeSpan.FromTicks((long)milliseconds * TimeSpan.TicksPerMillisecond);

DateTime dateTime = new DateTime(1900, 1, 1);
dateTime += timeSpan;

TimeSpan offsetAmount = TimeZone.CurrentTimeZone.GetUtcOffset(dateTime);
DateTime networkDateTime = (dateTime + offsetAmount);

return networkDateTime;
}
}

How can I query the local network for the current datetime via SNTP?

Just remembered this question, figured I'd post the solution I found:

var cmd = new System.Diagnostics.Process
{
StartInfo =
{
FileName = "cmd.exe",
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
RedirectStandardOutput = true,
Arguments = "/C net time /DOMAIN:" + Environment.UserDomainName,
UseShellExecute = false
}
};

cmd.Start();

string output = cmd.StandardOutput.ReadToEnd();
if (output.EndsWith("The command completed successfully.\r\n\r\n"))
{
int is_index = output.IndexOf("is ");
int serv_start = output.IndexOf(@"\\") + 2;
int serv_end = is_index - 1;
string time_server = output.Substring(serv_start, serv_end - serv_start).Split(new char[] { '.' })[0];
if (time_server == Environment.MachineName)
return DateTime.MaxValue; // local machine is acting as time server

int time_start = is_index + 3;
int time_end = output.IndexOf("\r");
string local = output.Substring(time_start, time_end - time_start);
return DateTime.ParseExact(local, "M/d/yyyy h:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture);
}

return DateTime.MaxValue;

This gets the current time from the domain's time server; it will return DateTime.MaxValue if the command fails or if the local machine is the time server (if you trust the system time, why are you checking the local network?). Exception handling has been omitted for brevity.

I did not investigate what culture net time uses to format its output, so it may be necessary to use something other than InvariantCulture for that.

How to query local system time and time from network server using NodaTime

NodaTime is a dependency of NodaTime.NetworkClock. You need them both if you want the network clock feature.

This is a very common practice when one library provides the core features and another library extends it with additional functionality.

Install from Nuget:

Install-Package NodaTime.NetworkClock

And you will also get the NodaTime package automatically installed as well.

Then use them simply like this:

Instant currentSystemTime = SystemClock.Instance.Now;
Instant currentNetworkTime = NetworkClock.Instance.Now;


Related Topics



Leave a reply



Submit