2

I ran into a problem related to .NET timezone IDs in combination with XenApp, which can be reduced to the following snippet throwing a TimeZoneNotFoundException (i.e. the call to TimeZoneInfo.FindSystemTimeZoneById):

var tzLocal = TimeZoneInfo.Local;
var tzId = tzLocal.Id;
var tz = TimeZoneInfo.FindSystemTimeZoneById(tzId);

The exact exception text is:

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)

(Something similar happens in NodaTime 1.1, e.g. inside the call to NodaTime.DateTimeZoneProviders.Bcl.GetSystemDefault()).

The strange thing is that TimeZoneInfo.Local.Id seems to return the German name of the timezone, although the server is running with the language set to English and the timezone id should be language-neutral (see .Net TimeZoneInfo ID - Is it Windows Language Specific?). But the client's language is German... (Update/Clarification: the problem will not occur if client and server use the same language.)

What I think is going on here is:

  1. .NET calls GetTimeZoneInformation in kernel32.dll in order to retrieve the local timezone.
  2. The API call gets intercepted by XenApp (see Is it possible to get a users timezone for an application hosted by Citrix XenApp?) because XenApp can be configured to use the client's local timezone (see http://mdaslam.wordpress.com/2010/01/05/xenapp-time-zone-setting/).
  3. The resulting TIME_ZONE_INFORMATION structure contains a German standard name (I checked this with p/invoke on the English XenApp server).
  4. Since the TIME_ZONE_INFORMATION structure (see http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx) does not contain a language-neutral timezone identifier .NET fails to match the returned German timezone identifier to its local timezone "database" (with English names) and uses the (localized) standard name as a fallback identifier for the timezone. Ergo the TimeZoneInfo.Local.Id contains the German name of the "local" timezone.
  5. Then TimeZoneInfo.FindSystemTimeZoneById fails for this fallback identifier because it really is unknown to the system (because it is the localized standard name from a system with a different language).

So how can I work around this issue besides telling the customer to disable the usage of the client's timezone in XenApp?

Community
  • 1
  • 1
Chaquotay
  • 2,212
  • 1
  • 17
  • 22
  • Have you considered mapping the German timezone names to English in your code? Those names aren't likely to change so it shouldn't be a maintenance issue. – acfrancis Nov 13 '13 at 11:07
  • Mapping those localized names to language-neutral ids in our code should work, but I don't like it, because we would have to update this mapping every time we are dealing with a new language, and because this problem also occurs in 3rd party code like NodaTime (which we could fix as well since it is open-source...). – Chaquotay Nov 13 '13 at 13:15
  • This is very odd. The `Id` property should *not* be a localized one. I've never heard of XenApp, but it sounds like it's messing this up. – Jon Skeet Nov 16 '13 at 10:27
  • 1
    @JonSkeet We switched from `DateTimeZoneProviders.Bcl.GetSystemDefault()` to `BclDateTimeZone.ForSystemDefault()`, which seems to work in all situations. But still a strange behaviour... – Chaquotay Mar 05 '14 at 21:08
  • @Chaquotay: Definitely very odd... that suggests that the time zone ID given by `TimeZoneInfo.Local.Id` can't then be looked up using `TimeZoneInfo.FindSystemTimeZoneById`, if I remember the code correctly... – Jon Skeet Mar 05 '14 at 21:25
  • @JonSkeet Yes, the look-up in `TimeZoneInfo.FindSystemTimeZoneById` seems to be the core of the problem, see also the first code snippet in my question. – Chaquotay Mar 05 '14 at 21:33

1 Answers1

1

This is just a guess, but it's likely that when XenApp maps the client time zone, it is using the GetTimeZoneInformation function from the Win32 API. This returns a TIME_ZONE_INFORMATION structure, which does not include the id of the time zone. It only returns the information about the time zone, such as the bias and current DST info, along with the localized names.

It should probably instead be using GetDynamicTimeZoneInformation, which returns a DYNAMIC_TIME_ZONE_INFORMATION structure. One of the elements of which is the TimeZoneKeyName, which would map back to .NET's TimeZoneInfo.Id without being localized.

Now I know very little about XenApp, but it's entirely possible that Citrix is already aware of this problem and either has fixed it in the latest version or is working on it. You should update to the latest version if possible, and if it is still broken then go see if it's listed in their bug tracker. If not, then please report it and reference this post.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • AFAIK the customer is already using the latest XenApp version and we have a workaround (switching to `BclDateTimeZone.ForSystemDefault()` in NodaTime), so as far as my management is concerned this issue is resolved and we won't investigate this issue any further :-/ – Chaquotay Mar 05 '14 at 21:26