Click here to Skip to main content
Email Password   helpLost your password?

Screenshot - Article.gif

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.

/*
 * WINDOWS TIME SYNCHRONIZER - C# .NET
 * 
 * FILE NAME    :    Program.cs
 * 
 * DATE CREATED :    March 06, 2007, 12:05:54 PM
 * CREATED BY   :    Gunasekaran Paramesh
 * 
 * LAST UPDATED :    April 25, 2007, 12:38:12 PM
 * UPDATED BY   :    Gunasekaran Paramesh
 * 
 * DESCRIPTION  :    Synchronizes Windows System Time with Yahoo! Server Time.
*/

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
            {
                // Initialize EventLog

                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...");

                    // Send HTTP request for Timestamp

                    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();

                    // Save as Timestamp as a temporary XML file

                    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();

                    // Read the XML file and get the Timestamp value

                    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();

                    // Delete the temporary XML file

                    FileInfo TFile = new FileInfo(TempFile);
                    Trace.WriteLineIf(Tracer.Enabled, 
                        "Deleting the temporary XML file...");
                    TFile.Delete();

                    // Convert Timestamp to Time

                    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() + "]");

                    // Change the system time

                    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 )
            {
                // Log for errors                

                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

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralNTP
Wael Al Wirr
4:21 9 Aug '07  
hey guys,
I am trying to synchronize my server with a NTP server can anyone help me ?

WaelA
Software Engineer
WaelA@hotmail.com

Generalit visits strange adds sites ?!
andré_k
22:02 17 Jul '07  
perhaps the Yahoo's "web service" site you proposed systematically opens those adds:

Access:Outbound TCP access Object:1040 -> 66.94.228.98 (www.hackday.org):80 (http)
Access:Outbound TCP access Object:1041 -> 81.95.96.66 (uvirt1.active24.cz):80 (http)
Access:Outbound TCP access Object:1042 -> 194.154.75.194 (webhosting-bix.rbc.ru):80 (http)
Access:Outbound TCP access Object:1043 -> 72.22.69.53 (host368.ipowerweb.com):80 (http)

And so will be with any "encapsulated" and mysterious site you'll find.

So, if you want to keep my sympathy,
Solution 1° : you'd better write a clean time web service or a cleaner program
Solution 2° : Finally, a NTP application to synchronize the local computer time would perhaps be simpler, faster and much better..




GeneralWhy this when there is NTP?
Ramon Smits
5:12 24 May '07  
I'm sorry to say but why use this solution when time-synchronisation is build-in in Windows? NTP even adjusts time according to the latency between the client and the server.

XP has configurable NTP settings in it's date time properties and all other Windows variations can do this on the commandline with the NET TIME command.
GeneralRe: Why this when there is NTP?
Gunasekaran Paramesh
8:55 24 May '07  
Why Windows when there is Linux? I just thought to develop this when I found the sample service from Y!

Programming is fun indeed!!!

Param

GeneralRe: Why this when there is NTP?
Ramon Smits
12:41 24 May '07  
I don't say programming isn't fun. I love programming but this just isn't the way to do time synchronisation. You should have made that clear in your article to user NTP for that and this is just a sort of webservice example.

Don't get me wrong.. go on with contributing articles but do point out your motivation to create the article in the first place and add pro's and con's if there are common other solutions available.

In other words.. innovate, don't immitate unless its better Smile
GeneralRe: Why this when there is NTP?
sillett
15:40 24 May '07  
In many cases, especially in a corporate environment, the NTP or TIME protocols are blocked. And one often finds in a Windows environment with a sloppy IT department that the Windows time server (typically the PDC Emulator in Active Directory) is off by several minutes.

Thus a method for time synchronization that uses HTTP and not NTP or TIME is quite useful when the ports are blocked as pretty much everyone allows outbound HTTP.

Thanks for the article.

Bob

GeneralRe: Why this when there is NTP?
Ramon Smits
22:31 24 May '07  
Corporate environments have domains. Computers are within a domain and for security it is very critical that all computers within a domain are sharing the same time. If indeed the domain controllers are having a big offset then the administrators should sync their domain controllers with any of the *.pool.ntp.org servers. The solution is not to just adjust one pc in the network with this method.
GeneralRe: Why this when there is NTP?
sillett
2:54 25 May '07  
Why are you so obstinate? Who appointed you the gatekeeper of what can be posted on CodeProject? He wrote this article because it was fun and the code does something useful in that it syncs time to Yahoo over HTTP. The fact that it uses HTTP and not NTP makes it useful.

The purpose of CodeProject is to share code snippets. This code can also be used as a template to interface with other Yahoo services. This code is a "for the sake of an example" project.

Crawl out from under your little bridge and learn some people skills.
AnswerRe: Why this when there is NTP?
Ramon Smits
3:02 25 May '07  
If people just post everything they make up then the quality of CP.COM is degrading.

So lets wrap up all usefull protocols into webservices! Wow that would be a good idea! Lets just wrap up SMTP, NNTP, NTP, TELNET, FTP! That would them make them more accessible!

I respect skills but I really don't see them in this article. Instead of just insulting me and my opinion and free right to let me say why this really shouldn't be the way to go you are nagging without good arguments.
GeneralRe: Why this when there is NTP?
JLester
4:11 29 May '07  
Not everything is as black and white as you would like to make it seem. Yes, computers in corporate environments should sync with domain controllers but this is not always possible.

Recently, I had to do something very similar to this, and the article here would have been an excellent reference for me. In my case the computer was not going to be added to the corporate domain, and because the ports were blocked NTP was unavailable.

I agree that a little statement mentioning NTP would have been useful but sitting on your moral programming high ground saying one should not use this method, and NTP is the only way it should be done, is just unrealistic and very short sighted.

Nice article, even if it did come 3 months to late for me :P

AnswerRe: Why this when there is NTP?
Ramon Smits
5:51 29 May '07  
If the ports where blocked then the it staff whould open up those port for NTP traffic. Not a big issue at all.

Any other method shouldn't be used at all.

This is ofcourse my opinion. Smile Do whatever you would like to do. But if I would ever employ someone like you that just did it this way because ports where blocked then I really doubt your skills and wouldn't fit in the organisation.

IT infrastructure is ment to help not to restrict. Firewalls are there for security not for restrictions. But that is a whole other kind of discussion.
GeneralRe: Why this when there is NTP?
JLester
6:26 29 May '07  
I'll restate not all real world issues are as black and white as "Any other method shouldn't be used at all". Just because the ports should be opened up, which I agree with, doesn't mean they will be.

The fact that you would question someone’s skill because of a restriction, that may or may not be out of the persons control, shows just how short sighted you are. I'd love to hire someone who is able to solve a problem in more than one way depending on the external conditions.

Would I have prefered to use NTP, yes. Did I look into it, yes. Unfortunatly, in my "real world" application this was the only method available to synchronize the time on the machine, and I appreciate the article and hope Param posts more.

GeneralRe: Why this when there is NTP?
AndyCLon
23:21 28 May '07  
Yes, there is NTP and it's a much lighter and more flexible protocol than a webservice and I agree that this is not appropriate for an office machine in a domain. But as mentioned there are also cases where an individual machine might want to have an accurate time but is not able to access either a domain controller or NTP server.

So you perhaps the article could be improved by adding comments at the beginning that mention these?

Am I correct in thing that the time is being synced every 60s? This seems excessive, once or twice a week should be sufficient to compensate for clock drift on the RTC. Some comments on why clock drift occurs and hence why you need to sync the time would also be good.

In general I think this is a useful article, the techniques and code could be easily robbed for other projects and it's clearly written.

My final thought is that of course "Gunasekaran Paramesh" should keep writing articles and "Ramon Smits" should keep providing feedback, the thing that makes quality articles is this feedback process, not people getting things exactly right first time. Don't forget that there is a rating system for people to mark articles.



Last Updated 24 May 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010