57

How to get current date and time from internet or server using C#? I am trying to get time as follows:

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);
}

I am passing server IP address as netServer, but it does not work properly.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
hmlasnk
  • 1,160
  • 1
  • 14
  • 33
  • 2
    "does not work properly" is a poor description of the problem. _What_ doesn't work? Exactly? – Oded Jun 22 '11 at 05:16
  • 1
    Here is another post that also may help. http://stackoverflow.com/questions/1193955/how-to-query-an-ntp-server-from-c – TheRealTy Jun 22 '11 at 05:17

6 Answers6

51

Here is code sample that you can use to retrieve time from NIST Internet Time Service

var client = new TcpClient("time.nist.gov", 13);
using (var streamReader = new StreamReader(client.GetStream()))
{
    var response = streamReader.ReadToEnd();
    var utcDateTimeString = response.Substring(7, 17);
    var localDateTime = DateTime.ParseExact(utcDateTimeString, "yy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
}
Alex Aza
  • 76,499
  • 26
  • 155
  • 134
  • 2
    You should use the format string: "yy-MM-dd HH:mm:ss" instead. HH is the 24 hour designation. hh is for 12 hour, see: http://msdn.microsoft.com/en-us/library/8kb3ddd4%28v=vs.110%29.aspx – userx Nov 18 '14 at 17:28
  • 1
    @AlexAza Good solution. Works almost all of the time One time it failed to connect with the following error (not your code's fault): `An unhandled exception of type 'System.Net.Sockets.SocketException' occurred in System.dll Additional information: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond` – nam Jun 11 '16 at 16:15
49

Here is a quick code to get the time from the header, works without the need of port 13

public static DateTime GetNistTime()
{
    var myHttpWebRequest = (HttpWebRequest)WebRequest.Create("http://www.microsoft.com");
    var response = myHttpWebRequest.GetResponse();
    string todaysDates = response.Headers["date"];
    return DateTime.ParseExact(todaysDates, 
                               "ddd, dd MMM yyyy HH:mm:ss 'GMT'", 
                               CultureInfo.InvariantCulture.DateTimeFormat, 
                               DateTimeStyles.AssumeUniversal);
}
Alex Essilfie
  • 12,339
  • 9
  • 70
  • 108
glienart
  • 601
  • 5
  • 4
  • 11
    Good solution. Works on `google.com`,`yahoo.com` and `msdn.com` as well. On msdn.com it was a bit delayed. Also, we need to `dispose response object` explicitly or enclosing it in using{...} statement – nam Jun 11 '16 at 16:11
  • 11
    Nice solution, but the HttpWebRequest cast is redundant. Also, you can simplify the code like this: `using (WebResponse response = WebRequest.Create("http://www.microsoft.com").GetResponse())return DateTime.ParseExact(response.Headers["date"], "ddd, dd MMM yyyy HH:mm:ss 'GMT'", CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.AssumeUniversal); ` – Pixelchai Sep 13 '16 at 19:27
17

Things could go wrong. All implements of the code founded above are prone to errors. Sometimes, it works and sometimes it trows a WebExpection error message.

A better implementation:

        try{
            using (var response = 
              WebRequest.Create("http://www.google.com").GetResponse())
                //string todaysDates =  response.Headers["date"];
                return DateTime.ParseExact(response.Headers["date"],
                    "ddd, dd MMM yyyy HH:mm:ss 'GMT'",
                    CultureInfo.InvariantCulture.DateTimeFormat,
                    DateTimeStyles.AssumeUniversal);
        }
        catch (WebException)
        {
            return DateTime.Now; //In case something goes wrong. 
        }

Conclusion:

Having your web app depend on a service that provides accurate date information is critical. I have used one of the code founded here in my app and it really mess things up.

cerberus
  • 331
  • 2
  • 9
12

One more version of the same idea:

public static class InternetTime
{
    public static DateTimeOffset? GetCurrentTime()
    {
        using (var client = new HttpClient())
        {
            try
            {
                var result = client.GetAsync("https://google.com", 
                      HttpCompletionOption.ResponseHeadersRead).Result;
                return result.Headers.Date;
            }
            catch
            {
                return null;
            }
        }
    }
}

Here HttpCompletionOption.ResponseHeadersRead is used to prevent loading of the rest of the response, as we need only HTTP headers.

Use InternetTime.GetCurrentTime().Value.ToLocalTime() to get current local time.

dodbrian
  • 1,394
  • 14
  • 18
  • I thought that your answer would be faster than [glienart's](https://stackoverflow.com/a/36981876/5734097), but it takes about 1.4 second more. Maybe there is an overhead on processing the date field into `DateTimeOffset`? – D.Kastier Dec 14 '18 at 11:31
4

Important: first check the avaible servers on NIST Internet Time Servers.

public static DateTime GetServerTime()
{
    var result = DateTime.Now;

    // Initialize the list of NIST time servers
    // http://tf.nist.gov/tf-cgi/servers.cgi
    string[] servers = new string[] {
        "time-c.nist.gov",
        "time-d.nist.gov",
        "nist1-macon.macon.ga.us",
        "wolfnisttime.com",
        "nist.netservicesgroup.com",
        "nisttime.carsoncity.k12.mi.us",
        "nist1-lnk.binary.net",
        "wwv.nist.gov",
        "time.nist.gov",
        "utcnist.colorado.edu",
        "utcnist2.colorado.edu",
        "nist-time-server.eoni.com",
        "nist-time-server.eoni.com"
    };
    
    Random rnd = new Random();
    
    foreach (string server in servers.OrderBy(x => rnd.NextDouble()).Take(9))
    {                
        try
        {
            // Connect to the server (at port 13) and get the response. Timeout max 1second
            string serverResponse = string.Empty;
            var tcpClient = new TcpClient(); 
            
            if (tcpClient.ConnectAsync(server, 13).Wait(1000))
            {
                using (var reader = new StreamReader(tcpClient.GetStream()))
                {
                    serverResponse = reader.ReadToEnd();
                }
            }         
            
            // If a response was received
            if (!string.IsNullOrEmpty(serverResponse))
            {
                // Split the response string ("55596 11-02-14 13:54:11 00 0 0 478.1 UTC(NIST) *")
                string[] tokens = serverResponse.Split(' ');

                // Check the number of tokens
                if (tokens.Length >= 6)
                {
                    // Check the health status
                    string health = tokens[5];
                    if (health == "0")
                    {
                        // Get date and time parts from the server response
                        string[] dateParts = tokens[1].Split('-');
                        string[] timeParts = tokens[2].Split(':');

                        // Create a DateTime instance
                        DateTime utcDateTime = new DateTime(
                            Convert.ToInt32(dateParts[0]) + 2000,
                            Convert.ToInt32(dateParts[1]), Convert.ToInt32(dateParts[2]),
                            Convert.ToInt32(timeParts[0]), Convert.ToInt32(timeParts[1]),
                            Convert.ToInt32(timeParts[2]));

                        // Convert received (UTC) DateTime value to the local timezone
                        result = utcDateTime.ToLocalTime();

                        return result;
                        // Response successfully received; exit the loop
                    }
                }
            }
        }
        catch
        {
            // Ignore exception and try the next server
        }
    }
    return result;
}
Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
Xtian11
  • 2,130
  • 1
  • 21
  • 13
  • 1
    No need for that. You can directly check the one URL only.as they stats. "The global address time.nist.gov is resolved to all of the server addresses below in a round-robin sequence to equalize the load across all of the servers." – RATHI Aug 31 '21 at 10:41
0
    public static Nullable<DateTime> GetDateTime()
    {
        Nullable<DateTime> dateTime = null;
        System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create("http://www.microsoft.com");
        request.Method = "GET";
        request.Accept = "text/html, application/xhtml+xml, */*";
        request.UserAgent = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)";
        request.ContentType = "application/x-www-form-urlencoded";
        request.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
        try
        {
            System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                string todaysDates = response.Headers["date"];

                dateTime = DateTime.ParseExact(todaysDates, "ddd, dd MMM yyyy HH:mm:ss 'GMT'",
                    System.Globalization.CultureInfo.InvariantCulture.DateTimeFormat, System.Globalization.DateTimeStyles.AssumeUniversal);
            }
        }
        catch
        {
            dateTime = null;
        }
        return dateTime;
    }