56

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
  • 159,224
  • 26
  • 237
  • 393
hmlasnk
  • 1,100
  • 1
  • 13
  • 31
  • 1
    "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

7 Answers7

55

For environments where port 13 is blocked, time from NIST can be web scraped as below,

public static DateTime GetNistTime()
{
    DateTime dateTime = DateTime.MinValue;

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://nist.time.gov/actualtime.cgi?lzbc=siqm9b");
    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 RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); //No caching
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    if (response.StatusCode == HttpStatusCode.OK)
    {
        StreamReader stream = new StreamReader(response.GetResponseStream());
        string html = stream.ReadToEnd();//<timestamp time=\"1395772696469995\" delay=\"1395772696469995\"/>
        string time = Regex.Match(html, @"(?<=\btime="")[^""]*").Value;
        double milliseconds = Convert.ToInt64(time) / 1000.0;
        dateTime = new DateTime(1970, 1, 1).AddMilliseconds(milliseconds).ToLocalTime();
    }

    return dateTime;
}
Nemo
  • 3,023
  • 1
  • 26
  • 22
  • When I try this I get HTTP 407 (proxy authorization). Any idea how to use current user's credential without having code in my password? – Louis Rhys Nov 29 '12 at 11:07
  • 5
    Instead of using regex you could just retrive the DATE header. if (DateTime.TryParse(response.GetResponseHeader("DATE"), out dateTime)) return dateTime; – Robert Feb 18 '13 at 18:57
  • @LouisRhys Try setting up the defaultProxy in your App.config file as shown here, http://stackoverflow.com/questions/2131933/http-407-proxy-authentication-error-when-calling-a-web-service – Nemo Jun 12 '13 at 14:44
  • 1
    @publicENEMY NIST changed their logic to dynamically update time using javascript, the code has been updated accordingly. – Nemo Mar 25 '14 at 15:35
  • 4
    I just get the internet time from any popular website (say google) by checking the http response header "Date" parameter. That way you don't have to rely on any one service but can easily change it to any other. – petke Jan 05 '16 at 03:30
  • @someoneelse - That's a good idea. Please consider posting it as a separate answer here. – Nemo Jan 05 '16 at 14:19
  • 1
    @SyaifulNizamYahya I got it to work https://github.com/jtara1/misc_scripts/blob/master/misc_scripts/UpdateOSTime.cs – James T. Dec 24 '17 at 01:42
  • this method is working no more. It was working well in my app but stopped working some days ago. I am receiving this response: – mannan Sep 08 '19 at 13:09
  • http://nist.time.gov/actualtime.cgi?lzbc=siqm9b is not working , any help on the new url please – lazarus Nov 06 '19 at 11:16
  • Parsing html won't work anymore, may have to host WebBrowser component and intercept Javascript calls. Or look for an alternate official government website. Will look into it and update the code, hopefully soon. – Nemo Nov 06 '19 at 14:54
  • Does this return UTC time or local time? – NOT_A_ROBOT Dec 03 '20 at 05:06
47

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
  • 73,821
  • 25
  • 151
  • 132
  • @user809689 - don't forget to mark the answer if this helped. – Alex Aza Jun 22 '11 at 15:07
  • I would recommend using `time.nist.gov` instead of hardcoding the IP Address. Otherwise this is an excellent answer. – Derek W Aug 29 '14 at 03:01
  • 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
46

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,031
  • 9
  • 67
  • 106
glienart
  • 571
  • 4
  • 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); ` – Pozogo Sep 13 '16 at 19:27
  • 2
    Amazing answer. Good for people for whom ports are blocked. – Aditya Bokade Jan 09 '18 at 17:40
  • Brilliant! Will definitely use this. – ccalboni Feb 23 '18 at 08:29
14

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
  • 303
  • 2
  • 9
9

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,114
  • 16
  • 13
  • 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
3

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
  • 1
  • 4
  • 26
  • 35
Xtian11
  • 1,866
  • 1
  • 18
  • 12
  • 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;
    }