我遇到了与 .NET 时区 ID 与 XenApp 结合使用相关的问题,可以简化为以下抛出TimeZoneNotFoundException
的代码片段(即调用 TimeZoneInfo.FindSystemTimeZoneById
):
var tzLocal = TimeZoneInfo.Local;
var tzId = tzLocal.Id;
var tz = TimeZoneInfo.FindSystemTimeZoneById(tzId);
确切的异常文本是:
System.TimeZoneNotFoundException:
The time zone ID 'Mitteleuropäische Zeit' was not found on the local computer.
at System.TimeZoneInfo.GetTimeZone(String id)
at System.TimeZoneInfo.FindSystemTimeZoneById(String id)
(在NodaTime 1.1中也发生了类似的事情,例如在调用NodaTime.DateTimeZoneProviders.Bcl.GetSystemDefault()
中)。
奇怪的是,TimeZoneInfo.Local.Id
似乎返回时区的德语名称,尽管服务器正在运行的语言设置为英语,并且时区 ID 应该是语言中立的(请参阅 .Net 时区信息 ID - 它是特定于 Windows 语言的吗?)。但是客户的语言是德语...(更新/澄清:如果客户端和服务器使用相同的语言,则不会出现此问题。
我认为这里发生的事情是:
- .NET 调用 kernel32 中的
GetTimeZoneInformation
.dll以检索本地时区。 - API 调用会被 XenApp 截获(请参阅是否可以获取 Citrix XenApp 托管的应用程序的用户时区?),因为可以将 XenApp 配置为使用客户端的本地时区(请参阅 http://mdaslam.wordpress.com/2010/01/05/xenapp-time-zone-setting/)。
- 生成的
TIME_ZONE_INFORMATION
结构包含一个德语标准名称(我在英语 XenApp 服务器上使用 p/invoke 检查了这一点)。 - 由于
TIME_ZONE_INFORMATION
结构(请参阅 http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx)不包含中性语言时区标识符,因此 .NET 无法将返回的德语时区标识符与其本地时区"数据库"(带有英文名称)匹配,并使用(本地化的)标准名称作为时区的回退标识符。因此,TimeZoneInfo.Local.Id
包含"本地"时区的德语名称。 - 然后
TimeZoneInfo.FindSystemTimeZoneById
此回退标识符失败,因为系统确实不知道它(因为它是具有不同语言的系统的本地化标准名称)。
那么,除了告诉客户在 XenApp 中禁用客户端时区的使用之外,我该如何解决此问题呢?
一个猜测,但当 XenApp 映射客户端时区时,它很可能使用的是 Win32 API 中的GetTimeZoneInformation
函数。 这将返回一个TIME_ZONE_INFORMATION
结构,其中不包括时区的 id。 它仅返回有关时区的信息,例如偏差和当前 DST 信息,以及本地化名称。
它可能应该使用 GetDynamicTimeZoneInformation
,它返回一个DYNAMIC_TIME_ZONE_INFORMATION
结构。 其中一个元素是 TimeZoneKeyName
,它将映射回 。NET的TimeZoneInfo.Id
没有本地化。
现在我对 XenApp 知之甚少,但 Citrix 完全有可能已经意识到这个问题,并且已经在最新版本中修复了它或正在处理它。 如果可能的话,你应该更新到最新版本,如果它仍然坏了,那么去看看它是否列在他们的错误跟踪器中。 如果没有,请报告并参考这篇文章。