Date and Calendar Formatting

Glossary


  • Japanese Emperor Era: This Japanese calendar works exactly like the Gregorian calendar, except that the year and era are different. The Japanese calendar recognizes one era for every emperor's reign. The current era is the Heisei era, which began in the Gregorian calendar year 1989. The era name is typically displayed before the year. For example, the Gregorian calendar year 2002 would be Heisei 14 in the Japanese calendar.
  • Taiwan calendar: The Taiwan calendar works exactly like the Gregorian calendar, except the year is different. Years in Taiwan are calculated from the year 1912, when Dr. Sun Yat-sen founded a republic in China. 1912 represents Year 1 of the Taiwan calendar. To calculate the year in the Taiwan calendar, take the year in the Gregorian calendar and subtract 1911. For instance, the Gregorian calendar year 1971 would be 60 in the Taiwan calendar.
  • Hijri (Islamic lunar): Since the Islamic calendar is purely lunar, as opposed to solar or luni-solar, the Islamic (Hijri) year is shorter than the Gregorian year by about 11 days, and months in the Islamic (Hijri) year are not related to seasons, which are fundamentally determined by the solar cycle.
  • Hebrew lunar: A calendar based on the cycle of the moon around the Earth. The length of this cycle, the lunar month, is about 29½ days. Twelve lunar months make, therefore, about 354 days.
  • Korean Tangun Era: According to Korean legend, the god-king Tangun founded the Korean nation in BC 2333. Early Korea used a lunar calendar. As the rest of the world encroached on Korea, it eventually went to the solar, Gregorian calendar. Yet much of the country still uses the lunar calendar to keep track of births and deaths and some traditional holidays.
  • Thai calendar: The Thai calendar uses the Buddhist Era BE, which is 543 years older than the Christian Era AD. To convert from a BE date to an AD date, subtract 543. Thus BE 2543=2000. Before April 1, AD 1889, Thailand used a lunar calendar of 12 or 13 months each with 29 or 30 days, each month starting with the new moon. The Gregorian calendar was adopted on April 1, 1889.

Date formatting is not constant throughout the world. Although each date basically displays the day, month, and year, their presentation order and separators vary greatly. In fact, there might be many differences between regions within the same country. To help illustrate this, take a look at two basic date formats for English (United States):

Long Date (Tuesday, October 12, 1954)

Short Date (10/12/54)

Now compare these formats for English (United States), Spanish (Mexico), and Japanese:

Long Date

English (United States): Tuesday, October 12, 1954

Spanish (Mexico): martes, 12 de octubre de 1954

Japanese: 19541012

Obviously the names of the months and days of the week are different from locale to locale, but in Spanish (Mexico), the day comes before the month, everything is lowercase, and the preposition "de" (Spanish for "of") has been added. In Japanese, the day of the week is not displayed, and the translations for day, month, and year act more like separators.

Short Date

English (United States): 10/12/54

Spanish (Mexico): 12/10/54

Japanese: 54/10/12

In the short date, in Spanish (Mexico) the order is once again day/month/year as compared to English (United States) where it is month/day/year. In Japan, the order is year/month/day. This can cause some real confusion if not watched carefully.

All the examples given so far were based on the Gregorian calendar. However, to add to the complexity, world-ready products should also take into consideration other calendaring systems in use worldwide. For example, there are the Japanese, the Buddhist era, the Hijri, the Hebrew lunar, and the Taiwan calendars. One of the major differences between calendars is that each calendar could have a different year value. For example, the Gregorian year 2000 is the twelfth year in the Japanese Heisei era and the year 1421 in the Hijri calendar. The first day of the year might not start on January 1. The Chinese New Year was on February 5 of the Gregorian year 2000. The length of the year and months might also vary, as well as ways of handling leap years. Or even within the same calendar, the first day of the week might start on another day besides Sunday, depending on the culture. For instance, in most of the European countries that use the Gregorian calendar, the start of the week is Monday. Unlike English (United States), there are other locales that use more than one calendar type, such as Korean. (See Figure 4-10.)

figure 4-10 available calendar types for the korean locale.

Figure 4-10 - Available calendar types for the Korean locale.

The Regional And Language Options property sheet allows the user to:

  • Select an alternative calendar (if applicable to the selected locale).
  • Define a two-digit year range for each one of the available calendars.
  • Define a default long-date and short-date formatting for each available calendar type.

Although not all international calendars are provided for, there are many supported calendar types on Windows 2000 and Windows XP. (See Table 4-1.)

Table 4-1 Supported calendar types in Windows 2000 and Windows XP.

Value

Meaning

ENUM_ALL_CALENDARS

All applicable calendars for the specified locale

CAL_GREGORIAN

Gregorian (localized)

CAL_GREGORIAN_US

Gregorian (English strings always)

CAL_JAPAN

Japanese Emperor Era

CAL_TAIWAN

Taiwan

CAL_KOREA

Korean Tangun Era

CAL_HIJRI

Hijri (Islamic lunar)

CAL_THAI

Thai

CAL_HEBREW

Hebrew (lunar)

CAL_GREGORIAN_ME_FRENCH

Gregorian Middle East French

CAL_GREGORIAN_ARABIC

Gregorian Arabic

CAL_GREGORIAN_XLIT_ENGLISH

Gregorian transliterated English

CAL_GREGORIAN_XLIT_FRENCH

Gregorian transliterated French

The interesting fact about NLS APIs and .NET support is that you don't need to know the target languages or how the names of days and months are translated into the target language. The system returns the translated values to you automatically.

You have seen some of the variations that exist among calendars throughout the world. The following sections provide solutions for handling the motley assortment of formats.

Manipulating Calendars and Formatting Dates in Win32

The easiest and most efficient method of formatting the date in a way that's locale-aware is to use the GetDateFormat API. This API allows the formatting of any given date in any supported locale format, according to the currently selected default calendar type and date format. Here is a code sample that shows how this API works:

 TCHAR g_szBuf1[MAX_STR]; GetDateFormat(   LOCALE_USER_DEFAULT,  // the locale for which the formatting is                         //    being done   DATE_LONGDATE,        // date format (long, short, ...)   NULL,                 // the date to be formatted (here current                         //    system date)   NULL,                 // style of date format   g_szBuf1,             // output buffer   MAX_STR               // size of output buffer ); MessageBox(NULL, g_szBuf1, TEXT("Long date format"), MB_OK); 

The result of this code's execution for English (United States) and English (Canada) is illustrated in Figure 4-11.

figure 4-11 long date formatted for english (united states) and english (canada).

Figure 4-11 - Long date formatted for English (United States) and English (Canada).

In more advanced date processing and display, you can use the lpFormat parameter of GetDateFormat to represent the date in any alternative formats that the current locale supports. The elements in Table 4-2 can be used to construct a format-picture string. If you use spaces to separate the elements in the format string, these spaces will appear in the same location in the output string. The letters must adhere to the casing conventions shown in Table 4-2. (For example, the correct formatting for "month as digits with leading zero for single-digit months" would be "MM" not "mm.") Characters in the format-picture string that are enclosed in single quotation marks will appear in the same location and will be unchanged in the output string.

Table 4-2 Date and time picture string elements.

Picture

Meaning

d

Day of the month as digits with no leading zero for single-digit days.

dd

Day of the month as digits with leading zero for single-digit days.

ddd

Day of the week as an abbreviation. The function uses the LOCALE_SABBREVDAYNAME value associated with the specified locale.

dddd

Day of the week as its full name. The function uses the LOCALE_SDAYNAME value associated with the specified locale.

M

Month as digits with no leading zero for single-digit months.

MM

Month as digits with leading zero for single-digit months.

MMM

Month as an abbreviation. The function uses the LOCALE_SABBREVMONTHNAME value associated with the specified locale.

MMMM

Month as its full name. The function uses the LOCALE_SMONTHNAME value associated with the specified locale.

y

Year as last two digits, but with no leading zero for years less than 10.

yy

Year as last two digits, but with leading zero for years less than 10.

yyyy

Year represented by full four digits.

gg

Period/era string. The function uses the CAL_SERASTRING value associated with the specified locale. This element is ignored if the date to be formatted does not have an associated era or period string.

For example, to get the date string:

 "Wed, Aug 31 94" 

use the following picture string:

 "ddd',' MMM dd yy" 

You can also retrieve all standard date formats available for a given locale by using the EnumDateFormatsEx API. Here is how it works:

 // Enumerate all long date formats for the current user locale. EnumDateFormatsEx(EnumDateFormatsProc, // callback function for                                        //    enumeration    LOCALE_USER_DEFAULT,                // flag for the user locale    DATE_LONGDATE);                     // date formats // the callback function and what it contains... BOOL CALLBACK EnumDateFormatsProc(LPTSTR lpDateFormatString,       CALID CalId) {  // If enumeration completed, stop...    if (!lpDateFormatString)       return FALSE;    // Format today's date for the current locale using    // the retrieved format. GetDateFormat(LOCALE_USER_DEFAULT, NULL, NULL, lpDateFormatString,       g_szBuf1, MAX_STR);    return TRUE; } 

Execution of the previous code would give the following result in English (United States) and English (Canada) user locales, respectively. (See Figure 4-12.)

figure 4-12 available long-date formats for english (united states) and english (canada).

Figure 4-12 - Available long-date formats for English (United States) and English (Canada).

As you probably noticed in the last code sample, one of the arguments of the enumeration callback function for date formats is the calendar type (CALID). As mentioned earlier, for some locales more than one calendar type is available. For example, if the user locale is set to Hebrew, then the enumeration would return long-date formats for both Gregorian and Hebrew lunar calendars. For most of the applications, the basic functionality made available by GetDateFormat, which allows the date to be represented in the currently selected calendar and format, is enough. However, some applications might want to have more control over the way this information is presented and eventually select the calendar type in which the date is being displayed. There are several Win32 NLS APIs that allow you to manipulate calendar types.

The EnumCalendarInfoEx API can be used to enumerate all calendar information (such as names of calendars, names of days of the week, and names of months) for all applicable and available calendar types pertaining to a given locale. The code sample enumerates the native names of all supported calendars.

 // Enumerate the native calendar names for all available calendar // types that correspond to the current user locale. EnumCalendarInfoEx(EnumCalendarInfoProc,  // enumeration callback                                           // fuction    LOCALE_USER_DEFAULT,  // locale - any valid LCID    ENUM_ALL_CALENDARS,   // does enumeration for all supported                        //  calendars    CAL_SCALNAME);        // calendar info (return the calendar name) // The callback function will look like: BOOL CALLBACK EnumCalendarInfoProc(LPTSTR lpCalendarInfoString,    CALID Calendar) {    if (!lpCalendarInfoString)       return FALSE;    MessageBox(NULL, g_szBuf2, TEXT("Calendars names"), MB_OK);    return TRUE; } 

Execution of the previous code sample would give the following result on English (United States) and Arabic (Tunisia) user locales, respectively. (See Figure 4-13.)

figure 4-13 available calendar types for english (united states) and arabic (tunisia).

Figure 4-13 - Available calendar types for English (United States) and Arabic (Tunisia).

The GetLocaleInfo API with the LOCALE_ICALENDARTYPE flag also allows you to retrieve the default calendar type currently selected by the user. Once you have retrieved the calendar you want, you can use GetCalendarInfo to retrieve specific information about that particular calendar. This information includes the following:

  • Long, short, and year/month date formats
  • Abbreviations and full names of months
  • Abbreviations and full names of days of the week
  • An integer value indicating the upper boundary of the two-digit year range
  • Native name of the calendar

In a nutshell, Win32 NLS APIs give your application full control over the way a date can be represented by letting you select a given calendar type and a given formatting type for that calendar. In fact, NLS APIs give you more flexibility than you would ever need. As stated earlier, GetDateFormat is probably enough to format dates in a way that's locale-aware.

Date Formatting in Web Pages

In "Retrieving the Browser Language Setting" earlier in this chapter, you saw how to retrieve the current browser locale on the client side and how to set the global locale of your context or session to this value. Once the appropriate locale has been set, you can easily format dates using FormatDateTime in VBScript, a locale-aware function. Suppose you retrieve Spanish (Mexico) as the primary browser locale. ("es-MX" is the default value for this locale.) The following code saves the current context locale (matching the server's user locale), sets the locale to Spanish (Mexico), formats the date in Spanish (Mexico) format, and restores the original locale:

 currentLocale = GetLocale Original = SetLocale("es-MX") DateData = FormatDateTime(Date(),vbLongDate) Original = SetLocale(currentLocale) 

And the output would be:

 martes, 18 de diciembre de 2001 

Obviously, scripting technology does not offer the same flexibility to manipulate dates and calendars as NLS APIs do in the case of Win32 programming. However, the FormatDateTime function lets you display dates in the user's preferred culture, in both short-date and long-date formats.

Date and Calendar Formatting in the .NET Framework

The easiest and most efficient way of formatting dates in the .NET world is to take advantage of the DateTime structure, which provides methods allowing you to perform culture-sensitive operations on DateTime. Use the DateTimeFormatInfo class to format and display a DateTime based on a culture-specific standard. DateTimeFormatInfo defines how DateTime values are formatted and displayed, depending on the culture. For example, using the ShortDatePattern, the date April 24, 2001, is formatted as 4/24/2001 for the "en-US" culture and 24/04/2001 for the "en-GB"-English (United Kingdom)-culture.

An instance of DateTimeFormatInfo can be created for a specific culture, but not for a neutral culture. A neutral culture does not provide enough information to display the correct date format. You just saw that English (United States) and English (United Kingdom) share the same neutral culture-English-and yet have completely different formatting for the date.

The following code example displays the current date using the DateTime-FormatInfo.ShortDatePattern when the CurrentThread.CurrentCulture is set to "en-US," and then to "de-DE" (German in Germany).

 using System; using System.Globalization; using System.Threading; public class FormatDate {    public static void Main()    {      DateTime dt = DateTime.Now;       // Set the CurrentCulture property to U.S. English.  Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");       // Display dt, formatted using the ShortDatePattern.       //    and the CurrentThread.CurrentCulture.       Console.WriteLine(dt.ToString("d"));       // Create a CultureInfo object for German in Germany.       CultureInfo ci = new CultureInfo("de-DE");       // Display dt, formatted using the ShortDatePattern       //    and the CultureInfo object.       Console.WriteLine(dt.ToString("d", ci));    } } 

If you execute this code on April 24, 2001, the output appears as follows:

 4/24/2001         // short-date format for English (United States) 24.04.2001        // short-date format for German (Germany) 

Table 4-3 lists the standard format characters for each standard pattern of formatting, and the associated DateTimeFormatInfo property that can be set to modify the standard pattern. The format characters are case-sensitive; for example, "g" and "G" represent slightly different patterns.

Table 4-3 List of DateTimeFormatInfo properties, patterns, and date formats for "en-US" format patterns. The format pattern varies according to culture.

Format Character

Format Pattern

Associated Property/Description

d

MM/dd/yyyy

ShortDatePattern

D

dddd, dd MMMM yyyy

LongDatePattern

f

dddd, dd MMMM yyyy HH:mm

Full date and time (long date and short time)

F

dddd, dd MMMM yyyy HH:mm:ss

FullDateTimePattern (long date and long time)

g

MM/dd/yyyy HH:mm

General (short date and short time)

G

MM/dd/yyyy HH:mm:ss

General (short date and long time)

m, M

MMMM dd

MonthDayPattern

r, R

ddd, dd MMM yyyy HH':'mm':'ss 'GMT'

RFC1123Pattern

s

yyyy'-'MM'-'dd'T'HH':'mm':'ss

SortableDateTimePattern (based on ISO 8601) using local time

t

HH:mm

ShortTimePattern

T

HH:mm:ss

LongTimePattern

u

yyyy'-'MM'-'dd HH':'mm':'ss'Z'

UniversalSortableDateTimePattern (based on ISO 8601) using uni- versal time

U

dddd, dd MMMM yyyy HH:mm:ss

Sortable date and time (long date and long time) using universal time

y, Y

yyyy MMMM

YearMonthPattern

In Thailand, the Gregorian and the Buddhist calendar coexist. Internally, however-similar to the Win32 paradigm-the .NET Framework handles dates in the Gregorian calendar by using data structures. Therefore, when you use the methods provided by the DateTime structure, you must be aware that the members such as the DateTime.Day property, the DateTime.Month property, the DateTime.Year property, and the DateTime.AddDays method are based on the Gregorian calendar. Even if you change the current calendar in your application's code or change date and time settings through the Regional And Language Options property sheet, the Gregorian calendar is still used to perform the calculations for these methods. This functionality prevents the arithmetic performed by these methods from being corrupted by a user's settings. If you want to perform culture-sensitive date and time operations based on the current calendar, you must use the DateTimeFormatInfo.Calendar property to call methods provided by the Calendar class such as Calendar.GetDayOfMonth, Calendar.GetMonth, Calendar-.GetYear, and Calendar.AddDays.

To handle native calendar types, the .NET Framework provides the Calendar class as well as the following Calendar implementations: GregorianCalendar, HebrewCalendar, HijriCalendar, JapaneseCalendar, JulianCalendar, KoreanCalendar, TaiwanCalendar, and ThaiBuddhistCalendar. Other things you can use include the CultureInfo class, which has a CultureInfo.Calendar property that specifies a culture's default calendar. The CultureInfo.OptionalCalendars property specifies the optional calendars supported by a culture.

The following code example in C# creates CultureInfo objects for the culture "th-TH" (Thai in Thailand) and displays the default and optional calendars for each culture. The GregorianCalendar is further divided into subtypes by the GregorianCalendar.CalendarType property. In this example, each time the calendar is determined to be Gregorian, the CalendarType value is retrieved and displayed.

 using System; using System.Globalization; public class TestClass {    public static void Main()    {       // Create a CultureInfo object for Thai in Thailand.       CultureInfo th = new CultureInfo("th-TH");       DisplayCalendars(th);    }    protected static void DisplayCalendars(CultureInfo cultureinfo)    {       CultureInfo ci = new CultureInfo(cultureinfo.ToString());       // Display the default calendar for the culture.       if (ci.Calendar is GregorianCalendar)          Console.WriteLine ("\n\n");          Console.WriteLine (             "The default calendar for the {0} culture is: \n{1}\n\n",             ci.DisplayName.ToString(), ci.Calendar.ToString() +             " subtype " +             ((GregorianCalendar)ci.Calendar).CalendarType.ToString());       else          Console.WriteLine ("\n\n");   Console.WriteLine (            "The default calendar for the {0} culture is: \n{1}\n\n",            ci.DisplayName.ToString(), ci.Calendar.ToString());  // Display the optional calendars for the culture.         Console.WriteLine (          "The optional calendars for the {0} culture are: ",          ci.DisplayName.ToString());       for (int i = ci.OptionalCalendars.GetLowerBound(0); i <=          ci.OptionalCalendars.GetUpperBound(0); i++ )          {           if (ci.OptionalCalendars[i] is GregorianCalendar)             {                // Display the calendar subtype.                String CalStr = (ci.OptionalCalendars[i].ToString() +                   " subtype " +  ((GregorianCalendar)ci.OptionalCalendars[i]).CalendarType.ToString());                Console.WriteLine(CalStr);             }             else                Console.WriteLine (ci.OptionalCalendars[i].ToString());          }    } } 

This code produces the following output:

 The default calendar for the Thai (Thailand) culture is:  System.Globalization.ThaiBuddhistCalendar The optional calendars for the Thai (Thailand) culture are:   System.Globalization.ThaiBuddhistCalendar               System.Globalization.GregorianCalendar  subtype Localized 

As you see, the .NET Framework offers a UI that's extensive, yet flexible and easy to use for date and calendar formatting. The sections that follow outline the points to consider when representing time in Win32 applications, Web pages, and the .NET Framework. Included is information on using the appropriate separators between hours, minutes, and seconds; constructing format-picture strings; and displaying time zones.



Microsoft Corporation - Developing International Software
Developing International Software
ISBN: 0735615837
EAN: 2147483647
Year: 2003
Pages: 198

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net