Introduction
This is a simple utility written in C# .NET Version 2.0. It synchronizes Windows system time with Yahoo! server time through a web service offered by Yahoo!.
Using the code
The utility makes an HTTP request to the Yahoo! URL, which returns Yahoo! server time as a timestamp in XML format. Then the XML is parsed to get the timestamp and is converted into regional date-time. Windows system time is modified to this using a P-Invoke function call.
using System;
using System.Net;
using System.Xml;
using System.IO;
using System.Threading;
using System.Diagnostics;
using Microsoft.Win32;
using System.Configuration;
using System.Runtime.InteropServices;
namespace TryWinTimeSync
{
class Program
{
[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( [In] ref SYSTEMTIME st );
[STAThread]
static void Main(string[] args)
{
BooleanSwitch Tracer = new BooleanSwitch("TraceSwitch",
"Trace for entire application");
EventLog Log = null;
try
{
Log = new EventLog();
if(!System.Diagnostics.EventLog.SourceExists("WinTimeSync"))
System.Diagnostics.EventLog.CreateEventSource(
"WinTimeSync", "Zion");
Log.Source = "WinTimeSync";
Log.Log = "Zion";
if ( Tracer.Enabled )
Trace.Listeners.Add(new EventLogTraceListener(Log));
Trace.WriteLineIf(Tracer.Enabled, "Starting WinTimeSync...");
Boolean ServiceAlive = true;
Double CurrentTimestamp = 0;
Trace.WriteLineIf(Tracer.Enabled,
"Opening configuration file for initializing" +
" global settings...");
Int32 SyncInterval = Convert.ToInt32(
ConfigurationSettings.AppSettings[
"SyncInterval"].ToString());
String RequestURL = ConfigurationSettings.AppSettings[
"TimeServerURL"].ToString();
Trace.WriteLineIf(Tracer.Enabled,
"Global settings initialized [SyncInterval: " +
SyncInterval + " minutes; RequestURL: " +
RequestURL + "]");
while ( ServiceAlive )
{
Trace.WriteLineIf(!Tracer.Enabled,
"Synchronizing system time with time server...");
Trace.WriteLineIf(Tracer.Enabled,
"Creating HTTP request to [" + RequestURL + "]");
WebRequest Req = WebRequest.Create(RequestURL);
Trace.WriteLineIf(Tracer.Enabled,
"Setting default proxy for the HTTP request...");
Req.Proxy = WebProxy.GetDefaultProxy();
Trace.WriteLineIf(Tracer.Enabled,
"Sending HTTP request...");
WebResponse Res = Req.GetResponse();
String TempFile = Guid.NewGuid().ToString() + ".xml";
Trace.WriteLineIf(Tracer.Enabled,
"Creating a temporary XML file [" + TempFile + "]");
StreamWriter SW = new StreamWriter(TempFile);
Trace.WriteLineIf(Tracer.Enabled,
"Saving HTTP response to the temporary XML file...");
SW.Write(new StreamReader(
Res.GetResponseStream()).ReadToEnd());
SW.Close();
Trace.WriteLineIf(Tracer.Enabled,
"Opening the temporary XML file...");
XmlTextReader MyXML = new XmlTextReader(TempFile);
Trace.WriteLineIf(Tracer.Enabled,
"Reading the temporary XML file...");
while ( MyXML.Read() )
{
switch ( MyXML.NodeType )
{
case XmlNodeType.Element:
if ( MyXML.Name == "Timestamp" )
{
Trace.WriteLineIf(Tracer.Enabled,
"Retriving the current timestamp" +
" from the temporary XML file...");
CurrentTimestamp = Convert.ToDouble(
MyXML.ReadInnerXml());
Trace.WriteLineIf(Tracer.Enabled,
"Current timestamp retrived [
" + CurrentTimestamp + "]");
}
break;
}
}
Trace.WriteLineIf(Tracer.Enabled,
"Closing the temporary XML file...");
MyXML.Close();
FileInfo TFile = new FileInfo(TempFile);
Trace.WriteLineIf(Tracer.Enabled,
"Deleting the temporary XML file...");
TFile.Delete();
DateTime MyDateTime =
new DateTime(1970, 1, 1, 0, 0, 0, 0);
Trace.WriteLineIf(Tracer.Enabled,
"Converting the timestamp to time...");
MyDateTime = MyDateTime.AddSeconds(CurrentTimestamp);
Trace.WriteLineIf(Tracer.Enabled,
"Timestamp converted to time [
" + MyDateTime.ToLocalTime() + "]");
SYSTEMTIME SysTime = new SYSTEMTIME();
SysTime.wYear = (short) MyDateTime.Year;
SysTime.wMonth = (short) MyDateTime.Month;
SysTime.wDay = (short) MyDateTime.Day;
SysTime.wHour = (short) MyDateTime.Hour;
SysTime.wMinute = (short) MyDateTime.Minute;
SysTime.wSecond = (short) MyDateTime.Second;
Trace.WriteLineIf(Tracer.Enabled,
"Setting the system time...");
SetSystemTime(ref SysTime);
Trace.WriteLineIf(Tracer.Enabled,
"Switching to sleep state until SyncInterval...");
for ( int i = 0; i < SyncInterval; i++ )
Thread.Sleep(1000 * 60);
Trace.WriteLineIf(Tracer.Enabled,
"Switching back to active mode...");
}
}
catch ( Exception Ex )
{
if ( Tracer.Enabled )
Log.WriteEntry(Ex.StackTrace, EventLogEntryType.Error);
else
Log.WriteEntry(Ex.Message, EventLogEntryType.Error);
}
}
}
}
Sample configuration file
Below is the sample configuration file.
TraceSwitch
is used to enable debug log messages.
SyncInterval
specifies the elapsed time in seconds where the utility synchronizes the Windows system time with the Yahoo! time server.
TimeServerURL
specifies the actual Yahoo! URL which, on request, returns the server time.
<configuration>
<system.diagnostics>
<switches>
<add name="TraceSwitch" value="1" />
</switches>
</system.diagnostics>
<appSettings>
<add key="SyncInterval" value="60" />
<add key="TimeServerURL" value=
"http://developer.yahooapis.com/TimeService/V1/getTime?appid=YahooDemo" />
</appSettings>
</configuration>
History
- Baseline v1.0 - April 25, 2007