C# TimeZoneInfo.ConvertTime incorrect result - c#

I'm trying to convert time between two timezones, and found out an hour difference between US Eastern Standard Time to Western European Time
Supposedly, USA Eastern Standard Time (EST) 2018 Jun-18 1PM should be Western European Time (WET) same day 6PM, but the result from c# ConvertTime is 7PM, I think I missed something for the daylight setting?
Anyway, here's the code:
var str = "2018-07-09T13:00:00";
var dt = Convert.ToDateTime(str);
var SourceZoneValue = "Eastern Standard Time";
var DestinationZoneValue = "W. Europe Standard Time";
TimeZoneInfo sourceTimeZone = TimeZoneInfo.FindSystemTimeZoneById(SourceZoneValue);
TimeZoneInfo destinationTimeZone = TimeZoneInfo.FindSystemTimeZoneById(DestinationZoneValue);
DateTime localTime = TimeZoneInfo.ConvertTime(dt, sourceTimeZone, destinationTimeZone);
Console.WriteLine(localTime);
The outcome is 7PM instead 6PM, any idea? tks

You want to convert from Eastern Standard Time to W. Europe Standard Time, say from New York to Amsterdam.
New York time zone is -5 GMT, and Amsterdam time zone is +1 GMT:
New York Daylight saving started 11 March 2018 and will end on 4 November 2018.
Amsterdam Daylight saving started 25 March 2018 and will end on 28 October 2018.
Your date is 18 June, so daylight saving does not affect the time difference, I would say 7 PM is the correct result.
Maybe W. Europe Standard Time is not the correct time zone that you are looking for? For example, for the UK time:
var britishZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");

Related

TimeZoneInfo.ConvertTimeFromUtc is returning the wrong value

I'm taking a set date/time value and converting from UTC, but timezone. I'm expecting to get the original time - 5 to be the correct time in the EST time zone, but it is off by 1 hour and only offset it by 4 hours.
string dateString = "3/15/2021 6:59 AM";
DateTime TimeDataDue = DateTime.Parse(dateString, System.Globalization.CultureInfo.InvariantCulture);
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var TimeDataDueEastern = TimeZoneInfo.ConvertTimeFromUtc(TimeDataDue, easternZone).Dump();
The output I get is "3/15/2021 2:59:00 AM", but I expect to get "3/15/2021 1:59:00 AM"
Any suggestions?
Thanks!
As Yarik said in the question comments, the result you obtained is correct.
You can review the 2021 DST schedule for the US Eastern Time zone here:
https://www.timeanddate.com/time/zone/usa/new-york?year=2021
Additionally, you'll note that easternZone.DisplayName in your code will be "(UTC-05:00) Eastern Time (US & Canada)" (assuming English). In other words, despite the time zone having the word "Standard" in its Id, it applies for the entire year including both EST and EDT periods.
Since EDT is in effect on March 15th 2021, you get a result that is four hours behind UTC.

How to convert UTC to Australian Eastern Daylight Time (AEDT)? [duplicate]

This question already has an answer here:
TimeZoneInfo.ConvertTime from PST to UTC to AEST - off by one hour
(1 answer)
Closed 4 years ago.
We are downloading data from our trading partner's API. Till now we were working with "E. Australia Standard Time" and it was working fine.
After daylight saving started our trading partner said that they are working with "Australian Eastern Daylight Time (AEDT)".
I have used following code to convert from UTC to "E. Australia Standard Time".
DateTime utcTime = DateTime.UtcNow;
TimeZoneInfo objTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("E. Australia Standard Time");
DateTime TPDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, objTimeZoneInfo);
But I am getting following errors when I use "E. Australia Daylight Time" or "Australian Eastern Daylight Time (AEDT)"
The time zone ID 'E. Australia Daylight Time' was not found on the local computer.
The time zone ID 'Australian Eastern Daylight Time (AEDT)' was not found on the local computer.
What timezone id should I pass to FindSystemTimeZoneById() method to convert correctly to Australian Eastern Daylight Time (AEDT)?
You probably want to use "AUS Eastern Standard Time" (for Canberra, Hobart, Melbourne and Sydney). Despite having the word "Standard" in the name, this accounts for daylight savings time and uses UTC+10 in winter and UTC+11 in summer:
var tz = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
TimeZoneInfo.ConvertTimeFromUtc(new DateTime(2018,1,1,0,0,0,DateTimeKind.Utc), tz);
// => 01/01/2018 11:00:00
TimeZoneInfo.ConvertTimeFromUtc(new DateTime(2018,7,1,0,0,0,DateTimeKind.Utc), tz);
// => 01/07/2018 10:00:00
The "E. Australia Standard Time" time zone is for Brisbane, where they do not observe daylight savings time.
You can get a complete list of available time zones using the TimeZoneInfo.GetSystemTimeZones() method, or by running tzutil /l at the command line.

Get Datetime Offset for Timezone

I have a code where I need to find current offset from UTC for Central European Timezone.
My code is deployed in azure app service.
var offset = DateTimeOffset.Now.Offset.Hours + ":" +
DateTimeOffset.Now.Offset.Minutes;
The problem with above code is, it relies on server time, Even though my App Service is in West Europe, the time zone of Azure App Service is always UTC .
One solution is to change Azure App Service TimeZone to Desired TimeZone and it will work, but i am also looking at getting the offset using code.
Remember I cannot use system datetime to get offset as it's always UTC.
Can I get Current Central Europe DatetimeOffset irrespective of system date time?
You can do something like this
TimeZoneInfo cet = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
DateTimeOffset offset = TimeZoneInfo.ConvertTime(DateTime.Now, cet);
As described here.
If you're not sure about a TimeZoneId you can use GetSystemTimeZones() to find it.
An alternative, as described here, would be to do something like this
DateTime nowCet = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.Now,
"Central European Standard Time");
The nice thing about this is you can easily calculate the difference between two time zones like, for example
DateTime newYork = new DateTime(2017, 10, 04, 12, 23, 00);
DateTime berlin = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(newYork,
"Eastern Standard Time", "Central European Standard Time");
TimeSpan diff = berlin - newYork;
You can use TimeZoneInfo:
TimeZoneInfo cetInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time");
DateTimeOffset cetTime = TimeZoneInfo.ConvertTime(DateTimeOffset.Now, cetInfo);
With correct daylight saving offsets (example in CET):
DateTime utcDT = DateTime.UtcNow;
DateTime cetDT = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(utcDT, "UTC", "Central European Standard Time");
DateTimeOffset utcDTO = new DateTimeOffset(utcDT);
DateTimeOffset cetDTO = new DateTimeOffset(cetDT, cetDT - utcDT);
// Result (with daylight saving)
//
// 2021. 06. 24. 7:42:09
// 2021. 06. 24. 9:42:09
// 2021. 06. 24. 7:42:09 +00:00
// 2021. 06. 24. 9:42:09 +02:00

Noda Time Instant to CET

I'm using the Noda Time libarary (v 2.0.3) for date time handling in a .net core project. However; I'm having some issues converting an instant to a CET date-time.
I'm fairly new to Noda Time, possibly using it wrong (is not CET tz-db entry referring to CET at all)?
Example code
// get current system instant
var systemInstant = SystemClock.Instance.GetCurrentInstant();
// get oslo zoneddatetime from instant
var osloDateTime = systemInstant.InZone(DateTimeZoneProviders.Tzdb["Europe/Oslo"]);
// get CET(?) zoneddatetime from instant
var cetDateTime = systemInstant.InZone(DateTimeZoneProviders.Tzdb["CET"]);
// output
Debug.WriteLine(osloDateTime.ToString());
Debug.WriteLine(cetDateTime.ToString());
The output from the example code above gives me:
2017-06-16T22:28:16 Europe/Oslo (+02)
2017-06-16T22:28:16 CET (+02)
Acutally I was expecting the CET zoned time to be 21:28:16 (UTC+1) and not 22:28:16 (UTC+2). UTC+1 is also what the Time and date website displaying.
The Zone line of the europe file in the IANA time zone database contains this single line for the CET zone ID:
Zone CET 1:00 C-Eur CE%sT
Then the end recurrence of the C-Eur rule is this pair of lines:
Rule C-Eur 1981 max - Mar lastSun 2:00s 1:00 S
Rule C-Eur 1996 max - Oct lastSun 2:00s 0 -
So it goes into UTC+2 at 2am on the last Sunday of March each year, and back to UTC+1 at 2am on the last Sunday of October each year.
Note that the "abbreviation" in the CET time zone will vary between "CET" and "CEST" - and that may be what's misleading you. But Noda Time is following the definition of the ID "CET" as per the IANA database.
This is just another reason to avoid using the abbreviations, and instead to use full zone IDs such as Europe/Oslo which are unambiguous. I would suggest avoid trying to use the concept of "a CET date-time" entirely.
If you look at the result of DateTimeZoneProviders.Tzdb["CET"], it has a minimum offset of +1 and a maximum offset of +2, so I think it is refering to the actual central European timezone (including the Central European Summer Time [CEST]).
As the date you selected falls into the summer time range, it is UTC+2.
If you try the following you get UTC+1 for CET:
Instant.FromDateTimeUtc(new DateTime(2017, 01, 01, 12, 0, 0, DateTimeKind.Utc)).InZone(DateTimeZoneProviders.Tzdb["CET"]

.ToUniversalTime() Is Incorrect?

DateTime dt = new DateTime(1972, 4, 24, 0, 0, 0);
Response.Write("dt: " + dt.ToString("M/d/yyyy h:mm:ss tt") + "<br />");
Response.Write("dt.Kind: " + dt.Kind.ToString() + "<br />");
Response.Write("dt.ToUniversalTime(): " + dt.ToUniversalTime().ToString("M/d/yyyy h:mm:ss tt") + "<br />");
displays
dt: 4/24/1972 12:00:00 AM
dt.Kind: Unspecified
dt.ToUniversalTime(): 4/24/1972 7:00:00 AM
which is incorrect. April 24, 1972 at 12 PM Pacific is actually April 24, 1972 at 8 AM UTC.
I have confirmed the correct UTC conversion with iOS's internal UTC date conversation and www.timeanddate.com and the UTC time should be 8 AM. Am I doing something wrong?
The server is running in "Pacific Time" timezone so ToUniversalTime should be converting from Pacific timezone to UTC since Unspecified is treated like Local.
If you're on a machine that's not on Pacific Standard Time, you can see this behavior using the following code:
DateTime dt = new DateTime(1972, 4, 24, 0, 0, 0);
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
Console.WriteLine (TimeZoneInfo.ConvertTimeToUtc(dt, tz));
// 4/24/1972 7:00:00 AM
If you look at navy.mil's history of daylight saving time, you'll notice the following paragraph:
The Uniform Time Act of 1966 provided standardization in the dates of
beginning and end of daylight time in the U.S. but allowed for local
exemptions from its observance. The act provided that daylight time
begin on the last Sunday in April and end on the last Sunday in
October, with the changeover to occur at 2 a.m. local time.
And then a little later on:
In 1986, a law was passed that shifted the starting date of daylight
time to the first Sunday in April, beginning in 1987
So the DST switchover wasn't the first Sunday in April until 1987, but for some reason .NET is acting as if it was.
Timeanddate.com's history of DST seems to agree, and lists April 30, 1972 (the last Sunday in April) as the date clocks were turned forward one hour (to UTC-7).
Microsoft's DST adjustment rules for times before 1987 appear to be wrong (and I'm not the only one who thinks so).
Here's what TimeZoneInfo lists as the rules for PST:
Basically, Microsoft has ignored the historical rules and chosen to use rules put into effect in 1987 for dates that happened before those rules even existed.
Essentially your date (in 1972) is being handled incorrectly by Microsoft's TimeZoneInfo adjustment rules.
If you're looking for a library that handles these types of time zone rules much better, check out NodaTime, which handles this particular case correctly:
var pacific = DateTimeZoneProviders.Tzdb["America/Los_Angeles"];
LocalDateTime localDateTime = new LocalDateTime(1972, 4, 24, 0, 0);
ZonedDateTime zonedDateTime = pacific.AtStrictly(localDateTime);
DateTime utcDateTime = zonedDateTime.ToDateTimeUtc();
Console.WriteLine(utcDateTime);
// 4/24/1972 8:00:00 AM

Categories