使用 C# 以编程方式设置时间

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/204936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:57:49  来源:igfitidea点击:

Set time programmatically using C#

c#time

提问by Jim Blake

What is the best way to set the time on a remote machine remotely? The machine is running Windows XP and is receiving the new time through a web service call. The goal is to keep the remote machines in synch with the server. The system is locked down so that our web service is the only access, so I cannot use a time server on each remote machine.

在远程机器上远程设置时间的最佳方法是什么?机器运行 Windows XP 并通过 Web 服务调用接收新时间。目标是保持远程机器与服务器同步。系统已锁定,因此我们的 Web 服务是唯一的访问权限,因此我无法在每台远程机器上使用时间服务器。

采纳答案by Joel B Fant

I would use Windows built-in internet time abilities. You can set up a time serveron your server, have it get time from a 2nd-tier timeserver, and have all your client machines get time from it.

我会使用 Windows 内置的互联网时间功能。您可以在您的服务器上设置一个时间服务器,让它从第二层时间服务器获取时间,并让所有客户端机器从中获取时间。

I've been down the application-setting-system-time road before.

我以前一直在应用程序设置系统时间的道路上。

回答by Robert S.

This is the Win32 API call for setting system time:

这是用于设置系统时间的 Win32 API 调用:

[StructLayout(LayoutKind.Sequential)] 
public struct SYSTEMTIME { 
 public short wYear; 
 public short wMonth; 
 public short wDayOfWeek; 
 public short wDay; 
 public short wHour; 
 public short wMinute; 
 public short wSecond; 
 public short wMilliseconds; 
 } 
 [DllImport("kernel32.dll", SetLastError=true)] 
public static extern bool SetSystemTime(ref SYSTEMTIME theDateTime ); 

I'm not exactly sure how you would get the security worked out such that you could execute that function on the client, though.

不过,我不确定如何解决安全性问题,以便您可以在客户端上执行该功能。

You can get a lot more detail on setting system time at PInvoke.

您可以在PInvoke获得更多关于设置系统时间的详细信息。

回答by JosephStyons

The way to query a network machine for it's system time is NetRemoteTOD.

查询网络机器的系统时间的方法是NetRemoteTOD

Here's code to do it in Delphi (a usage example is posted below).

这是在 Delphi 中执行此操作的代码(下面发布了一个使用示例)。

Since it relies on Windows API calls, it shouldn't be too different in C#.

由于它依赖于 Windows API 调用,因此在 C# 中应该不会有太大的不同。

unit TimeHandler;

interface

type
  TTimeHandler = class
  private
    FServerName : widestring;
  public
    constructor Create(servername : widestring);
    function RemoteSystemTime : TDateTime;
    procedure SetLocalSystemTime(settotime : TDateTime);
  end;

implementation

uses
  Windows, SysUtils, Messages;

function NetRemoteTOD(ServerName :PWideChar; var buffer :pointer) : integer; stdcall; external 'netapi32.dll';
function NetApiBufferFree(buffer : Pointer) : integer; stdcall; external 'netapi32.dll';

type
  //See MSDN documentation on the TIME_OF_DAY_INFO structure.
  PTime_Of_Day_Info = ^TTime_Of_Day_Info;
  TTime_Of_Day_Info = record
    ElapsedDate : integer;
    Milliseconds : integer;
    Hours : integer;
    Minutes : integer;
    Seconds : integer;
    HundredthsOfSeconds : integer;
    TimeZone : LongInt;
    TimeInterval : integer;
    Day : integer;
    Month : integer;
    Year : integer;
    DayOfWeek : integer;
  end;

constructor TTimeHandler.Create(servername: widestring);
begin
  inherited Create;
  FServerName := servername;
end;

function TTimeHandler.RemoteSystemTime: TDateTime;
var
  Buffer : pointer;
  Rek : PTime_Of_Day_Info;
  DateOnly, TimeOnly : TDateTime;
  timezone : integer;
begin
  //if the call is successful...
  if 0 = NetRemoteTOD(PWideChar(FServerName),Buffer) then begin
    //store the time of day info in our special buffer structure
    Rek := PTime_Of_Day_Info(Buffer);

    //windows time is in GMT, so we adjust for our current time zone
    if Rek.TimeZone <> -1 then
      timezone := Rek.TimeZone div 60
    else
      timezone := 0;

    //decode the date from integers into TDateTimes
    //assume zero milliseconds
    try
      DateOnly := EncodeDate(Rek.Year,Rek.Month,Rek.Day);
      TimeOnly := EncodeTime(Rek.Hours,Rek.Minutes,Rek.Seconds,0);
    except on e : exception do
      raise Exception.Create(
                             'Date retrieved from server, but it was invalid!' +
                             #13#10 +
                             e.Message
                            );
    end;

    //translate the time into a TDateTime
    //apply any time zone adjustment and return the result
    Result := DateOnly + TimeOnly - (timezone / 24);
  end  //if call was successful
  else begin
    raise Exception.Create('Time retrieval failed from "'+FServerName+'"');
  end;

  //free the data structure we created
  NetApiBufferFree(Buffer);
end;

procedure TTimeHandler.SetLocalSystemTime(settotime: TDateTime);
var
  SystemTime : TSystemTime;
begin
  DateTimeToSystemTime(settotime,SystemTime);
  SetLocalTime(SystemTime);
  //tell windows that the time changed
  PostMessage(HWND_BROADCAST,WM_TIMECHANGE,0,0);
end;

And here is the usage example:

这是使用示例:

procedure TfrmMain.SynchLocalTimeWithServer;
var
  tod : TTimeHandler;
begin
  tod := TTimeHandler.Create(cboServerName.Text);
  try
    tod.SetLocalSystemTime(tod.RemoteSystemTime);
  finally
    FreeAndNil(tod);
  end;  //try-finally
end;

回答by JosephStyons

You could also probably do this in a batch file using some combination of

您也可以使用某些组合在批处理文件中执行此操作

TIME

to set the time, and

设置时间,以及

net time \server_name

to retrieve the time from a server.

从服务器检索时间。

回答by jp2code

Here's the routine I have been using for years to read the DateTimevalue off our our SQL Server (using file time), convert it to a SYSTEMTIMEthat is set on the PC.

这是我多年来一直使用的例程,DateTime从我们的 SQL Server读取值(使用文件时间),将其转换SYSTEMTIME为在 PC 上设置的值。

This works for PCs and Windows Mobile devices.

这适用于 PC 和 Windows Mobile 设备。

It can be called anytime you happen to be calling your SQL Server.

它可以在您调用 SQL Server 的任何时候调用。

public class TimeTool {

  private static readonly DateTime NODATE = new DateTime(1900, 1, 1);

#if PocketPC
  [DllImport("coredll.dll")]
#else
  [DllImport("kernel32.dll")]
#endif
  static extern bool SetLocalTime([In] ref SYSTEMTIME lpLocalTime);

  public struct SYSTEMTIME {
    public short Year, Month, DayOfWeek, Day, Hour, Minute, Second, Millisecond;
    /// <summary>
    /// Convert form System.DateTime
    /// </summary>
    /// <param name="time">Creates System Time from this variable</param>
    public void FromDateTime(DateTime time) {
      Year = (short)time.Year;
      Month = (short)time.Month;
      DayOfWeek = (short)time.DayOfWeek;
      Day = (short)time.Day;
      Hour = (short)time.Hour;
      Minute = (short)time.Minute;
      Second = (short)time.Second;
      Millisecond = (short)time.Millisecond;
    }

    public DateTime ToDateTime() {
      return new DateTime(Year, Month, Day, Hour, Minute, Second, Millisecond);
    }

    public static DateTime ToDateTime(SYSTEMTIME time) {
      return time.ToDateTime();
    }
  }

  // read SQL Time and set time on device
  public static int SyncWithSqlTime(System.Data.SqlClient.SqlConnection con) {
    SYSTEMTIME systemTime = new SYSTEMTIME();
    DateTime sqlTime = NODATE;
    string sql = "SELECT GETDATE() AS [CurrentDateTime]";
    using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(sql, con)) {
      try {
        cmd.Connection.Open();
        System.Data.SqlClient.SqlDataReader r = cmd.ExecuteReader();
        while (r.Read()) {
          if (!r.IsDBNull(0)) {
            sqlTime = (DateTime)r[0];
          }
        }
      } catch (Exception) {
        return -1;
      }
    }
    if (sqlTime != NODATE) {
      systemTime.FromDateTime(sqlTime); // Convert to SYSTEMTIME
      if (SetLocalTime(ref systemTime)) { //Call Win32 API to set time
        return 1;
      }
    }
    return 0;
  }

}