UPDATED ANSWER
My original response is below, and is still valid. However there is now an easier way, using the TimeZoneNames library. After installing from Nuget, you can do the following:
string tzid = theTimeZoneInfo.Id;
string lang = CultureInfo.CurrentCulture.Name;
var abbreviations = TZNames.GetAbbreviationsForTimeZone(tzid, lang);
The resulting object will have the properties similar to:
abbreviations.Generic == "ET"
abbreviations.Standard == "EST"
abbreviations.Daylight == "EDT"
You can also use this same library to get the fully localized names of the time zones. The library uses an embedded self-contained copy of the CLDR data.
ORIGINAL ANSWER
As others mentioned, Time zones abbreviations are ambiguous. But if you really want one for display, you need an IANA/Olson time zone database.
You can go from a Windows time zone to an IANA/Olson time zone and the other direction as well. But be aware that there could be multiple IANA/Olson zones for any given Windows zone. These mappings are maintained in the CLDR here.
NodaTime has both the database and the mappings. You can go from a .Net DateTime
or DateTimeOffset
with a TimeZoneInfo
, to a NodaTime Instant
and DateTimeZone
. From there, you can get the abbreviation name.
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
var dateTime = DateTime.UtcNow;
var instant = Instant.FromDateTimeUtc(dateTime);
var tzdbSource = TzdbDateTimeZoneSource.Default;
var tzid = tzdbSource.MapTimeZoneId(timeZoneInfo);
var dateTimeZone = DateTimeZoneProviders.Tzdb[tzid];
var zoneInterval = dateTimeZone.GetZoneInterval(instant);
var abbreviation = zoneInterval.Name;
Debug.WriteLine(abbreviation);