Sep 1 2008

What time was that?

Category: Tips and TricksJoeGeeky @ 11:50

I can't count the number of applications where I had to capture, store, and/or render date/time values. Generally speaking, this is not a problem although eventually taking this for granted will land you in trouble. Very often I see people just grabbing the local machine time (Ex. DateTime.Now) and storing it as a simple string or even a SQL Server DateTime (Ex. 31/12/2009 12:00). This is fine until Daylight Saving Time (DST) occures or a user reviews content from another time zone.

Here are a few rules that; if followed; will help you avoid any pain:

Be consistent in persistance, preferably UTC

Pick a time zone... any time zone... with no DST applied.  whenever you store a date/time, convert it to that time zone before you persist it.  To make things easier, I recommend you choose Universal Coordinated Time (UTC) (commonly referred to as GMT).

DateTime.UtcNow

Note: GMT and UTC are often misuderstood.  For example, the following three time zones are all GMT/UTC time zones.  The problem is that 2 of the 3 adjust for DST which is not suitable when trying to choose a stable neutral time zone. 

  • Greenwich (Adjusts to DST)
  • Dublin, Edinburgh, Lisbon, London (Adjusts to DST)
  • Casablanca, Monrovia, Reykjavik (No adjustment)

Retain the time BIAS details (e.g. offset)

If you choose to store your Date/Time information as something other then UTC, remember to keep the BIAS information for each persisted value so you can adjust time as needed. In the time zone world the offset information is called BIAS which is often expressed as the number of minutes to add or subtract to a UTC time to derive local time. One simple way to do this is to convert DateTime values using the ISO 8601 format.

To convert a DateTime to a string and retain the BIAS:

string localTimeWithBias = DateTime.Utc.ToString("O");
//Example: 2008-04-10T06:30:00.0000000-07:00

To convert a string back to the correctly adjusted DateTime object:

DateTime newDate = DateTime.Parse(localTimeWithBias, null, DateTimeStyles.RoundtripKind);

Note the -07:00 bit at the end... This is the time BIAS, this means the time is -7 hours from UTC.

Adjust persisted values for display

Whether you are rendering a Date/Time as content or writing it to a file, adjust time to meet the needs of the target. Here is a small set of sample extension methods that accomplish the following:

  • Convert time based on user configured preferences
  • Defaults to an application default if not configurable using user preferences
  • Convert time to and from UTC

internal static DateTime ToUTCFromUsersTimeZone(this DateTime instance)
{
    try
    {
        if (instance.Kind == DateTimeKind.Utc)
            return instance;

        IUser currentUser = UserContext.Current.User;

        TimeZoneInfo offsetZone = currentUser.TimeZone ??
            TimeZoneInfo.FindSystemTimeZoneById(MyCustomConfigSection.Current.DefaultTimeZone);

        DateTime convertedDateTime = TimeZoneInfo.ConvertTimeToUtc(instance, offsetZone);

        return DateTime.SpecifyKind(convertedDateTime, DateTimeKind.Utc);
    }
    catch
    {
        return instance;
    }
}

internal static DateTime ToUsersTimeZone(this DateTime instance)
{
    try
    {
        if (instance.Kind == DateTimeKind.Local) 
            return instance;

        IUser currentUser = UserContext.Current.User;

        TimeZoneInfo offsetZone = currentUser.TimeZone ??
            TimeZoneInfo.FindSystemTimeZoneById(MyCustomConfigSection.Current.DefaultTimeZone);

        DateTime convertedDateTime = TimeZoneInfo.ConvertTimeFromUtc(instance, offsetZone);

        return DateTime.SpecifyKind(convertedDateTime, DateTimeKind.Local);
    }
    catch
    {
        return instance;
    }
}

Don't forget Daylight Savings Time (DST)

Keep in mind that not every time zone uses DST, and those that do, don't all adjust by one hour or on the same day. More than anything else, you will need to do some careful testing around this area.

Tags: , ,

Aug 20 2008

What format do you want to use?

Category: Tips and TricksJoeGeeky @ 14:31

In this great big wide world of ours there are a lot of different ways to represent simple content such as Dates, Numbers, etc...  If your web applications are trying to reach international markets or you have an international team it makes sense to try and cater to the needs of your users. Fortunetally for us .NET has given us a lot of nice tools to simplify this for us.  Before we get into that, lets look at a couple very simple examples

The number 999999999:
Locale Format
England (en-GB) 999,999,999.00
France (fr-FR) 999 999 999,00
Denmark (de-DE) 999.999.999,00

The date 3 January 2006:
Locale Format
USA (en-US) 1/3/2006
France (fr-FR) 03/01/2006
Denmark (de-DE) 03.01.2006

Take a closer look at the dates above, as you will see, assumptions made by users from various locales can lead to very different meanings of what you are trying convey. In this case, some users will assume the date is 03 January 2006 while others will assume it is 01 March 2006.

There is a tendancy to use format specifiers or Culture objects such as follows:

CultureInfo culture = new CultureInfo("en-GB");
uint amount = 999999999;
amount.ToString("n", culture);
//Renders as 999,999,999.00

While this is useful for some scenarios it can lead to a load of variables being passed around all over the place. A more elegant way of dealing with this is the set the Culture on the executing thread which will default all format specifiers to the format for a given Culture.

Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB")
uint amount = 999999999;
amount.ToString("n");
//Renders as 999,999,999.00

Setting the thread can be done when an application starts, at the beginning of a request, or whenever it may be appropriate for your applications. The goal is to seperate this area of concern from other downstream components so they need not concern themselves with determining what Culture formats are required.

Determining the correct Culture/Formats to use can be tricky since it can be derived from so many places... Once again, you will have to do what makes since from your application. Whatever you decide to do, try to store/key this information using standard IETF tags as that will make things more standard (e.g. BCP 47, RFC 5646, RFC 4647, RFC 5645), portable, and easier to key on. Here are a few common examples:

  • For thick clients, you could use the Users Windows Culture settings
  • For web applications, Content-Language headers supplied by Browsers with HTTP Requests (e.g. RFC 2616, RFC 1766)
  • Request payloads such as XML (e.g. xs:lang attribute [RFC 3066])
  • Application supplied user preferences
  • Etc...

Here is an example of an HTTP Module that derives language preferences from Web Requests and sets the Culture for the target application to use. This is a nice pattern for ASP.NET applications because the module can be reused accross multiple applications or instances, and cleanly seperates this area of concern.


using System;
using System.Globalization;
using System.Threading;
using System.Web;
using Configuration;

public sealed class LocalizationService : IHttpModule
{
    #region IHttpModule Members

    public void Dispose()
    {
        //Nothing to do here
    }

    public void Init(HttpApplication context)
    {
        //subscribe to then Error event
        context.BeginRequest += SetLocalization;
    }

    internal void SetLocalization(object sender, EventArgs e)
    {
        var appInstance = (HttpApplication)sender;

        CultureInfo requestCulture;

        if (!ParseCultureFromRequestContext(appInstance, out requestCulture))
        {
            requestCulture = new CultureInfo(MyCustomConfigSection.Current.DefaultIetfCulture);
        }

        Thread.CurrentThread.CurrentCulture = requestCulture;
        Thread.CurrentThread.CurrentUICulture = requestCulture;
    }

    #endregion

    private static bool ParseCultureFromRequestContext(HttpApplication application, 
        out CultureInfo cultureInfo)
    {
        cultureInfo = null;
        string[] languages = application.Context.Request.UserLanguages;

        if (languages != null)
        {
            foreach (string language in languages)
            {
                try
                {
                    cultureInfo = new CultureInfo(language);

                    return true;
                }
                catch
                {
                    //Language tag not understood. Do nothing, go to the next one
                }
            }
        }

        return false;
    }
}

Tags: , ,

Mar 15 2006

An Intellectual Pursuit Continued with Localization and Globalization

Category: Intellectual PursuitsJoeGeeky @ 17:34

As witnessed on almost every news channel today, the military’s mission objectives can shift radically from warfighting to civil support.  This community has a lot of really great examples of practical localization and globalization opportunities. In the classic military environment, everyone speaks English, understands the common military phonetic alphabet, and has their clocks set to Greenwich Mean Time (e.g. Zulu) using military time. Twenty years ago those assumptions general held up, although today, they cannot rely on any of these assumptions any longer. 

Today, commanders in the field have to be able to more quickly adapt their available assets to peace-driven, civil support and security objectives. In these roles, field commanders often support non-military domestic and international civil authorities. Now, military units have to speak in local terms to include time format, time zone, language, grammar, measurement conversion, currency, telephony requirements, and more. While this paradigm is not a new one, there architectures generally do not support these changes and present difficult problems for field users who have to toggle back-and-forth between the two.

Consider something as simple as a keyboard. In a multi-national environment how would foreign nationals interact with our keyboards? Internationally, keyboard layouts vary widely. From a technological stand-point, advances in keyboards (Ex. LCD keyboards) will offer cost-effective solutions. While not currently available to the public, this type of technology offers a lot of solutions from a human factors stand-point, but specifically helps address multi-cultural, regional, and language challenges faced in the field.

Issues such as these require consideration early in development and engineering processes. We are not proposing that all applications need to support every language, local, and/or culture right out of the box. However, the geopolitical and military support climates today; and for the foreseeable future; suggest that future capabilities need to be malleable enough so that we can localize/globalize them as needed.   

For developers and engineers, localizing a system is the process of extracting all the language-dependent content that are normally contained within compiled applications, and putting them in a separate location that can later be modified by a translator and system administrators. By itself, this type of change does not cost anything and is really a matter of discipline within the engineering process. However, if this type of issue is not identified early the cost to go back and make these types of changes can be quite high.

Tags:

Mar 2 2006

An Intellectual Pursuit

Category: Intellectual PursuitsJoeGeeky @ 05:08

This one was a bit of a brain bender... In this project I didn't write any code at all. I was asked to try and define key developmental trends that might define the tenets for any number of new projects. In this great big world of ours there are a lot of opinions on this issue, so I read and I read, but in the end, I was left to come up with my own... Ohhh no! I had to think for myself and in this case I could not rely on the genius of Microsoft, MSDN, or any other resource I had come to rely on. Ok... Here it goes...

In order to understand long range technological impacts to the systems and products of the Future, we need to take a look at key industry and government transformations and architecture trends that are forming today. In the last decade, the requirements for applications and information interoperability, and more importantly, cross-domain information sharing have widened significantly. Technologically speaking, these changes have influenced a number of elements related to how these and related stakeholders are developing systems, applications, and information resources today. The following areas constitute some of the key transformational elements of modern solutions:

• Service-orientation (SOA)
• Human Factors Engineering
• Distributed, Parallel and Adaptive Information Processing
• Presence and Discovery Enabled Solutions
• Appliance-based Solutions
• Localization, Globalization, and Internationalization

As part of this endeavor I also put together an HCI Concepts brief. At a high level, the goal was to expand on the Human Factors Engineering material, with specific emphasis on graphical interfaces. As with most complex issues, the most important thing is to (a) define a common vernacular, (b) define measurements for success,  and (c) come up with a jingle... In this case "Sex Sells" and I don't mean porn.

Over the next few posts I will explore these ideas in more depth so stay tuned 

HCI Considerations.pdf (2.77 mb)

Tags: , , , , ,