Converting EST to IST gives error in C# - 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.

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

Getting the Arizona Standard Time in .net

I have an application in which time zones are treated as string, by using the system name so we can make an actual System.TimeZoneInfo object by doing:
var tz = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
Such values are persisted to DB, now we are facing an issue where one such object is requested to be on Arizona Time which is not a standard timezone. From what I have investigated the Arizona Time changes Time Zones due to the fact that it doesn't observes "Day Light Savings".
I am looking for a way to set one value in DB so that there is no need to change it according to day light savings changes.
Is there a way to do this?
Even if I have to change a bit the code to get the TimeZoneInfo object. What really matters to me is a way to determine the actual timezone corresponding to Arizona Time
About Arizona time zones
From timeanddate.com:
There is a common misconception that Arizona is on Pacific Daylight
Time (PDT) during the summer and on Mountain Standard Time (MST)
during the winter. Because MST and PDT have the same UTC offset of
minus 7 hours (UTC-7), Arizona has the same local time as neighboring
states California and Nevada during the summer season. Although the
time is the same, Arizona uses standard time (MST) all year.
“Daylight” time zones, such as MDT, are mostly used for areas that
switch to DST every year
IANA (tz database) time zone database contains two time zones for Arizona:
America/Phoenix (Mountain Standard Time - Arizona, except Navajo), which does not observe daylight saving changes (DST), and
America/Shiprock, which observes DST.
Arizona time zones in .NET
Depending on your users' exact location in Arizona, you should use either America/Phoenix or America/Shiprock time zone, so you will need two values in the database. However, if you try to get time zones with TimeZoneInfo.FindSystemTimeZoneById using tz database names, you will get System.TimeZoneNotFoundException.
In order to get Arizona time zone that does not observe DST (America/Phoenix), you can use:
TimeZoneInfo.FindSystemTimeZoneById("US Mountain Standard Time")
In order to get Arizona time zone that does observe DST (America/Shiprock), you can use:
TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time")
So, you would have both ids in your database, US Mountain Standard Time and Mountain Standard Time, or alternatively some other strings that you would later map to these .NET time zone ids.
Check out NodaTime, it can help you a lot when it comes to dealing with date, time and time zones.
And finally, here is a sample program (with NodaTime) that demonstrates the difference between .NET US Mountain Standard Time (America/Phoenix, Arizona without DST) and Mountain Standard Time (America/Shiprock, Arizona with DST).
using System;
using NodaTime;
using NodaTime.TimeZones;
namespace TimeZoneExample
{
class Program
{
static void Main(string[] args)
{
// Arizona without daylight saving time (TZ: America/Phoenix)
var mstWithoutDstTz = TimeZoneInfo.FindSystemTimeZoneById("US Mountain Standard Time");
// Arizona with daylight saving time (TZ: America/Shiprock)
var mstWithDstTz = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
// NodaTime BclDateTimeZone for Arizona without daylight saving time
var mstWithoutDstNodaTz = BclDateTimeZone.FromTimeZoneInfo(mstWithoutDstTz);
// NodaTime BclDateTimeZone for Arizona with daylight saving time
var mstWithDstNodaTz = BclDateTimeZone.FromTimeZoneInfo(mstWithDstTz);
// January 1, 2017, 15:00, local winter date
var localWinterDate = new LocalDateTime(2017, 01, 01, 15, 00);
// NodaTime ZonedDateTime for Arizona without daylight saving time: January 1, 2017, 15:00
var winterTimeWithoutDst = mstWithoutDstNodaTz.AtStrictly(localWinterDate);
// NodaTime ZonedDateTime for Arizona with daylight saving time: January 1, 2017, 15:00
var winterTimeWithDst = mstWithDstNodaTz.AtStrictly(localWinterDate);
// Both time zones have the same time during winter
Console.WriteLine($"Winter w/o DST: {winterTimeWithoutDst}"); // 2017-01-01T15:00:00 US Mountain Standard Time (-07)
Console.WriteLine($"Winter w/ DST: {winterTimeWithDst}"); // 2017-01-01T15:00:00 Mountain Standard Time (-07)
// add 180 days to get June 30, 2017
var sixMonthsToSummer = Duration.FromTimeSpan(new TimeSpan(180, 0, 0, 0));
// During summer, e.g. on June 30, Arizona without daylight saving time is 1 hour behind.
Console.WriteLine($"Summer w/o DST: {winterTimeWithoutDst + sixMonthsToSummer}"); // 2017-06-30T15:00:00 US Mountain Standard Time (-07)
Console.WriteLine($"Summer w/ DST: {winterTimeWithDst + sixMonthsToSummer}"); // 2017-06-30T16:00:00 Mountain Standard Time (-06)
}
}
}
If I understand your problem correctly, you want to create a custom time zone representing "Arizona Time" which has a constant offset from UTC regardless the date of the year.
If so, you should be able to use the static method
TimeZoneInfo.CreateCustomTimeZone
Just set the TimeSpan to the number of hours from UTC that you need it to be (-7 hours from what I can tell).
https://msdn.microsoft.com/en-us/library/bb309898(v=vs.110).aspx
EDIT: You might also have some success by simply using the named timezone
"US Mountain Standard Time"
which should represent the same.

TimeZoneInfo.ConvertTime from PST to UTC to AEST - off by one hour

I convert a string that represents a time in Pacific Time Zone that I am using to create a DateTime object:
var pacificDateTime = new DateTime(2016, 11, 16, 15, 0, 0) // 11/16/2016 3:00:00 PM
Using that, I create a DateTimeOffset because ultimately it becomes a bit easier to work with.
var pacificTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
var dateTimeNoKind = new DateTime(pacificDateTime.Ticks, DateTimeKind.Unspecified)
var DateTimeOffsetValue = TimeZoneInfo.ConverTimeToUtc(dateTimeNoKind, pacificTimeZoneInfo) // 11/16/2016 11:00:00 PM
So far so good. The difference between UTC and Pacific is that UTC is ahead by 8 hours (the given time is within daylight savings).
Then I want to convert from UTC to AEST—but this is where the problem appears:
var australianEasternTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
TimeZoneInfo.ConvertTime(DateTimeOffsetValue, australianEasternTimeZoneInfo) // 11/17/2016 10:00:00 AM
AEST is ahead of UTC by 10 hours. I had expected the value to be 11/17/2016 09:00:00 AM but instead I am getting an extra hour added to my result.
As a test, when I convert to PST or GMT or EST from the UTC time, they appear to convert back correctly.
I feel like I am missing something obvious or overlooking something simple?
From Wikipedia's Time in Australia article:
Australia has two eastern time zones. In the northeast, UTC+10 applies all year. In the southeast, UTC+10 applies during standard time, and UTC+11 applies during daylight time (aka summer time).
The northeast region (Queensland) uses the IANA time zone identifier "Australia/Brisbane", while the southeast region (New South Wales) uses "Australia/Sydney". These correspond to the Windows time zone identifiers: "E. Australia Standard Time" and "AUS Eastern Standard Time" respectively.
If you are converting for Queensland, use "E. Australia Standard Time".
If you are converting for New South Wales, use "AUS Eastern Standard Time".
As to the confusing nature of these identifiers, see the section about Windows time zones in the timezone tag wiki.
If you want to use the standard IANA identifiers instead, use Noda Time.

DateTime parsing error: The supplied DateTime represents an invalid time

I have one situation where date is "3/13/2016 2:41:00 AM". When I convert date by time-zone, I get an error.
DateTime dt = DateTime.Parse("3/13/2016 2:41:00 AM");
DateTime Date_Time = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dt, "Eastern Standard Time",
"GMT Standard Time");
Response.Write(dt);
after execution, I get this error:
The supplied DateTime represents an invalid time. For example, when
the clock is adjusted forward, any time in the period that is skipped
is invalid. Parameter name: dateTime
Try to check if the time is ambiguous or a valid time. Due to the daylight change the time you mentioned i.e, 2:41:00 AM doesn not exist since the clock was moved 1 hour ahead and hence the date is invalid or ambiguous.
2016 Sun, 13 Mar, 02:00 CST → CDT +1 hour (DST start) UTC-5h
Sun, 6 Nov, 02:00 CDT → CST -1 hour (DST end) UTC-6h
You can also refer to this blog: System.TimeZoneInfo: Working with Ambiguous and Invalid Points in Time
System.TimeZoneInfo (currently available as part of .NET Framework 3.5
Beta 1) contains methods for checking if a DateTime instance
represents an ambiguous or invalid time in a specific time zone. These
methods are particularly useful for validating user-supplied points in
time.
Background Information
Time zones that adjust their time for Daylight Saving Time (in most
cases by moving the clock time back or forward by 1 hour) have gaps
and repeats in the timeline — wherever the clock time was moved
forward or back by the adjustment. Let’s use Pacific Standard Time as
an example. In 2007 Pacific Standard Time (PST) changes to Pacific
Daylight Time (PDT) at 02:00AM (“spring forward”) on the second Sunday
in March and then returns at 02:00AM (“fall back”) on the first Sunday
in November
To check if the time is valid you can use:
TimeZoneInfo.IsInvalidTime
In my case, I was trying to convert a UTC date (thus, it was valid, as UTC dates don't skip any periods of time with DST).
The problem was that I was loading the date from Entity Framework and the DateKind was set to Unspecified. In that case, ConvertTimeBySystemTimeZoneId assumes it is a local time and may find it invalid.
The solution is to properly set the DateKind to UTC before converting:
var date = DateTime.ParseExact("2019-03-31T03:06:55.7856471", "O", CultureInfo.InvariantCulture);
// Here date.Kind == DateTimeKind.Unspecified
date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
// Now date.Kind == DateTimeKind.Utc
// Now the conversion should work
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(date, "Central Standard Time");

how to get current UTC offset of different timezones?

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

Categories

Resources