This is a little code sample to illustrate the issue:
enter code here
var offset1 = DateTimeZoneProviders.Tzdb.GetZoneOrNull("Europe/Moscow")
.GetUtcOffset(Instant.FromDateTimeUtc(DateTime.UtcNow));
var offset2 = DateTimeZoneProviders.Tzdb.GetZoneOrNull("Etc/GMT+3")
.GetUtcOffset(Instant.FromDateTimeUtc(DateTime.UtcNow));
Console.WriteLine(offset1 + " vs " + offset2);
Results in "{+03} vs {-03}"
Yes, that's correct. That's because the "Etc/GMT+X" zone IDs are confusing. They match POSIX TZ strings, which for some reason represent "the offset of UTC from local time" instead of the normal "offset of local time from UTC". See the Wikipedia list of tz database time zone for confirmation of that.
From the etcetra
file:
# Be consistent with POSIX TZ settings in the Zone names,
# even though this is the opposite of what many people expect.
# POSIX has positive signs west of Greenwich, but many people expect
# positive signs east of Greenwich. For example, TZ='Etc/GMT+4' uses
# the abbreviation "-04" and corresponds to 4 hours behind UT
# (i.e. west of Greenwich) even though many people would expect it to
# mean 4 hours ahead of UT (i.e. east of Greenwich).
If you want to create a time zone representing a fixed offset, you can either use an identifier of "UTC+X" or use DateTimeZone.ForOffset
.
See more on this question at Stackoverflow