how to get current UTC offset of different timezones? - c#

Problem:
I Need to execute a task on a server that is on UTC at specific time in different time zones. Say for example I want to execute at 9:00AM Pacific Time, irrespective of Daylight Savings changes.
What do I have?
I checked the enumeration of time zones by doing
var infos = TimeZoneInfo.GetSystemTimeZones();
foreach (var info in infos)
{
Console.WriteLine(info.Id);
}
I could see only "Pacific Standard Time" for the pacific time for example and If I do the following,
TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time").GetUtcOffset(DateTime.UtcNow)
I get -07:00:00 as output but as of now the offset is -08. That means it doesn't consider the daylight changes.
I was planing to to create a DateTime instance based on the offset I get above, which doesn't seem to work as I expected.
Also, I can't use frameworks like NodaTime
Any idea how I can get it working?

You've already got your answer, using TimeZoneInfo.GetUtcOffset and passing a DateTime with DateTimeKind.Utc will work.
I get -07:00:00 as output but as of now the offset is -08. That means it doesn't consider the daylight changes.
Actually, -7 is indeed the current offset, as Pacific time is currently using daylight saving time. In the winter, the offset reverts to -8, which is the standard offset. I think you just have them backwards.
Also, keep in mind that the Id property of a TimeZoneInfo object is the identifier for the entire time zone. Some of them are misleading, like "Pacific Standard Time" - which would make you believe that it only uses Pacific Standard Time (PST), but actually it represents the entire North American Pacific Time zone - including Pacific Standard Time and Pacific Daylight Time. It will switch offsets accordingly at the appropriate transitions.

You are probably looking for something like this:
var chinaTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("China Standard Time"));
var pacificTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
The string passed to FindSystemTimeZoneById is picked form TimeZoneInfo.GetSystemTimeZones()
Update: cleansed the code

Related

Incorrect result when using TimeZoneInfo.ConvertTime() to get a localised datetime

I have a very simple task and TimeZoneInfo.ConvertTime() is giving an incorrect result. I simply want to find the current datetime in the "Cen. Australia Standard Time" zone:
string timeZone = "Cen. Australia Standard Time";
TimeZoneInfo zoneID = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
DateTime nowAtTimeZone = TimeZoneInfo.ConvertTime(DateTime.UtcNow, zoneID);
// result: 24/10/2018 7:43:29 PM
// actual ACST time: 24/10/2018 6:43:29 PM (this is what I want)
// actual ACDT time: 24/10/2018 7:43:29 PM (this is not what I want)
I got the actual ACST time from here: https://www.timeanddate.com/time/zones/acst
And the actual ACDT time from here: https://www.timeanddate.com/time/zones/acdt
Note that replacing TimeZoneInfo.ConvertTime() with TimeZoneInfo.ConvertTimeFromUtc() gives identical results.
Note that the timezone is entered by the customer and this is all the information I have available. They do not record the city.
The result from TimeZoneInfo.ConvertTime() appears to be giving ACDT time, even though I have specified ACST.
The problem could be that TimeZoneInfo.ConvertTime() is applying daylight savings to ACST, when it should not be? If so how can I prevent it from doing that?
Time zones in Australia are complex as they are in many parts if the world. Wikipedia's page on this subject is a good overview.
As you can see, there are two major areas that use Australia Central Standard Time. One uses DST, the other does not.
For .NET on Windows with the TimeZoneInfo class:
Use "Cen. Australia Standard Time" for the ID of the south central Australian time zone that uses daylight saving time. Locations include Adelaide, and others.
Use "AUS Central Standard Time" for the ID of the north central Australian time zone that does not use daylight saving time. Locations include Darwin, and others.
The TimeZoneInfo class is doing the correct thing, based on the time zone it is given.
As far as picking the correct zone, use TimeZoneInfo.GetSystemTimeZones() to return all of the available time zones, the use the Id and DisplayName properties to create a drop-down list. The user should only have to choose from the display names, and you only need to use the ID in your code.
You need to call TimeZoneInfo.ConvertTimeFromUtc(datetime, timezoneInfo). Check this
string timeZone = "Cen. Australia Standard Time";
TimeZoneInfo zoneID = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
DateTime nowAtTimeZone = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, zoneID);

TimeZoneInfo BaseUtcOffset always zero on Windows Embedded 7

I'm trying to get the difference between an application running on Windows Embedded 7 and UTC time. To do that I have the following piece of code:
TimeZoneInfo utcTimeZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTime localTime = DateTime.Now;
DateTime utcTime = TimeZoneInfo.ConvertTime(localTime, TimeZoneInfo.Local, utcTimeZone);
TimeSpan utcOffset = localTime - utcTime;
This runs fine on my own development PC, running Windows 7. However, when I install my application on a device running Windows Embedded 7, no matter what timezone I set it to, when I run my application,
The value for TimeZoneInfo.Local.BaseUtcOffset is always 00:00.
The BaseUtcOffset value in the object returned by TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time") is also 00:00 (though this is to be expected).
The ConvertTime() function above always returns the current time less one hour. (Kind of not surprised since the TimeZoneInfo.Local.SupportsDaylightSavingsTime value is always false.)
Should I be using another way that TimeZoneInfo.Local to get the offset between UTC and the current time zone? I need to include Daylight Savings in this.
A few things:
The time zone with the ID "GMT Standard Time" is not UTC - it's UK Time. Its display name matches "Dublin, Edinburgh, Lisbon, London". It uses UTC+0 in the winter, and UTC+1 in the summer for daylight saving time.
The UTC time zone ID is simply "UTC" - though you'll rarely need that.
If TimeZoneInfo.Local.BaseUtcOffset is zero, then that means the computer's time zone setting is one that has UTC+0 as its standard offset. There are four of those currently defined in Windows. This property does not reflect daylight saving time.
Recognize that offsets will change depending on what time of the year that you are running the code. A time zone is not the same as a time zone offset.
Since you said you got zero in your above code, I'd guess that your local time zone is either the previously mentioned UK Time, or Casablanca, Morocco. This is because you are subtracting a UTC+1 local time with the time from another time zone that is also UTC+1 presently. 1 - 1 = 0
The correct way to do this does not involve subtraction at all. Simply use the GetUtcOffset method:
TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now);
Again, note that this returns the current offset. Running it at different times of the year, or by passing a different value instead of DateTime.Now could return a different result.

Converting EST to IST gives error in C#

I am trying to convert EST( Eastern Standard Time) to IST (Indian Standard Time) but the conversion is showing incorrect results.
Can anyone help me on that??
I searched on net and found that using Noda time we can solve that.
But I want to solve it using conventional DateTime class.
Here is my code and its output:
DateTime time= new DateTime(1899,12,30, 23, 30 ,0); //some random date and 11:30 PM in EST
TimeZoneInfo estZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); // Eastern Time Zone
TimeZoneInfo istZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time"); // Indian Time Zone
DateTime localTime = TimeZoneInfo.ConvertTime(time, estZone, istZone); // result is 10:00 am while it should be 09:00 am.
A few things:
The TimeZoneInfo identifier "Eastern Standard Time" refers to the North American Eastern Time zone, covering both Eastern Standard Time and Eastern Daylight Time. EST is UTC-5, while EDT is UTC-4. In general, you should not infer too much from the names of these identifiers. See more examples in the timezone tag wiki.
The TimeZoneInfo.ConvertTime method will use whichever offset is appropriate for the supplied date and time, correctly taking the daylight saving time rules into account.
The underlying time zone data from Windows does not go back to 1899. There are actually no sources of data that guarantee historical dates from that time period. Even the IANA time zone database used with Noda Time makes an educated guess. See History of DST in the United States.
Windows will just use the earliest data it has, which for this zone uses the daylight saving time rules that were in effect from 1986 to 2007. These are not the current rules, so it would make better sense to use a modern year, such as DateTime.Today.Year.
Even if you supplied a modern year, the correct converted time would indeed be 10:00 for a date in December. If you want 9:00, try a date in the summer.

Does "GMT Standard Time" imply BST?

I am confused by "GMT Standard Time".
I have data which is stored as DATE only, but is actually 6PM BST.
I read it in and add 18 hours. I then try to convert to UTC. My initial understanding is that the conversion would NOT take into account Daylight time (as "GMT Standard Time" and UTC are both WITHOUT daylight time). I thought I would have to test for daylight time on the source and then make an adjustment.
However, ConvertTime appears to know about Daylight time in the source and makes the appropriate change.
That seems odd to me - is this the expected behaviour?
TimeZoneInfo gmtZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
TimeZoneInfo utcZone = TimeZoneInfo.FindSystemTimeZoneById("UTC");
public static CultureInfo ci = CultureInfo.InvariantCulture;
string SomeDT = "27/01/2000"; //First BST day
var sourceDT = DateTime.ParseExact(SomeDT, "dd/MM/yyyy", ci).AddHours(18);
var utcDT = TimeZoneInfo.ConvertTime(sourceDT, gmtZone, utcZone);
// At this point utcDT has already been changed so test below is redundant.
// That Suggest "GMT Standard Time" is actually "Daylight Time" i.e.BST
if (gmtZone.IsDaylightSavingTime(sourceDT))
{
utcDT = utcDT.AddHours(-1);
}
else
{
Console.WriteLine("Not BST");
}
The problem is that the time zone IDs in Windows are confusing. Even though the ID is "GMT Standard Time", the time zone referred to by that ID is really "UK time"... like "Europe/London" in IANA. So yes, it will observe DST.
If you want genuine UTC, just use TimeZoneInfo.Utc.
(Alternatively, use Noda Time or something similar instead, and the more standard IANA time zones...)

Specify a date in another timezone C#

I've got an asp.net application that must run some code every day at a specific time in the Eastern Time Zone (DST aware). So my first thought is, get the eastern time value and convert it to local server time.
So I need something like this:
var eastern = DateTime.Today.AddHours(17); // run at 5pm eastern
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var utc = TimeZoneInfo.ConvertTimeToUtc(eastern, timeZoneInfo);
var local = TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZoneInfo.Local);
But how do I specify that the eastern DateTime object should be in the EST timezone.
Am I approaching this the wrong way?
First, there are several things you have to consider. You have to deal with Daylight Savings Time, which from time to time seems to change (the start and end dates have changed twice in the last 10 years). So in the Northern Hemisphere Winter, Eastern time is -5 GMT (or UTC). But, in the Summer it's -6 GMT or is that -4 GMT, I can never keep it straight (nor should I have to).
There are some DNF library functions to deal with time zone information, however you really need .net 3.5 for the most useful stuff. There's the TimeZoneInfo class in .net 3.5.
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime dt = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.Now,
TimeZoneInfo.IsDaylightSavingsTime(tzi) ?
tzi.DaylightName : tzi.StandardName);
if (dt.Hour == 17)
....
Also, keep in mind that twice every year an hour is lost or gained, so you also have to account for that if, for example, you have a countdown timer you display "time until next processing" or something like that. The fact is, time handling is not as easy as it would seem at first thought, and there are a lot of edge cases.
Seems I was able to answer my own question. Here's the code I'm using to get a next-run DateTime object.
private DateTime GetNextRun()
{
var today = DateTime.Today;
var runTime = new DateTime(today.Year, today.Month, today.Day, 17, 0, 0);
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var offset = timeZoneInfo.GetUtcOffset(runTime);
var dto = new DateTimeOffset(runTime, offset);
if (DateTime.Now > dto.LocalDateTime)
dto = dto.AddDays(1);
return dto.LocalDateTime;
}
Doing all the conversion using DateTimeOffset instead of DateTime proved effective. It even seems to handle Daylight Savings Time correctly.
A DateTime doesn't know about a time zone. Even DateTimeOffset doesn't really know about a time zone - it knows about a UTC instant and an offset from that.
You can write your own struct which does have a TimeZoneInfo and a DateTime, but I'm not sure you need it in this case. Are you just trying to schedule 5pm in Eastern time, or is this actually more general? What are you doing with the DateTime (or whatever) afterwards? Using DateTimeOffset and TimeZoneInfo you can definitely get the UTC instant of the time you're interested in; if you just need to know the time between "now" and then, that's fairly easy.
I feel duty-bound to point out that when Noda Time is production-ready, it would almost certainly be the right answer :)
You could use the DateTime.UtcNow to get UTC central time(which I believe is GMT 0) and from htere on just figure out how many time zones the one you want is and remove/add an hour for each zone.

Categories

Resources