Установите время программно, используя C#
Вопрос
Каков наилучший способ удаленно установить время на удаленном компьютере?Компьютер работает под управлением Windows XP и получает новое время через вызов веб-службы.Цель состоит в том, чтобы поддерживать синхронизацию удаленных машин с сервером.Система заблокирована, так что наш веб-сервис является единственным доступом, поэтому я не могу использовать сервер времени на каждой удаленной машине.
Решение
Я бы использовал встроенные в Windows возможности работы в Интернете.Вы можете настроить сервер времени на вашем сервере пусть он получает время от сервера времени 2-го уровня, и пусть все ваши клиентские машины получают время от него.
Я уже проходил по пути настройки приложения-системного времени.
Другие советы
Это вызов 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 );
Однако я не совсем уверен, как бы вы обеспечили безопасность таким образом, чтобы вы могли выполнить эту функцию на клиенте.
Вы можете получить гораздо более подробную информацию о настройке системного времени по адресу ПИнвоук.
Способ запросить у сетевого компьютера его системное время заключается в следующем НетРемотеТОД.
Вот код, чтобы сделать это на 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
значение с нашего SQL-сервера (используя время работы с файлом), преобразуйте его в 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
чтобы получить время с сервера.