Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / enterprise

Get Time from NTP Server using C#

5.00/5 (2 votes)
6 Jan 2016CPOL3 min read 30K  
Get Time from NTP Server using C#

Background

When I was developing code for checking the OneTime Passwords Code for LogonUserWithOTP, I noticed that on one of my development machines (Win7 Enterprise, domain joined) and also on my Windows 10 Mobile Insider Preview Device, the local clock had a rather big offset compared to the time on the server.

So, I decided to write some code that I could share between regular .NET applications and the newer Windows UAP platform.

Doing a search on the internet, I noticed that this had been discussed earlier (like on Q&A on Stackoverflow) but not yet made into a class to be shared between the different Windows platforms.

The NTP servers I will use in my code is the Global NTP pool.

Implementation

As the NTP uses UDP communication on port 123, we need to implement this using Sockets in regular .NET applications and DatagramSockets in the newer WinRT/UAP based applications.

As I want to share my code between the different types of projects, I opted for a Shared Project setup, using Conditional Compilation Directives.

When you create a Windows UAP, in your project properties, you can see that by default, 3 Conditional Compilation Symbols are added to your application: NETFX_CORE, WINDOWS_UWP and CODE_ANALYSIS:

Windows_UWP_Directive

I use the subsequent Conditional Compilation Directives in my code, when I need to make a distinction of the code, depending on the target platform:

C#
#if WINDOWS_UWP
//Code for UAP goes here
#else
//Code for regular .NET goes here
#endif

I decided to create a Helper Class that would embed all the logic of getting the Universal Time from a NTP server. My first idea was to make it a Static Class, so I could just call its methods, without having to instantiate it, but in UAP this would not work, as I had implemented a callback method.

It only makes sense to have one instance in my application, so being a big fan of Design Patterns and (being blown away in 1994 when the now famous book Design Patterns: Elements of Reusable Object-Oriented Software appeared), I choose to implement the Singleton Pattern for my Helper Class.

C#
public class DateTimeGenerator
{
#if WINDOWS_UWP
private TaskCompletionSource<DateTime> myResultCompletionSource;
#endif
private static DateTimeGenerator myInstance;
//--------------------------
//- Singleton, make sure that only 1 Instance of the class exists
//---------------------------
public static DateTimeGenerator Instance
{
get
{
if (myInstance == null)
{
myInstance = new DateTimeGenerator();
}
return myInstance;
}
}
//-------------------------------
//- Private constructor to initialize the internal variables
//-------------------------------
private DateTimeGenerator()
{
#if WINDOWS_UWP
myResultCompletionSource = null;
#endif
}

You can see that the scope of the constructor is Private, so it cannot be invoked directly from your code, and you must use the Instance property of the class.


The method GetNTPTime() is implemented as an Async Task, as it relies on your internet connection, DNS resolution, firewall settings, latency and other network infrastructure stuff and can take a while to contact the NTP server and get the current NTP time back. So to keep the UI responsive, it is best to use a Async Task as this way it runs on its own thread.

C#
public async Task<DateTime> GetNTPTime()

The complete code can be found at GitHub Source.


I think that the best way to use the NTP functionality in your own code is to:

  • have a settings page in your local application, that allows the user to specify whether to use NTP adjustment or not
  • do a periodic check in your application (once a day for example, or when loading the app) and inform the user in case of a larger than allowed, clock deviation

Filed under: C#, Development, Geen categorie Tagged: async Task, Singleton Image 2 Image 3 Image 4 Image 5 Image 6 Image 7 Image 8

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)