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
Using Cookiecontainer With Webclient Class
Await' Works, But Calling Task.Result Hangs/Deadlocks
Convert Generic List/Enumerable to Datatable
There Is Already an Open Datareader Associated With This Command Which Must Be Closed First
Watermark/Hint/Placeholder Text in Textbox
How to Get a User'S Client Ip Address in Asp.Net
Encrypting & Decrypting a String in C#
How to Execute a Stored Procedure Within C# Program
Output Log Using Ftpwebrequest
Why Would You Use Expression≪Func≪T≫≫ Rather Than Func≪T≫
How to Convert Json Object to Custom C# Object
Using a Class Defined in a C++ Dll in C# Code
How to Detect Windows 64-Bit Platform With .Net
Getting "Type or Namespace Name Could Not Be Found" But Everything Seems Ok