循序渐进全球化

日期格式设置

日历差异时间格式设置

*

 

本页内容

概述和说明概述和说明

Win32 中的日历处理和日期格式化Win32 中的日历处理和日期格式化

.NET Framework 中的日期和日历格式化.NET Framework 中的日期和日历格式化

引用引用

概述和说明

日期格式设置在整个世界上并不是完全一致的。虽然每种日期格式基本都显示日、月和年的内容,但其显示顺序和分隔符却相差很大。实际上,相同国家/地区内的各区域之间也可能存在诸多差异。

为帮助说明这一点,让我们来看一看两种基本的日期格式:

  

长日期 (Tuesday, October 12, 1954)
短日期 (10/12/54)

现在让我们比较一下美国英语、墨西哥西班牙语和日语之间这些格式的异同。

长日期

  

英语:Tuesday, October 12, 1954
西班牙语:martes 12 de octubre de 1954
日语:1954年10月12日

显然,月份和一周中每一天的名称在各区域设置之间是不同的。此外还有一些其他明显的区别。在西班牙语中,日在月份之前,所有内容均为小写,而且添加了冠词 "de"。在日语中,并不显示星期几,日、月和年的译文所起的作用很像分隔符。

短日期

  

英语:10/12/54
西班牙语:12/10/54
日语:54/10/12

从短日期中我们再次看到,西班牙语的顺序是日/月/年(美国英语的顺序是月/日/年)。在日本,顺序是年/月/日。如果不注意的话,这可能会引起混淆。例如,在不同的国家/地区,指定为 07/04/01 的日期可能表示:

  

英语:2001 年 7 月 4 日
西班牙语:2001 年 4 月 7 日
日语:2007 年 4 月 1 日

这些例子表明了在处理日期时要使用日期 API 的原因。它们不但能处理正确的日期,而且还能显示正确的长日期译文,从而可以节省翻译成本。

图 1:韩语区域设置的可用日历类型

图 1:韩语区域设置的可用日历类型


表 1:Windows 2000 和 Windows XP 中支持的日历类型

表 1:Windows 2000 和 Windows XP 中支持的日历类型


返回页首返回页首

Win32 中的日历处理和日期格式化

要想以可识别区域设置的方式来设置日期格式,最简单有效的方法就是使用 GetDateFormat API。此 API 允许根据当前所选的默认日历类型和日期格式,以任何支持的区域设置格式来格式化任何给定的日期。以下代码示例显示了此 API 的工作原理:

  

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);

下面的图 2 说明了此代码针对英语(美国)和英语(加拿大)的执行结果:

图 2:针对英语(美国)和英语(加拿大)格式化的长日期

图 2:针对英语(美国)和英语(加拿大)格式化的长日期


 

在更高级的日期处理和显示中,您可以使用 GetDateFormat 的 lpFormat 参数以当前区域设置支持的任何替代格式来显示日期。表 4-2 中的元素可用于构造格式-简写字符串。如果使用空格来分隔格式字符串中的各个元素,则在输出字符串中这些空格会显示在相同的位置。字母必须要遵循表 4-2 中显示的大小写约定(例如,对于“用两位数字表示月份(不足两位前面加零补齐)”,正确的格式设置是 "MM",而不是 "mm"。)格式-简写字符串中位于单引号中的字符在输出字符串中将显示在相同位置并且保持不变。

表 2:日期和时间简写字符串元素

表 2:日期和时间简写字符串元素


 

例如,要获得以下日期字符串:

  

"Wed, Aug 31 94"

使用以下简写字符串:

  

"ddd',' MMM dd yy"

也可以使用 EnumDateFormatsEx API 来检索可用于给定区域设置的所有标准日期格式。下面介绍它的工作原理:

  

// 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;

针对英语(美国)和英语(加拿大)用户区域设置执行上述代码将分别得到以下结果。(请参见下方的图 3)

图 3:针对英语(美国)和英语(加拿大)用户区域设置枚举所有长日期格式的结果

图 3:针对英语(美国)和英语(加拿大)用户区域设置枚举所有长日期格式的结果


您可能已经在上一个代码示例中注意到,日期格式的枚举回调函数的其中一个参数是日历类型 (CALID)。正如先前所述,对于某些区域设置,可以使用多个日历类型。例如,如果用户区域设置被设置为希伯来语,则无论是对于公历还是对于希伯来阴历,枚举都将返回长日期格式。对于大多数应用程序,GetDateFormat(它允许以当前选定的日历和格式显示日期)提供的基本功能已经足够。但是,一些应用程序可能希望对此信息的显示方式进行更多的控制,因此最终选择了当前显示日期所使用的日历类型。有多个 Win32 NLS API 允许您处理日历类型。

EnumCalendarInfoEx API 可用于枚举与指定区域设置相关的所有适用和可用日历类型的全部日历信息(如日历名称、一周中每一天的名称和月份名称)。下面的代码示例将枚举所有受支持日历的固有名称。

  

// Enumerate the native calendar names for all available calendar
// 与当前用户区域设置相对应的类型。

 

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;
}

针对英语(美国)和阿拉伯语(突尼斯)用户区域设置执行上述代码示例将分别得到以下结果。(请参见下方的图 4)

图 4:针对英语(美国)和阿拉伯语(突尼斯)用户区域设置枚举日历格式的结果

图 4:针对英语(美国)和阿拉伯语(突尼斯)用户区域设置枚举日历格式的结果


带有 LOCALE_ICALENDARTYPE 标记的 GetLocaleInfo API 还允许您检索用户当前选择的默认日历类型。检索到所需的日历之后,即可使用 GetCalendarInfo 来检索有关该特定日历的具体信息。此信息包括以下内容:

  • 长/短年/月份日期格式
  • 月份的缩写和全称
  • 一周中每一天的缩写和全称
  • 一个整数,表示两位数年份范围的上限
  • 日历的固有名称

简言之,Win32 NLS API 允许您为该日历选择给定的日历类型和给定的格式类型,从而为您的应用程序提供对日期显示方式的完全控制。在实际操作中,NLS API 可为您带来空前的灵活性。如前所述,使用 GetDateFormat 即足可以通过可识别区域设置的方式来设置日期格式。

返回页首返回页首

“使用区域设置模型”中,您已经看到了如何在客户端检索当前浏览器区域设置以及如何将您的上下文或会话的全局区域设置设定为此值。完成相应的区域设置后,您即可在 VBScript 脚本中使用 FormatDateTime(一个可识别区域设置的函数)轻松设置日期的格式。假设您检索到西班牙语(墨西哥)作为主浏览器区域设置。("es-MX" 是此区域设置的默认值。)以下代码将保存当前的上下文区域设置(与服务器的用户区域设置相匹配)、将区域设置设定为西班牙语(墨西哥)、用西班牙语(墨西哥)格式来格式化日期以及恢复原始区域设置:

  

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

输出结果将会是:

  

martes, 18 de diciembre de 2001

显然,脚本技术在处理日期和日历时并不像 NLS API 在 Win32 编程中那样灵活。但是,FormatDateTime 函数允许您以长短两种日期格式来显示用户的首选文化中的日期。

返回页首返回页首

.NET Framework 中的日期和日历格式化

在 .NET 环境中设置日期格式的最简单有效的方法是利用 DateTime 结构,利用它提供的方法您可以对 DateTime 执行区分文化的操作。使用 DateTimeFormatInfo 类基于特定于文化的标准来格式化和显示 DateTimeDateTimeFormatInfo 定义如何根据地域设置 DateTime 值的格式并进行显示。例如,使用 ShortDatePattern,日期 April 24, 2001 在 "en-US" 文化中被格式化为 4/24/2001,在 "en-GB" 英语(英国)文化中被格式化为 24/04/2001。

DateTimeFormatInfo 实例可以针对特定文化而不是针对中立文化加以创建。中立文化没有为显示正确的日期格式提供足够的信息。正如您刚刚看到的,虽然英语(美国)和英语(英国)共享相同的中立文化(英语),但其日期格式设置却完全不同。

以下代码示例将在 CurrentThread.CurrentCulture 被依次设置为"en-US" 和 "de-DE"(德语,德国)后使用 DateTimeFormatInfo.ShortDatePattern 属性来显示当前日期。

  

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));
}
}

 

如果您对 April 24, 2001 执行此代码,则输出结果将如下所示:

  

4/24/2001 // 英语(美国)的短日期格式

24.04.2001 // 德语(德国)的短日期格式

下表列出了每种标准格式设置模式的标准格式字符,以及可以设置用来修改标准模式的相关 DateTimeFormatInfo 属性。格式字符是区分大小写的,例如,"g" 和 "G" 所代表的模式略有不同。

表 3:"en-US" 格式模式的 DateTimeFormatInfo 属性、模式和日期格式列表。格式模式会因文化的不同而变化。


在泰国,公历和佛教历同时存在。但是在内部,与 Win32 模式相似,.NET Framework 通过使用数据结构来处理公历日。因此,当您使用由 DateTime 结构提供的方法时,必须要意识到成员(如 DateTime.Day 属性、DateTime.Month 属性、DateTime.Year 属性和 DateTime.AddDays 方法)是基于公历的。即使您在应用程序的代码中更改了当前日历或者通过区域和语言选项控制面板更改了日期和时间设置,仍然是采用公历来执行这些方法的计算。此功能可防止这些方法所执行的运算被用户的设置所破坏。如果您要根据当前日历来执行区分文化的日期和时间操作,则必须使用 DateTimeFormatInfo.Calendar 属性来调用由 Calendar 类提供的方法(如 Calendar.GetDayOfMonthCalendar.GetMonthCalendar.GetYearCalendar.AddDays)。

为处理固有日历类型,.NET Framework 提供了 Calendar 类以及下列 Calendar 实现:GregorianCalendarHebrewCalendarHijriCalendarJapaneseCalendarJulianCalendarKoreanCalendarPersianCalendarTaiwanCalendarThaiBuddhistCalendar 您可以使用的其他内容还包括 CultureInfo 类,它拥有 CultureInfo.Calendar 属性,可用来指定文化的默认日历。CultureInfo.OptionalCalendars 属性可指定某种文化支持的可选日历。

以下 C# 代码示例将为文化 "th-TH"(泰语,泰国)创建 CultureInfo 对象,并显示每个文化的默认和可选日历。通过 GregorianCalendar.CalendarType 属性,GregorianCalendar 被进一步划分为若干子类型。在本例中,每当日历被确定为使用公历时,系统都会检索和显示 CalendarType 值。


 

  

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());

 

// 显示文化的默认日历。
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());
}
}
}

此代码将产生以下输出:

  

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

 

正如您所看到的,.NET Framework 为设置日期和日历格式提供了一个 UI,不但应用范围广,而且还灵活易用。后续部分将概述在 Win32 应用程序、网页和 .NET Framework 中显示时间时应考虑的几点内容。其中包括在小时、分钟和秒之间使用适当的分隔符、构造格式-简写字符串以及显示时区等信息。

返回页首返回页首

引用

请参见以下 MSDN 文档:

 

日历差异时间格式设置

 

返回页首返回页首 上一页第 4 页,共 11 页下一页