TimeZoneInfo.ConvertTimeFromUTC produce different output then TimeZone.BaseUTCOffset - c#

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);

Related

TimeZone.GetUtcOffset() Requires DateTime, but DateTime's Timezone is Ignored, why?

My goal is to get the difference between UTC and another time zone. Take for example the difference between UTC and EST (UTC-5:00). Also for sake of example assume my system is currently in Pacific Standard Time so DateTime.Kind, "LOCAL", is PST. In order to find the difference between UTC and EST I'm forced to provide a DateTime which I'm providing in PST. Here's a simplified snippet of my code:
public static void Run_Timezone_Test()
{
var myDate = DateTime.Now;
Console.WriteLine(myDate.Kind);
//OUTPUT: Local (note this is currently PST)
var easternTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var offset = easternTimeZone.GetUtcOffset(myDate);
Console.WriteLine(offset);
//OUTPUT: -05:00:00 (correct offset for EST)
Console.ReadLine();
}
Why am I forced to provide "myDate" if it and its time zone are not used?
Here's an example of why it matters:
var AUSEast = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
var offset = AUSEast.GetUtcOffset(DateTime.Now);
Console.WriteLine(offset);
offset = AUSEast.GetUtcOffset(DateTime.Now.AddMonths(6));
Console.WriteLine(offset);
At the time of writing, this will output (assuming you have AEST installed as a system time - you can check via TimeZoneInfo.GetSystemTimeZones()):
11:00:00
10:00:00
Note that a time zone does not indicate an offset from UTC by itself. Time anomalies (most commonly daylight savings) will change the UTC offset while still remaining in the same time zone

How to solve timezone conversion error?

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);

How to use Standard Time Only in TimezoneInfo.ConvertTime C#

I am having a Issue with the C# function of TimeZoneInfo.ConvertTime().
What i need to get is the Standard Time not the DST but i'm only getting DST is there a way to Tell the Function to only get the Result in Standard Time.
My local Timezone is UTC -6:00 Central America Standard Time, so if my time is 12:00 PM the Conversion i'm getting is throwing it at 2 PM Eastern Time but i need it to tell me it's 1:00 PM.
public static DateTime TimetoEst( DateTime timenow)
{
var currentTimeZone = TimeZone.CurrentTimeZone.GetUtcOffset(timenow).ToString();
var estzone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var conver = TimeZoneInfo.ConvertTime(timenow, estzone);
return conver;
}
Thanks
A couple of things:
The ID "Eastern Standard Time" represents both EST and EDT, with the appropriate transitions in place. It would more appropriately be called "Eastern Time", but alas this is the identifier and the convention used by Windows time zones.
The Eastern Time zone really does transition in and out of daylight saving time. If you were to always adjust to just Eastern Standard Time (UTC-5), you would be ignoring the reality of timekeeping in that region - that it is in Eastern Daylight Time (UTC-4) for dates in the summer months.
Your code will indeed return EST, but only for date values that are outside of the DST period.
Now, if you still think this is what you want to do - then you can do it without the TimeZoneInfo object at all. Simply adjust the result from the offset that applies to your source value, to the UTC-5 offset that applies to EST.
public static DateTime TimetoEst(DateTime timenow)
{
var dto = new DateTimeOffset(timenow); // will use .Kind to decide the offset
var converted = dto.ToOffset(TimeSpan.FromHours(-5));
return converted.DateTime;
}
This is what you asked, but for the record - I don't think this is the best plan. Besides the issues above - assuming that the input value should be interpreted based on the local time zone is not necessarily a good idea - and unless the input time has a .Kind of DateTimeKind.Utc, it will indeed use the computer's local time zone.
You did label the variable as timenow. If you are just after a DateTime which represents the current time in a fixed offset, then it's much safer just to get it like so:
DateTime dt = DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(-5)).DateTime;
And if you really want the current time in the Eastern Time zone, taking DST into account when appropriate, then:
DateTime dt = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.UtcNow,
"Eastern Standard Time");

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();
}

Is there a generic TimeZoneInfo For Central Europe?

Is there a generic TimeZoneInfo for Central Europe that takes into consideration both CET and CEST into one?
I have an app that is doing the following:
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
DateTimeOffset dto = new DateTimeOffset(someDate, tzi.BaseUtcOffset);
var utcDate = dto.ToUniversalTime().DateTime;
The problem is that this is returning the wrong utcDate because the BaseUtcOffset is +1 instead of +2. It appears that CET has DST as well and depending on the time of the year it is +1 or +2.
Firstly, I'd like to applaud mgnoonan's answer of using Noda Time :) But if you're feeling less adventurous...
You're already using the right time zone - but you shouldn't be using BaseUtcOffset which is documented not to be about DST:
Gets the time difference between the current time zone's standard time and Coordinated Universal Time (UTC).
It can't possibly take DST into consideration when you're not providing it a DateTime to fetch the offset for :)
Assuming someDate is a DateTime, you could use:
DateTimeOffset dto = new DateTimeOffset(someDate, tzi.GetUtcOffset(someDate));
Or just ConvertTimeToUtc:
var utcDate = TimeZoneInfo.ConvertTimeToUtc(someDate, tzi);
Note that you should work out what you want to do if your local time occurs twice due to a DST transition, or doesn't occur at all.
Maybe Noda Time can help you out?

Categories