7

In C#, how do I query a remote server for its current time?

Similar functionality to

net time \\servername

but returning a datestamp that includes seconds.

Thanks

bluish
  • 26,356
  • 27
  • 122
  • 180
David Laing
  • 7,605
  • 10
  • 33
  • 44

8 Answers8

5

You can use the NetRemoteTOD function.

An example from http://bytes.com/groups/net-c/246234-netremotetod-usage:

// The pointer.
IntPtr pintBuffer = IntPtr.Zero;

// Get the time of day.
int pintError = NetRemoteTOD(@"\\sony_laptop", ref pintBuffer);

// Get the structure.
TIME_OF_DAY_INFO pobjInfo = (TIME_OF_DAY_INFO)
Marshal.PtrToStructure(pintBuffer, typeof(TIME_OF_DAY_INFO));

// Free the buffer.
NetApiBufferFree(pintBuffer);
Patrick McDonald
  • 64,141
  • 14
  • 108
  • 120
  • Working like a charm. And it doesn't need remote server to have **Windows Time Service running** (@Reed Copsey answer) or **port 13 open** (@Zanoni answer) or **access to the filesystem** (@bluish answer). This approach works with **Windows 2000 or higher** - perfect.. – bairog May 26 '14 at 11:10
4

You can try getting the daytime on port 13:

System.Net.Sockets.TcpClient t = new System.Net.Sockets.TcpClient ("yourmachineHOST", 13);
System.IO.StreamReader rd = new System.IO.StreamReader (t.GetStream ()); 
Console.WriteLine (rd.ReadToEnd ());
rd.Close();
t.Close();
Zanoni
  • 30,028
  • 13
  • 53
  • 73
  • A nice simple solution, if the remote server has port 13 open... You can test quite simply whether the port is open using telnet yourmachineHOST 13 and seeing if you get a response – David Laing Jun 18 '09 at 09:53
4

Below is a more complete implementation.

Usage: DateTime? now = RemoteTOD.GetNow(@"\\ServerName");

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

//https://learn.microsoft.com/en-us/windows/desktop/api/lmremutl/nf-lmremutl-netremotetod
public static class RemoteTOD {

    // Important: CharSet must be Unicode otherwise error 2184 is returned
    [DllImport("netapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
    private static extern int NetRemoteTOD(String UncServerName, ref IntPtr BufferPtr);

    [DllImport("netapi32.dll")]
    private static extern void NetApiBufferFree(IntPtr bufptr);

    public static DateTime? GetNow(String serverName, bool throwException = false) {
        IntPtr ptrBuffer = IntPtr.Zero;
        int result = NetRemoteTOD(serverName, ref ptrBuffer);
        if (result != 0) {
            if (throwException)
                throw new Win32Exception(Marshal.GetLastWin32Error());
            return null;
        }

        TIME_OF_DAY_INFO tod = (TIME_OF_DAY_INFO) Marshal.PtrToStructure(ptrBuffer, typeof(TIME_OF_DAY_INFO));
        NetApiBufferFree(ptrBuffer); // must be freed using NetApiBufferFree according to the documentation

        //DateTime d0 = new DateTime(1970,1,1);
        //d0 = d0.AddSeconds(tod.elapsedt);
        DateTime nowUtc = new DateTime(tod.year, tod.month, tod.day, tod.hour, tod.minute, tod.second, 10 * tod.hunds);
        DateTime now = nowUtc.ToLocalTime();
        return now;
    }
}

[StructLayout(LayoutKind.Sequential)]
public struct TIME_OF_DAY_INFO {

    ///<summary>The number of seconds since 00:00:00, January 1, 1970, GMT.</summary>
    public int elapsedt;

    ///<summary>The number of milliseconds from an arbitrary starting point (system reset). Typically, this member is read twice,
    ///once when the process begins and again at the end. To determine the elapsed time between the process's start and finish,
    ///you can subtract the first value from the second.</summary>
    public int msecs;

    ///<summary>The current hour. Valid values are 0 through 23.</summary>
    public int hour;

    ///<summary>The current minute. Valid values are 0 through 59.</summary>
    public int minute;

    ///<summary>The current second. Valid values are 0 through 59.</summary>
    public int second;

    ///<summary>The current hundredth second (0.01 second). Valid values are 0 through 99.</summary>
    public int hunds;

    ///<summary>The time zone of the server. This value is calculated, in minutes, from Greenwich Mean Time (GMT). For time zones
    ///west of Greenwich, the value is positive; for time zones east of Greenwich, the value is negative. A value of –1 indicates
    ///that the time zone is undefined.</summary>
    public int timezone;

    ///<summary>The time interval for each tick of the clock. Each integral integer represents one ten-thousandth second (0.0001 second).</summary>
    public int tinterval;

    ///<summary>The day of the month. Valid values are 1 through 31.</summary>
    public int day;

    ///<summary>The month of the year. Valid values are 1 through 12.</summary>
    public int month;

    ///<summary>The year.</summary>
    public int year;

    ///<summary>The day of the week. Valid values are 0 through 6, where 0 is Sunday, 1 is Monday, and so on.</summary>
    public int weekday;
}
Loathing
  • 5,109
  • 3
  • 24
  • 35
1

Windows Time Service implements NTP. Here is a C# implementation of an NTP client. A Windows GUI using it can be found at Simple Network Time Protocol Client. It's by Valer Bocan.

bluish
  • 26,356
  • 27
  • 122
  • 180
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • If you can't query the actual remote server for its time; you can at least query the same domain controller / NTP server and get a pretty similar time. Using the referenced NTP client is as simple as var client = new InternetTime.SNTPClient("pkh-srv-dc03"); client.Connect(false); Console.WriteLine(client.DestinationTimestamp); – David Laing Jun 18 '09 at 10:16
1

Using the C# NTP client in Reed Copsey (& David Laing) answer, you can get a time "now" stamp (in ms) from a domain controller / NTP server using:

InternetTime.SNTPClient sntp = new InternetTime.SNTPClient("ntp1.ja.net");
sntp.Connect(false); // true to update local client clock
DateTime dt = sntp.DestinationTimestamp.AddMilliseconds(sntp.LocalClockOffset);
string timeStampNow = dt.ToString("dd/MM/yyyy HH:mm:ss.fff");
Ken
  • 581
  • 1
  • 6
  • 5
  • 1
    You could post this code in [@Reed Copsey's answer](http://stackoverflow.com/a/1008145/505893), so it will be enhanced and will be easy for future readers to understand it. ;) – bluish Jul 25 '12 at 13:22
0

If you have access to the filesystem of the remote system with a UNC path (like \\remotehost\foo\bar; for instance using Windows Explorer), you can retrieve remote datetime, even if it's not a Windows system, with following workaround. Create a dummy file, read it's write time and throw it away. It works also for local host.

public DateTime filesystemDateTime(string path)
{
    //create temp file
    string tempFilePath = Path.Combine(path, "lampo.tmp");
    using (File.Create(tempFilePath)) { }
    //read creation time and use it as current source filesystem datetime
    DateTime dt = new FileInfo(tempFilePath).LastWriteTime;
    //delete temp file
    File.Delete(tempFilePath);

    return dt;
}
bluish
  • 26,356
  • 27
  • 122
  • 180
0
class RemoteSystemTime 
    {
        static void Main(string[] args)
        {
            try
            {
                string machineName = "vista-pc";

                System.Diagnostics.Process proc = new System.Diagnostics.Process();
                proc.StartInfo.UseShellExecute = false;
                proc.StartInfo.RedirectStandardOutput = true;
                proc.StartInfo.FileName = "net";
                proc.StartInfo.Arguments = @"time \\" + machineName;
                proc.Start();
                proc.WaitForExit();

                List<string> results = new List<string>();
                while (!proc.StandardOutput.EndOfStream)
                {
                    string currentline = proc.StandardOutput.ReadLine();
                    if (!string.IsNullOrEmpty(currentline))
                    {
                        results.Add(currentline);
                    }
                }

                string currentTime = string.Empty;
                if (results.Count > 0 && results[0].ToLower().StartsWith(@"current time at \\" +                                               machineName.ToLower() + " is "))
                {
                    currentTime = results[0].Substring((@"current time at \\" + machineName.ToLower() + " is                             ").Length);

                    Console.WriteLine(DateTime.Parse(currentTime));
                    Console.ReadLine();
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.ReadLine();
            }
        }
Brad Larson
  • 170,088
  • 45
  • 397
  • 571
Kevin M
  • 5,436
  • 4
  • 44
  • 46
  • 1
    Note that "current time at" is not correct if language is not english on your local machine. – bairog May 26 '14 at 11:27
  • 1
    BTW: **NET TIME command** uses **NetRemoteTOD function** (from @Patrick McDonald answer): http://blogs.msdn.com/b/w32time/archive/2009/08/07/net-time-and-w32time.aspx – bairog May 26 '14 at 11:41
0

Simple Network Time Protocol Client

bluish
  • 26,356
  • 27
  • 122
  • 180
Nime Cloud
  • 6,162
  • 14
  • 43
  • 75
  • I'm sorry but this answer is useless, it points to the same project as [@Reed Copsey's answer](http://stackoverflow.com/a/1008145/505893). I'll paste your link on that answer and I think this answer should be closed. Thanks! – bluish Jul 25 '12 at 13:24