System.TimeZoneInfo.Local.Id returns "Local" instead of proper IANA ID on Debian and Ubuntu. This appears to be due to TimeZoneInfo.cs:TryGetNameFromPath being coded to only work with symbolic links regarding /etc/localtime. On Linux distros based on Debian, /etc/localtime is not a symbolic link but rather is a full copy of one of the particular files in /usr/share/zoneinfo. This causes Mono to fail to identify the system's configured timezone.
brandon@UbuntuServer:~$ mono -V
Mono JIT compiler version 22.214.171.124 (2017-02/5077205 Thu May 25 09:19:30 UTC 2017)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
LLVM: supported, not enabled.
GC: sgen (concurrent by default)
brandon@UbuntuServer:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.5 LTS
csharp> System.TimeZoneInfo.Local.Id "Local"
What is expected is something like "US/Central" -- whatever the system is actually using. In particular, it should match the content of the /etc/timezone file.
Perhaps the Mono code in TimeZoneInfo.cs:CreateLocal() could probe /etc/timezone after the "TZ" environment variable probe, and before the /etc/localtime lookup logic.
A common manifestation of this bug is when attempting to use the popular NodaTime library on Mono on Debian-based distros. Specifically, when attempting to call `NodaTime.DateTimeZoneProviders.Tzdb.GetSystemDefault()`
If it's any help to others coming across this bug, I've devised the following workaround:
/// OS file where the IANA timezone ID is stored.
protected const string TimezoneFilePath = "/etc/timezone";
/// Environment variable that Mono will use for the IANA timezone ID.
protected const string MonoTimezoneEnvironmentVariableKey = "TZ";
/// Workaround/fix for Mono bug where it cannot determine the IANA timezone if /etc/localtime is a copy rather
/// than a link to a zoneinfo file in /usr/share/zoneinfo. Some distros use a symbolic link, and Mono works with
/// that. Others such as Debian based distros use a file copy, and Mono does *not* work there.
/// In the latter case `System.TimeZoneInfo.Local` will contain "Local" for the Id.
var timezoneLines = File.ReadAllLines(TimezoneFilePath);
if (timezoneLines.Length < 1) return;
string timezoneId = timezoneLines;
if (string.IsNullOrWhiteSpace(timezoneId)) return;
// Force Mono to reload it's internal tzinfo