How to solve timezone conversion error? - c#

I am trying to convert to a swedish timezone with this code:
Thread.CurrentThread.CurrentCulture = new CultureInfo("sv-SE");
TimeZoneInfo cet = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
DateTime currentDate = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local);
var swedishTime = TimeZoneInfo.ConvertTime(currentDate, cet, TimeZoneInfo.Local);
For some reason I am getting:
{"The conversion could not be completed because the supplied DateTime
did not have the Kind property set correctly. For example, when the
Kind property is DateTimeKind.Local, the source time zone must be
TimeZoneInfo.Local.\r\nParameter name: sourceTimeZone"}
What am i missing?

A few things:
Culture only affects output formatting when converting to/from strings. It doesn't affect time zone conversions, so it is unnecessary here.
The time zone identifiers used by TimeZoneInfo on Windows come from the Windows operating system itself, and sometimes their names do not match up to what you may expect.
You're using the Windows time zone ID "Central European Standard Time", which has a display name of "(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb".
For Sweden, you should actually use the ID "W. Europe Standard Time", which has a display name of "(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"
You can read more about this in the section titled "The Microsoft Windows Time Zone Database" in the timezone tag wiki.
Since it appears you are looking for the current time in a particular time zone, you should not be going through the local time zone at all. Just convert directly from UTC to the target time zone.
The code should simply be:
var tz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
var swedishTime = TimeZoneInfo.ConvertTime(DateTime.UtcNow, tz);
Or if you prefer, you can use a convenience method:
var swedishTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.UtcNow,
"W. Europe Standard Time")

Just delete "TimeZoneInfo.Local" from "var swedishTime".
Thread.CurrentThread.CurrentCulture = new CultureInfo("sv-SE");
TimeZoneInfo cet = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
DateTime currentDate = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Local);
var swedishTime = TimeZoneInfo.ConvertTime(currentDate, cet);

I faced the same issue and I fixed it by changing to DateTimeKind.Unspecified.
Instead of this
var currentDateTime = DateTime.UtcNow;
I put this:
var currentDateTime = new DateTime(DateTime.UtcNow.Ticks, DateTimeKind.Unspecified);

Related

TimeZoneInfo.ConvertTimeFromUTC produce different output then TimeZone.BaseUTCOffset

I have a UTC date-time, I need to convert it to EST time zone. It should be as simple as this
var easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var dt = DateTime.SpecifyKind(value, DateTimeKind.Utc);
return TimeZoneInfo.ConvertTimeFromUtc(dt, easternZone);
So my input date is
02-08-2019 22:53:32
and the result value is
02-08-2019 18:53:32
It deduct 4 hours from given time.
But if I check the Offset between Eastern Standard Time Zone and UTC time zone then the value it return is
easternZone.BaseUtcOffset {-05:00:00} System.TimeSpan
If this is true then above result value should be
02-08-2019 17:53:32
I am not sure what I am missing here.
I am not sure what I am missing here.
BaseUtcOffset does not take into account daylight saving time (it can't, since it doesn't know what specific date you are interested in). You likely want to use GetUtcOffset:
The returned time span includes any differences due to the application
of adjustment rules to the current time zone. It differs from the
BaseUtcOffset property, which returns the difference between
Coordinated Universal Time (UTC) and the time zone's standard time
and, therefore, does not take adjustment rules into account.
Adjustment Rule is discussed here (emphasis mine):
Provides information about a time zone adjustment, such as the
transition to and from daylight saving time.
As a general rule, if dates are ever <= 1 hour out from what you expect, look into daylight savings issues.
To illustrate the impact of daylight saving time:
var timeUtc = Convert.ToDateTime("01-01-2019 22:53:32");
var easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var dt = DateTime.SpecifyKind(timeUtc, DateTimeKind.Utc);
Console.WriteLine(TimeZoneInfo.ConvertTimeFromUtc(dt, easternZone));
Console.WriteLine(easternZone.GetUtcOffset(dt));
timeUtc = Convert.ToDateTime("07-07-2019 22:53:32");
easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
dt = DateTime.SpecifyKind(timeUtc, DateTimeKind.Utc);
Console.WriteLine(TimeZoneInfo.ConvertTimeFromUtc(dt, easternZone));
Console.WriteLine(easternZone.GetUtcOffset(dt));
The above code will output:
1/1/2019 5:53:32 PM
-05:00:00
7/7/2019 6:53:32 PM
-04:00:00
Try This :
var timeUtc = Convert.ToDateTime("02-08-2019 22:53:32");
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime easternTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, easternZone);
Console.WriteLine(easternTime);

How to get the offset when converting time to specific timezone and then UTC? C#

I am trying to convert date to UTC format where I can get correct offset. I am using ToString("O") in simple DateTime.Now which works.
Now when I am converting my current time (EST) to CST (Central) or MST (Mountain) then I am not getting offset. What am I missing here? Is there any other way to do it?
Code:
var currentTimeToUtc = DateTime.Now.ToString("O");
// Output = "2018-12-27T12:31:21.9946661-05:00" --This is perfect.
var centralTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.Now, "Central Standard Time");
var centralTimeToUtc = centralTime.ToString("O");
// Output = "2018-12-27T11:31:19.8046052"
// Expected Output = "2018-12-27T11:31:19.8046052-06:00"
var mountainTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.Now, "Mountain Standard Time");
var mountainTimeToUtc = mountainTime.ToString("O");
// Output = "2018-12-27T10:31:25.2438418"
// Expected Output = "2018-12-27T10:31:25.2438418-07:00"
This is the expected behavior of DateTime. If you need to keep time zone information, use DateTimeOffset instead.
The reason for the difference in the output is that DateTime.Now and centralTime / mountainTime are of different kind: DateTime before conversion is Local, but after conversion it becomes Unspecified.
Run the program below to confirm this:
var now = DateTime.Now;
Console.WriteLine(now.Kind);
var centralTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(now, "Central Standard Time");
Console.WriteLine(centralTime.Kind);
var mountainTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(now, "Mountain Standard Time");
Console.WriteLine(mountainTime.Kind);
The behavior cannot be changed because DateTime does not store offset; it relies on two well-known offsets for interpretation of the time zone - Local means your local time zone, and UTC means UTC time zone.
The third option, Unspecified, means that the value of DateTime cannot be interpreted as an absolute value by itself, because time zone has been stripped from it. Your code knows what time zone it is, because you did the conversion, but the information about the time zone is part of your program's design, not part of the corresponding DateTime object. .NET added DateTimeOffset objects specifically to address this problem.

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

I want to initialize DateTime in EST and then convert to Universal TIme

I want to initialize DateTime in Eastern Standard Time and then convert to universal time.
I have One DateTime (CurrentDT) whose TimeZone is not set, but it is in EST.
it is parsedExact from following sting
"ddd, d MMM yyyy H:mm:ss"
I have written following code to solve the problem.
TimeZoneInfo currentTimeZone=null;
currentTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
CurrentDT=TimeZoneInfo.ConvertTime(CurrentDT, currentTimeZone);
CurrentDT = CurrentDT.ToUniversalTime();
The Problem is that it looks like i am doing wrong. I am converting DateTime,which is in local time zone to Eastern Standerd Time and then to universal standard Time.
I don't know how can i initialize TimeZone of CurrentDt initially.
Kindly help me understand Thankyou.
If I remember well, DateTime doesn't preserve info about TimeZone, but if you know that a certain DateTime is in a specific TimeZone you can get the UTC from it doing something like this:
var UtcDateTime = TimeZoneInfo.ConvertTimeToUtc(CurrentDt, TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")); // 1st param is the date to convert and the second is its TimeZone
In some cases you could use (relatively) new type DateTimeOffset, like here:
var est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var offset = est.GetUtcOffset();
var dataTimeOffset = new DateTimeOffset(dateTimeWithoutOffset, offset);
var result = dateTimeOffset.UtcDateTime;
Since you should work in different time zones, DateTimeOffset can make your code more clear.

How to tell if it's British Summer Time

I have the following code, which should return an offset of 60 (to show that in the UK at present, we are in British Summer Time - ie. 60 minutes ahead of GMT):
var info = TimeZoneInfo.FindSystemTimeZoneById("Greenwich Standard Time");
DateTimeOffset localServerTime = DateTimeOffset.Now;
double off = localServerTime.Offset.TotalMinutes;
return off;
However, it returns 0.
Could anyone please help fix this for me?
Use TimeZoneInfo.IsDaylightSavingTime Method (DateTimeOffset) to find if it is currently Daylight saving for your Timezone.
var info = TimeZoneInfo.FindSystemTimeZoneById("Greenwich Standard Time");
DateTimeOffset localServerTime = DateTimeOffset.Now;
bool isDaylightSaving = info.IsDaylightSavingTime(localServerTime);
There are further examples here
Your machine is not configured correctly if you get 0 and live in the UK. Probable causes are:
The machine's time zone is not set correctly. Click the clock on the taskbar to correct.
The machine is not configured to observe daylight savings. Click the clock.
The database that TimeZoneInfo consults for daylight savings rules in out of date or corrupted. It is stored in the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones registry key.
Be careful about making radical changes, having it configured wrong might well have been done intentionally to work around some kind of flaw in a business-critical app that runs on the server. Talk to whomever administers the server first.
Another option is to use Noda Time.
The following code works with Noda Time 1.4 and higher:
var zone = NodaTime.TimeZones.TzdbDateTimeZoneSource.Default.ForId("Europe/London");
var zonedClock = NodaTime.SystemClock.Instance.InZone(zone);
var zonedDateTime = zonedClock.GetCurrentZonedDateTime();
bool isDST = zonedDateTime.IsDaylightSavingTime();
Console.WriteLine(isDST);
zone is a DateTimeZone object representing the UK's timezone, "Europe/London"
zonedClock is a ZonedClock object which represents, in this case, the system clock and the UK's timezone
zonedDateTime is a ZonedDateTime object representing the current date and time in the timezone ("the current instant provided by the underlying clock, adjusted to the time zone of this object")
isDST is a boolean indicating whether the current instant is in DST or not. At the time of writing (April 2018) this evaluates to true
With earlier versions of Noda where ZonedClock is not available, we can do this instead:
var zone = NodaTime.TimeZones.TzdbDateTimeZoneSource.Default.ForId("Europe/London");
var now = Instant.FromDateTimeOffset(DateTimeOffset.Now);
var zonedDateTime = new ZonedDateTime(now, zone);
bool isDST = zonedDateTime.IsDaylightSavingTime();
To master conversion from one timezone to anther you need to see what's supported (how?) and what's not.
foreach (var tz in TimeZoneInfo.GetSystemTimeZones())
{
Console.WriteLine("TimeZone Offset: {0} Name : {1}, Supports DLS: {2}", tz.BaseUtcOffset,tz.StandardName,tz.SupportsDaylightSavingTime);
}
This should give you the list all timezones including info about DayLightSaving.
Notice that:
TimeZone Offset: 00:00:00 Name : Greenwich Standard Time, Supports DLS: False
TimeZone Offset: 00:00:00 Name : GMT Standard Time, Supports DLS: True
So you need to use "GMT Standard Time" because it supports daylight saving already. No work needs to be done.
Here is sample code:
private static string GetBSTTimeStamp(string timestamp)
{
DateTime dt = DateTime.Parse(timestamp);
//TimeZoneInfo bst = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
//Console.WriteLine("Time zone supports dls? {0}", bst.SupportsDaylightSavingTime);
//Console.WriteLine("Time zone offset? {0}", bst.BaseUtcOffset);
DateTime dateTimeInUtc = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dt, "Eastern Standard Time", "GMT Standard Time");
return dateTimeInUtc.ToString();
}

Categories