Reputation: 381
I have code that converts long numbers to dates.
DateTimeOffset value =
DateTimeOffset.FromUnixTimeSeconds(1597325462);
DateTime showTime = value.DateTime;
string easternZoneId = "America/New_York";
TimeZoneInfo easternZone =
TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
DateTime targetTime =
TimeZoneInfo.ConvertTime(showTime, easternZone);
Console.WriteLine("DateTime is {0}", targetTime);
On my Mac, the output is "DateTime is 8/13/2020 6:31:02 AM"
On my server the output is "DateTime is 8/13/2020 9:31:02 AM"
Identical code on both.
The Linux box value is accurate. How can I get the same result on my Mac?
Upvotes: 2
Views: 1442
Reputation: 241758
The overload of TimeZone.ConvertTime
you're using takes a DateTime
value and a destination TimeZoneInfo
. There's no mention of the source time zone, so it is infered from the .Kind
property of the DateTime
being passed in.
In your case, that is DateTimeKind.Unspecified
, because the .DateTime
property of a DateTimeOffset
always returns unspecified, regardless of what the offset is.
In the ConvertTime
call, if the kind is DateTimeKind.Unspecified
, it is assumed to be local time (as if it were DateTimeKind.Local
). (Scroll down to the Remarks section in the docs here.) Thus, you are converting as if the Unix timestamp were local-time based, rather than the actuality that it is UTC based. You get different results between your workstation and server because they have different system-local time zones - not because they are running different operating systems.
There are a number of different ways to rewrite this to address the problem. I will give you a few to choose from, in order of my preference:
You could leave everything as a DateTimeOffset
throughout the conversion process:
DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
string easternZoneId = "America/New_York";
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
DateTimeOffset targetTime = TimeZoneInfo.ConvertTime(value, easternZone);
You could use the .UtcDateTime
property instead of the .DateTime
property:
DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
DateTime showTime = value.UtcDateTime;
string easternZoneId = "America/New_York";
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
DateTime targetTime = TimeZoneInfo.ConvertTime(showTime, easternZone);
You could use ConvertTimeFromUtc
instead of ConvertTime
:
DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
DateTime showTime = value.DateTime;
string easternZoneId = "America/New_York";
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
DateTime targetTime = TimeZoneInfo.ConvertTimeFromUtc(showTime, easternZone);
You could specify UTC as the source time zone in the ConvertTime
call:
DateTimeOffset value = DateTimeOffset.FromUnixTimeSeconds(1597325462);
DateTime showTime = value.DateTime;
string easternZoneId = "America/New_York";
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
DateTime targetTime = TimeZoneInfo.ConvertTime(showTime, TimeZoneInfo.Utc, easternZone);
There are a few other options, such as explicitly setting the kind, but I think the above gives you enough to go on.
If in doubt, pick the first option. DateTimeOffset
is much easier to rationalize than DateTime
in most cases.
Upvotes: 2
Reputation: 26430
The issue seems to be that there is not such a timezone I'd in the ICU library that both OS look into.
Check the example in the Microsoft docs: https://learn.microsoft.com/en-us/dotnet/api/system.timezoneinfo.converttimebysystemtimezoneid?view=netcore-3.1
DateTime currentTime = DateTime.Now;
Console.WriteLine("New York: {0}",
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(currentTime, TimeZoneInfo.Local.Id, "Eastern Standard Time"));
So it looks like the id you should look for is ""Eastern Standard Time"
If you can't find it then run the following code to check the available timezones on your pc
foreach (TimeZoneInfo z in TimeZoneInfo.GetSystemTimeZones())
Console.WriteLine(z.Id);
The destinationTimeZoneId parameter must correspond exactly to the time zone's identifier in length, but not in case, for a successful match to occur; that is, the comparison of destinationTimeZoneId with time zone identifiers is case-insensitive.
So check the timezones and copy the correct string to use based on what exists on the machine.
Upvotes: 0