Date Formatting with YUI – Part IV

By Philip TellisJuly 6th, 2009

In Part I of this series, we introduced date formatting with the YUI Date utility and integrated it with the DataTable control in Part II and the Charts control in Part III. In this final part, we’ll look at date localisation with YUI.

To recap, we can format dates using YUI using the YAHOO.util.Date class, which is currently distributed as part of the DataSource utility. Any valid strftime format specifier is supported, so for example, YAHOO.util.Date.format(new Date(), { format: "%Y-%b-%d"}); would return the date as <four digit year>-<short month name>-<two digit day of month>.

The Date utility accepts an optional third parameter, which specifies the locale to use when formatting a date. If not specified, this defaults to "en". The locale is a string that may be the two-letter ISO-639-1 language code, optionally followed by a hyphen and a two-letter ISO-3166-1 country code. For example, fr is used for French, while fr-CA is used for the dialect of French spoken in Canada, and fr-CH is used for the dialect of French spoken in Switzerland. de-CH, on the other hand, is the dialect of German spoken in Switzerland.

Examples of valid locale codes
Locale Code Language
en English (default)
fr French
fr-CA French dialect spoken in Canada
fr-CH French dialect spoken in Switzerland
de German
de-DE German dialect spoken in Germany

The locale code impacts only the following format specifiers:

%a
abbreviated weekday name according to the current locale
%A
full weekday name according to the current locale
%b
abbreviated month name according to the current locale
%B
full month name according to the current locale
%c
preferred date and time representation for the current locale
%h
same as %b
%p
either “AM” or “PM” according to the given time value, or the corresponding strings for the current locale
%P
like %p, but lower case
%r
time in AM and PM notation equal to %I:%M:%S %p
%x
preferred date representation for the current locale without the time
%X
preferred time representation for the current locale without the date

Built-in locales

Let’s start off by looking at the built-in locales. The Date utility includes the following locales by default:

  • en – English (the default)
  • en-US – US English
  • en-GB – British English
  • en-AU – Australian English (identical to British English)

In the following example, we’ll print out the locale-specific date format using the built-in locales:

var d = new Date();
var f = { format: "%x%n" };
var s = "%x:\n";
s += "  Default:\t" + YAHOO.util.Date.format(d, f);
s += "  en-US:\t" + YAHOO.util.Date.format(d, f, "en-US");
s += "  en-GB:\t" + YAHOO.util.Date.format(d, f, "en-GB");

alert(s);

See a working example. Note the different output for en-US and en-GB. Similar differences between these two locales can be seen for %r, %c, and %X.

Supporting other languages

Now, there are many languages other than English, and many web applications that cater to speakers of these languages which the date formatter should support. While these aren’t provided by YUI itself, it is fairly easy to add your own locale patch. Let’s create one now for French. We do this by mixing in the YAHOO.util.DateLocale class with our locale definitions using the YAHOO.lang.merge method:

YAHOO.util.DateLocale["fr"] = YAHOO.lang.merge(YAHOO.util.DateLocale, {
	a: ["dim", "lun", "mar", "mer", "jeu", "ven", "sam"],
	A: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
	b: ["jan", "fév", "mar", "avr", "mai", "jun", "jui", "aoû", "sep", "oct", "nov", "déc"],
	B: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
	c: "%a %d %b %Y %T %Z",
	p: ["", ""],
	P: ["", ""],
	x: "%d.%m.%Y",
	X: "%T"
});

var d = new Date();
var f = { format: "%c%n" };
var s = "%c:\n";
s += "  Default:\t" + YAHOO.util.Date.format(d, f);
s += "  fr:   \t" + YAHOO.util.Date.format(d, f, "fr");

alert(s);

Try it out.

Similarly, we can create one for Canadian French by using the French locale as a base. The only difference is in the locale-specific date format %x:

YAHOO.util.DateLocale["fr-CA"] = YAHOO.lang.merge(YAHOO.util.DateLocale["fr"], {
	x: "%Y-%m-%d"
});

var d = new Date();
var f = { format: "%A, %x%n" };
var s = "%A, %x:\n";
s += "  Default:\t" + YAHOO.util.Date.format(d, f);
s += "  fr:   \t" + YAHOO.util.Date.format(d, f, "fr");
s += "  fr-CA:\t" + YAHOO.util.Date.format(d, f, "fr-CA");
s += "  fr-CH:\t" + YAHOO.util.Date.format(d, f, "fr-CH");
s += "  de-CH:\t" + YAHOO.util.Date.format(d, f, "de-CH");

alert(s);

Try it out.

Notice that we also try to access fr-CH and de-CH which haven’t been defined. In this case, the Date utility falls back to a less specific locale and tries fr and de instead. Since de hasn’t been defined either, it falls back to en, which is built in.

I’ve included definitions for a few locales as examples. If you’d like to use these locales, it may make more sense to just include the code directly in your HTML pages, or copy the files to your own servers.

  • fr – French, Canadian French and Swiss French
  • de – German, and Swiss German
  • hi – Hindi
  • ko – Korean

7 Comments

  1. All those French words should be capitalized ;-) Good article, great info, Thanks Philip!

  2. Good stuff as usual. This should be “it” file

    YAHOO.util.DateLocale['it'] = YAHOO.lang.merge(YAHOO.util.DateLocale, {
    a: ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'],
    A: ['domenica', 'lunedi', 'martedi', 'mercoledi', 'giovedi', 'venerdi', 'sabato'],
    b: ['gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'],
    B: ['gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'],
    x: '%d/%m/%Y',
    X: '%T'
    });

    YAHOO.util.DateLocale['it-IT'] = YAHOO.lang.merge(YAHOO.util.DateLocale['it'], {
    });

  3. Great info! Note the locale is case-sensitive. This might affect you if you are using the HTTP Accept-Language header to determine which language to show. Most browsers send an all–lower case Accept-Language header (“en-gb”), but YAHOO.util.DateLocale would expect “en-GB”.

  4. @Julien, you’re probably right, but I’ve only been able to find documentation regarding abbreviated short forms for French months. Until I can find an authoritative source , I’m sticking with what the system locale information on unix tells me.

    @Andrea, thanks for the addition.

    @Nate: good point. We actually don’t recommend using the Accept-Language header as the sole method for detecting language for a few reasons. Some people have this header set incorrectly, and there are also cases when one is travelling in a foreign country, using an internet cafe computer. In both cases, the Accept-Language header may not be what the user really wants. It’s better to give the user the choice up front. You can also just restrict the choice to the list that you support.

    There’s also the case where you may not actually support anything that the Accept-Language requests. In that case, you have a choice between giving the user the option, or returning a 406 Not Acceptable header.

    That said, the locale string we use is not very strict, so someone could potentially create one for klingon, or elmer fudd.

  5. I’m wondering if there’s a preferred way of augmenting the locale – ie. if I want to have a localized time format – 24 hours by default, 12 hours for en-GB. Not sure this is the best way to do:

    Y.each(Y.DataType.Date.Locale, function(loc) {
    loc['TS'] = ‘%H:%M’;
    });
    Y.DataType.Date.Locale["en-GB"]["TS"]=’%I:%M%p’;

  6. @Janos, the syntax you’re using seems to be based on the YUI3 version of the date utility and it looks like you’re trying to add a new format specifier to the locale.

    At this point of time though, only single character format specifiers are supported, so this may not work the way you expect it to. That said, I haven’t verified that it won’t work.

    We’ll be adding templates in a future version, mainly to make it easier to generate an ISO8601, or RFC2822, or unix date command style dates. When this support has been added, it should be possible to do what you want. I have no timeline on when this will happen though.

  7. Julien Lecomte is absolutely wrong, the names of the days as well as the months’ names must not be capitalized. Any decent french grammar (e.g. “Le Bescherelle”) can be looked up on that in 20s. The only special case is about anniversary dates or generally important historical dates such as “Le 11 Novembre” or “Le 14 Juillet”. Those acquire a special status and cease to be treated as common names.

    The YUI Date utility is a blessing, thnaks for the awesome works… as usual !