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

本文关键字:设置 时间 方式 编程 使用 | 更新日期: 2023-09-27 17:47:46

在远程机器上远程设置时间的最佳方式是什么?该机器正在运行Windows XP,并通过web服务调用接收新时间。目标是使远程计算机与服务器保持同步。系统被锁定,所以我们的网络服务是唯一的访问权限,所以我不能在每台远程机器上使用时间服务器。

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

这是用于设置系统时间的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 ); 

不过,我不太确定你将如何计算安全性,以便在客户端上执行该功能。

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

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

我以前一直走应用程序设置系统的道路。

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

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

由于它依赖于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;

下面是使用示例:

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

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

TIME

设置时间,以及

net time ''server_name

从服务器检索时间。

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

这适用于PC和Windows Mobile设备。

它可以在您碰巧调用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;
  }
}