C# – TimeZoneInfo with current UTC offset

TimeZoneInfo always shows the base UTC offset. This can be confusing because the UTC offset can change based on the date (due to daylight savings rules). Here’s an example showing DateTimeOffset and TimeZoneInfo with different offsets:

  • DateTimeOffset.Now -> “6/27/2022 4:40:00 PM -04:00
  • TimeZoneInfo.Local.DisplayName -> “(UTC-05:00) Eastern Time (US & Canada)”

You can get a date’s UTC offset from DateTimeOffset and combine it with TimeZoneInfo.DisplayName. This approach is implemented in the following TimeZoneInfo extension method:

public static class TimeZoneInfoExtensions
{
	public static string GetDisplayNameWithCurrentOffset(this TimeZoneInfo timezone, DateTimeOffset date)
	{
		if (!timezone.SupportsDaylightSavingTime)
			return timezone.DisplayName;

		//Example: Removes (UTC-04:00)
		var displayNameWithoutOffset = timezone.DisplayName.Remove(0, 11);

		var currentOffset = TimeZoneInfo.ConvertTime(date, timezone).Offset;
		var currentOffsetHHMM = currentOffset.ToString("hh\\:mm");

		if (currentOffset < TimeSpan.Zero)
		{
			return $"(UTC-{currentOffsetHHMM}){displayNameWithoutOffset}";
		}
		else
		{
			return $"(UTC+{currentOffsetHHMM}){displayNameWithoutOffset}";
		}
	}
}
Code language: C# (cs)

Here’s an example of using this extension method to get the local time zone with the UTC offset from today’s date (DateTimeOffset.Now):

var defaultDisplayName = TimeZoneInfo.Local.DisplayName;
Console.WriteLine($"Display Name (base offset): {defaultDisplayName}");

var localNow = DateTimeOffset.Now;
var displayNameWithCurrentOffset = TimeZoneInfo.Local.GetDisplayNameWithCurrentOffset(localNow);
Console.WriteLine($"Display Name (current offset): {displayNameWithCurrentOffset}");
Code language: C# (cs)

This outputs the following:

Display Name (base offset): (UTC-05:00) Eastern Time (US & Canada)
Display Name (current offset): (UTC-04:00) Eastern Time (US & Canada)Code language: plaintext (plaintext)

I’ll show a few more examples of using this extension method.

Get all system time zones and display them with current UTC offsets

In this example, it’s getting all the system time zones with their current UTC offsets:

var localNow = DateTimeOffset.Now;

foreach (var timeZone in TimeZoneInfo.GetSystemTimeZones())
{
	var defaultDisplayName = timeZone.DisplayName;
	Console.WriteLine($"Display Name (base offset): {defaultDisplayName}");

	var displayNameWithCurrentOffset = timeZone.GetDisplayNameWithCurrentOffset(localNow);
	Console.WriteLine($"Display Name (current offset): {displayNameWithCurrentOffset}");
}
Code language: C# (cs)

Note: You can use this as a starting point for generating time zone lists to show to the user.

Here’s a small snippet of the output:

...
Display Name (base offset): (UTC-05:00) Eastern Time (US & Canada)
Display Name (current offset): (UTC-04:00) Eastern Time (US & Canada)
...
Display Name (base offset): (UTC+08:00) Perth
Display Name (current offset): (UTC+08:00) Perth
...Code language: plaintext (plaintext)

Get a time zone by ID and display it with the current UTC offset

Here’s an example of looking up a time zone by its ID and then getting its current UTC offset:

var pacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");

var defaultDisplayName = pacificTimeZone.DisplayName;
Console.WriteLine($"Display Name (base offset): {defaultDisplayName}");


var displayNameWithCurrentOffset = pacificTimeZone.GetDisplayNameWithCurrentOffset(DateTimeOffset.Now);
Console.WriteLine($"Display Name (current offset): {displayNameWithCurrentOffset}");
Code language: C# (cs)

This outputs the following:

Display Name (base offset): (UTC-08:00) Pacific Time (US & Canada)
Display Name (current offset): (UTC-07:00) Pacific Time (US & Canada)Code language: plaintext (plaintext)

Leave a Comment