C# Handling Daylight Saving in Time Conversion - c#

I have a date string 2020-11-26T14:24:29-08:00 which is passed to the backend ASP NET MVC application.
I am parsing the date/time string using the below code:
DateTime dateTime = DateTimeOffset.ParseExact("2020-11-26T14:24:29-08:00",
"yyyy'-'MM'-'dd'T'HH':'mm':'sszzz",
CultureInfo.InvariantCulture).DateTime;
This code is giving me time which is 1 hour less than the actual time. This is because of Daylight Savings.
Now, I want to know if daylight saving is active in the timezone or not. So I wrote the below code:
var offset = DateTimeOffset.ParseExact("2020-11-26T14:24:29-08:00",
"yyyy'-'MM'-'dd'T'HH':'mm':'sszzz",
CultureInfo.InvariantCulture);
TimeZoneInfo zone = null;
foreach (TimeZoneInfo z in TimeZoneInfo.GetSystemTimeZones())
{
if(zone.BaseUtcOffset == offset.Offset)
zone = z; // this runs multiple times
}
The above code if condition is hitting multiple times with the following zones satisfying condition.
Yukon Standard Time
Pacific Standard Time (Mexico)
UTC-08
Pacific Standard Time
So, I further narrowed down the code
var offset = DateTimeOffset.ParseExact("2020-11-26T14:24:29-08:00",
"yyyy'-'MM'-'dd'T'HH':'mm':'sszzz",
CultureInfo.InvariantCulture);
TimeZoneInfo zone = null;
foreach (TimeZoneInfo z in TimeZoneInfo.GetSystemTimeZones())
{
if(zone.BaseUtcOffset == offset.Offset && zone.SupportsDaylightSavingTime) // added second condition
zone = z; // this runs multiple times
}
This time I got three:
Yukon Standard Time
Pacific Standard Time (Mexico)
Pacific Standard Time
Is it possible to get the exact timezone? (I know this user is in Pacific Standard Time)
Or is it okay to use any (first one) and add one hour to time to get the correct time?

If that datetime string is all you're able to use, I suspect you have to hope the offset they've given you is in line with their time zones daylight savings time (and so could be different for the same location).
I think more information might be needed before a useful answer can be given. Where is this value coming from, what use is the daylight savings time?

Related

Check a date (datetime) if it is Daylight Saving Time with unknown region - c#

With what I understood from other questions I've used below code for checking a date if it is Daylight saving time and altering as required. I do not know which region would the application be used hence I am using Utc. However it is not working as expected.
DateTime dateValWithOffset = dateVal;
TimeZoneInfo timeZoneInfo = TimeZoneInfo.Utc;
if(timeZoneInfo.IsDaylightSavingTime(dateValWithOffset))
{
dateValWithOffset = dateValWithOffset.AddMinutes(60);
}
Example: for sample date (06-JUL-21 06.16.34.547000000 AM) above code should be showing dateValWithOffset as 07/06/2021 02:16:34.547 AM but it returns 07/06/2021 01:16:34.547 AM . If someone can point out where am I going wrong please.
Datetime values should always be in UTC. To format a datetime in the machine or user's local timezone, you should convert to a DateTimeOffset. Knowing the local time and knowing if that time is in daylight saving time are two different things.
// machine local
var timeZoneInfo = TimeZoneInfo.Local;
// or by name
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(name);
var localTime = new DateTimeOffset(dateVal, timeZoneInfo.GetUtcOffset(dateVal));
var isDst = timeZoneInfo.IsDaylightSavingTime(localTime)
IMHO DateTime is a terrible type, designed before the age of cloud computing. All DateTimeKind values other than Utc encourage programmers to continue to handle dates incorrectly and should be deprecated.
As jason.kaisersmith said in comments, "UTC is universal, so there is no daylight saving."
To elaborate, UTC does not have any daylight saving time. Instead, daylight saving time is observed differently at each time zone across the world. Some time zones don't use it at all. Some time zones start and stop DST at different dates or times than other time zones. There's even one time zone that shifts for DST by 30 minutes instead of the usual 1 hour. Without a time zone reference, the concept of DST is meaningless.
For clarity and reference, here's an overview of anticipated DST dates for 2022 by country, and a detailed list of dates and times for the first half and second half of 2022.

How to get convert server time to local time and deal with daylight saving time

I host my website (asp.net webforms, .Net 4.5, SQL Server 2012) on Godaddy and they (the server) use Mountain Standard Time (-7 compare to UTC time) which is never changed and does not observe daylight saving time.
So if I do
Response.Write("UTC Time: " + DateTime.UtcNow.ToString() + "<br/>");
Response.Write("Server Time: " + DateTime.Now.ToString() + "<br/>");
Response.Write("Server DateTimeOffset: " + DateTimeOffset.Now.ToString() + "<br/>");
It will display this:
UTC Time: 9/18/2015 5:14:09 PM
Server Time: 9/18/2015 10:14:09 AM
Server DateTimeOffset: 9/18/2015 10:14:09 AM -07:00
But my users are located in Atlanta, GA which does observe daylight saving time and according to timeanddate.com they use EDT in the summer and EST in the winter
How do I get correct current time of user? Let say user open my web-application and hit Show my time button, it will display a correct current user's time?
You should never rely on the time zone settings of a server. Therefore DateTime.Now should not be ever used in an ASP.NET application.
There are many other reasons to avoid DateTime.Now. Read:The case against DateTime.Now.
The local time of the server is never guaranteed to be the local time of the user of your website anyway. If it is, it's just coincidental.
The easiest way to get the user's current time in their time zone is via JavaScript:
var now = new Date();
Though this is based on the user's clock, which may or may not be correctly set. To have any guarantees about the time, you'd have to use the UTC time of the server's clock, with the user's time zone applied.
One approach you might consider is to send the UTC time of the server down to the client, then load that into JavaScript in the client to project it to their time zone:
// C#
string serverUtcTime = DateTime.UtcNow.ToString("o"); // "2015-09-18T17:53:15.6988370Z"
// JS
var now = new Date("2015-09-18T17:53:15.6988370Z");
Actually detecting the user's time zone is a hard problem that does not currently have a solution. Some may recommend new Date().getTimezoneOffset(), but that only gives you the current numeric offset, not the time zone. Offsets can change for DST, and many time zones use similar offsets. There are also complications for historical dates near DST transitions that will work against you.
Scripts like jsTimeZoneDetect can guess your IANA time zone ID, such as America/New_York for Eastern time, but they are not 100% accurate. If you need the user's time zone on your server, then ultimately should ask the user for their time zone somewhere in your application.
In .NET, you can use Noda Time to work with IANA time zones. Without Noda Time, .NET has the TimeZoneInfo class, but it can only work with Windows time zones.
If you know for certain that the users are in Atlanta, GA (which is in the US Eastern time zone), then you can do this:
DateTime utc = DateTime.UtcNow;
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime eastern = TimeZoneInfo.ConvertTimeFromUtc(utc, tz);
Or, with Noda Time and IANA time zone IDs:
Instant now = SystemClock.Instance.Now;
DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"];
ZonedDateTime eastern = now.InZone(tz);
You can use TimeZoneInfo.ConvertTime to convert from one time zone to another. However, if you just convert to EST or EDT, it will always display that value. If you want to always display the correct time for the client, you'll need to do something like using Javascript to store the client browser's local time zone in a cookie, then use that value as the time zone to convert to.
It might be a little more streamlined to get UtcTime from the server and convert from that using TimeZoneInfo.ConvertTimeFromUtc, if you expect to do much of this. Basically the same process, though.
Take a look at this example. This is quite easy.
[Test, TestCase(1), TestCase(9)]
public void Test(int month)
{
var serverTime = new DateTime(2015, month, 18, 10, 14, 09);
// No Daylight saving in Russia
var serverTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
// Daylight saving in Atlanta
var localTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Atlantic Standard Time");
// check if ConvertTime take care of daylight saving
var localTime = TimeZoneInfo.ConvertTime(serverTime, serverTimeZone, localTimeZone);
// it does
if (localTimeZone.IsDaylightSavingTime(localTime))
Assert.AreEqual(string.Format("{0}/18/15 04:14 AM", month), localTime.ToString("M/dd/yy hh:mm tt", System.Globalization.CultureInfo.InvariantCulture));
else
Assert.AreEqual(string.Format("{0}/18/15 03:14 AM", month), localTime.ToString("M/dd/yy hh:mm tt", System.Globalization.CultureInfo.InvariantCulture));
}

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

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

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