Abstracting System Time in ASP.NET Applications

When designing web applications, it is a good idea to be cautious about the way you handle the time of day and calendar. It can get complicated when you have servers in different time zones and the user of the time-sensitive application may, or may not, want his local time, including daylight-saving adjustments, to be assumed. Problems pop up unexpectedly, so maybe it is better to tackle the issue up-front. Dino Esposito explains.

How many times have you used the expression DateTime.Now or even DateTime.UtcNow in production as well as development code? Both of these are fairly commonly-used pieces of code that just return the current system time and the current UTC time respectively. For most web applications, it doesn’t really matter which you use, though a few best practices have been developed over time. The real pain in the neck comes when the application is, of its very nature, time-sensitive; and both the output that it produces, and the user interface it displays, depends on the time of the day and/or, worse yet, the current day of the year. While you are facing these issues, you need to come to grips with the .NET Framework API to deal with time zones and, most surprisingly, with a completely missing API to extract the system time.

In this article, I’ll just review the .NET Framework and .NET Core API for time zones and discuss common practices to deal with time detection in web applications. To help you make sense of the content, which admittedly may sound a little bit weird if your usual domain doesn’t depend on the current time of the day, I’ll also outline the context in which those solutions are necessary.

Defining a Time-sensitive Web Application

A time-sensitive web application is a web application whose user interface depends on the current time of the day, as does some of the internal functionality. Personally, I do a lot of everyday work in the context of scheduling applications; either booking applications or sport tournaments applications. In both cases, a strict functional requirement is that the content that you display is filtered by the current time. For example, a common practice in the press rooms of tennis tournaments is to show the list of completed matches of the previous day until the time comes that matches of the current day start. Usually, at 10am the user interface switches to an empty list waiting for the first matches of the day to complete. Until then, it is expected to show the completed matches of the day before. Why has it got to be so complicated? Isn’t it enough just to switch on at the stroke of midnight? The narrow ‘domain’ reason is that sometimes the matches of the previous day will run across midnight to end around 1am or even 3am. Another reason is that, in the early morning, the fans who connect to the site could then easily see the summary of the past day, including night matches. So switching day around 10am proved to be, in that specific context, a good practice.

Another flavor of time-sensitive web application is used in different ways at different times of the year. As an example, consider a booking application that gets registrations or whatever in a specific timeframe. Both the user interface and backend logic (controllers) should prevent registrations beyond a date or even beyond a given hour of the day. In this case, in addition to formalizing an application-specific system time you also have the problem of testing any functionality. If you stick to using low-level DateTime current time functions, how would you simulate a given time for testing purposes?

In summary, there are a couple of aspects to examine. One is how to extend the system time with time zone information, a task that looms larger in importance with cloud hosting. Another aspect is how to abstract the concept of time so that it can be injected programmatically in the application itself. Let’s start learning a bit more about the native DateTime API.

DateTime API in the .NET Framework

If you’re curious about the details of the time and dates in the .NET Framework, you can take a look at the source code of the DateTime struct here:

http://referencesource.microsoft.com/#mscorlib/system/datetime.cs

In brief, the DateTime.Now method returns the current time as provided by the operating system timer. A Windows low-level function named GetSystemTimeAsFileTime does the job and all it does is to return an Int64 value (ticks) that stores the number of 100 nanosecond intervals elapsed since 12am of January 1, year 1 in the proleptic (assigned a date before it was devised) Gregorian Calendar. The Gregorian calendar was introduced in October 1582 and abruptly added 10 extra days jumping from the 4th to the 14th, according to more accurate calculations of the mean length of the calendar year. For more details on this historical change, you can check out https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar. The proleptic Gregorian calendar is the current Gregorian calendar applied to the retrospective dates until the January 1, 1. All computer systems use the proleptic Gregorian calendar. The DateTime.UtcNow method gets the current system time and subtracts from it the offset of the operating systems time zone.

It turns out that the configured time zone of the operating system is the crucial element that is needed to figure out the time of the day that works for our applications. Noticeably, for a web application that is the configured time zone of the host operating system. If your host is, say, in the United States and the user is based in Europe, then calling DateTime.Now returns a time that is a few hours back before the perceived time. This is going to be a serious issue for some applications. Let’s see how we can deal with time zones programmatically.

Time Zone API in the .NET Framework (Core)

The key class to work with time zone information in the .NET Framework is System.TimeZoneInfo. Each time zone is identified by a plain unique string, known as the ID, that is globally stored in the system registry. The list of supported time zones can be found here: https://support.microsoft.com/en-us/help/973627/microsoft-time-zone-index-values. The ID of the time zone corresponds to the value in the Name column. To read time zone information, specifically the official offset from UTC time, you call the following method.

If you’re interested in a programmatically available list of supported time zones, you do the following instead.

The TimeZoneInfo class offers specific properties to get the base UTC offset that you can then render in terms of hours or minutes. Here’s how to get it in minutes. Note that most of the places of the world have an UTC offset expressed in integer hours, but not all of them. For example, the UTC offset of the popular city of Bengaluru (India) is GMT 5:30 as of September. Hence, using minutes to calculate time zone offsets is much better and more flexible codewise.

What about daylight saving rules? The TimeZoneInfo class returns the neat offset from GMT not including changes due to daylight saving rules. It goes without saying that daylight saving rules are subject to change by law and it may take time for the operating system code to reflect that. Fortunately, though, those changes won’t happen often. The following routine shows how to integrate the calculation of daylight saving with the UTC offset of the time zone. Note that this code might not work for particular cities subject to custom rules.

If I call the function as below, as of September, I will get a value of 120 because two hours is the difference between the current time in Rome and GMT.

Note that if the time zone ID won’t match any of the predefined time zones, then an exception will be thrown. Also note that the code I’ve shown works beautifully both in the .NET Framework and in the .NET Framework Core.

Towards a Global DateTime Abstraction

For those applications that need to present a different user interface at different times of the day, it is important to get to know and support the time zone. You can’t just use DateTime.Now or DateTime.UtcNow because both of them depend on the configuration of the server. If editing the server configuration is an option—mostly not, I’d say, but you never know—then using DateTime methods is acceptable.

In light of this, why not try to take the matter one step further and move towards a abstraction of the software date and time? The concept of system time has to be refreshed to become the concept of application time that only occasionally coincides with the time returned by the timer on the physical server machine.

Here’s a first shot at it.

The default implementation of the interface could be as below.

Instead of calling DateTime.Now, you now create a singleton of the DefaultApplicationDateTime class and call the Now method on it throughout the application. In a classic ASP.NET MVC application, you can expose the singleton out of the global settings object that you might want to have, or out of the HTTP application object in global.asax. In ASP.NET Core, instead, you might want to add an instance of the DefaultApplicationDateTime class as a singleton through the internal dependency injection system.

If you look again at the suggested implementation of the DefaultApplicationDateTime class you see that it first calculates the UTC offset and then it adds the resulting number of minutes to the current UTC time obtained via DateTime.UtcNow. To simplify the testing of those applications that behave differently in different days, you might want to extend the above interface to find a way to inject the base date for which the time is calculated. Put another way, the code might be injected the Datetime to use in lieu of UtcNow in the implementation of method Now().

Impact on ASP.NET Code

Abstracting the implementation of the application current time has a clear impact on the code you write. Basically, you should stop using the low-level DateTime functions and refactor calls to using your own abstraction. I see two possible ways of achieving just that in a reliable way. If you have a global settings object around your application, then I would prefer to expose the application time from there and replace any direct DateTime access with the settings property. If you have a settings object, then a common approach is to expose the settings object from all of the view model classes. The best way to do this is to derive your actual view model classes from a common base class that incorporates settings and the application-specific time abstraction.

In ASP.NET Core, if you have a settings object you can inject it throughout the application via dependency injection. At the same time though, dependency injection also makes it simple to inject just the selected implementation of the date-time logic in the view as well as in any controller or service you happen to use. To inject application-specific time in a view, you can proceed as follows:

You now use the moniker SystemTime to access the current time of the application as it was configured. Notice that in some applications of this technique I read the time zone from the configuration file of the application and embed this reading step in the initialization of the application. In ASP.NET Core programming, this could be achieved by programmatically creating an instance of the application time object and then adding that specific instance to the dependency injection system as a singleton. From the configuration file, whether web.config in ASP.NET MVC or some JSON file in ASP.NET Core, I also read the current base date of the application for ease of testing those scenarios where the user interface is different in different days.

Summary

Honestly, the topic of this article is one that I never thought could have been the subject of a technical article. Yet it happened, and it happens because the problem described—abstracting system time to make it dependent on the application context time—hit me a few times lately. The idea of abstracting the time API is a recent one I had, as for long time I just wrote the same fix around time zones over and over again. In the end, for me it turned out to be an instance of the ‘Rule of Three’ that is popular in code refactoring: the same code can be copied once, maybe twice but when the same code is used three times, it should be refactored to a more general comprehensive approach.