Установить время программно с помощью C#
Как лучше всего установить время на удаленной машине удаленно? Машина работает под управлением Windows XP и получает новое время через вызов веб-службы. Цель состоит в том, чтобы держать удаленные машины в синхронизации с сервером. Система заблокирована так, что наш веб-сервис является единственным доступом, поэтому я не могу использовать сервер времени на каждой удаленной машине.
5 ответов
Я бы использовал встроенные возможности интернет-времени Windows. Вы можете настроить сервер времени на вашем сервере, он получает время от 2-го уровня timeserver, и все ваши клиентские машины получают время от него.
Я уже был на пути Настройки приложения-Системы-времени.
Это вызов 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.
способ запроса сетевой машины для ее системного времени -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;
вот процедура, которую я использую в течение многих лет, чтобы прочитать DateTime
value off our our SQL Server (используя время файла), преобразуйте его в SYSTEMTIME
это установлено на ПК.
это работает для ПК и устройств 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;
}
}
вы также можете сделать это в пакетном файле, используя некоторую комбинацию
TIME
установить время, и
net time \server_name
для получения времени с сервера.