Does ConvertTimeFromUtc() and ToUniversalTime() handle DST? - c#

If daylight saving time is in effect, and a date object has been saved into the database (UTC format) which you retrieve to show it in the view (for example the view in asp.net-mvc).
And you do that by using this method:
public static DateTime ConvertToLocalTimeFromUtcTime(DateTime utcDate, string timeZoneId)
{
TimeZoneInfo localZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
DateTime localTime = TimeZoneInfo.ConvertTimeFromUtc(utcDate, localZone);
if (localZone.IsDaylightSavingTime(localTime))
localTime = localTime.AddHours(1); // is this needed !?
return localTime;
}
The question is, does TimeZoneInfo.ConvertTimeFromUtc() handle DST's or do you have to check that yourself and either add or subtract X hour(s) to the date object?
Same question for when persisting a date object to the database by converting it to UTC format with ToUniversalTime().

Yes. ConvertTimeFromUtc will automatically handle daylight saving time adjustments, as long as the time zone that you are targeting uses daylight saving time.
From the MSDN documentation:
When performing the conversion, the ConvertTimeFromUtc method applies any adjustment rules in effect in the destinationTimeZone time zone.
You should not try to add an additional hour in your conversion. That will give you an incorrect translation.
Regarding DateTime.ToUniversalTime, it does take DST into account, but be careful with this method. It assumes that the input value is in the computer's local time zone. If you just need to mark it with DateTimeKind.Utc, then use DateTime.SpecifyKind instead.

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.

Convert timestamp from any timezone to UTC, and optionally without DST

We have timestamps from CSV files that look like this:
06-02-2018 15:04:21
We do not control the delivery of them, nor the timezone.
What we do know so far is that we have seen so far is this:
Standard Romance Time
Standard Romance Time, but without DST compensation.
UTC
From this, we gather that we need an engine that can take any timestamp (written in patterns that DateTime.ParseExact understands), belong to any timezone, optionally ignore DST, and then convert it to UTC (the format we internally use).
I was hoping this could do it:
public DateTime ConvertToUtc(string fromTimestamp, DataReaderConfiguration dataReaderConfiguration)
{
DateTime readTime = DateTime.ParseExact(fromTimestamp, dataReaderConfiguration.TimestampFormat,
CultureInfo.InvariantCulture, DateTimeStyles.None);
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(readTime,
TimeZoneInfo.FindSystemTimeZoneById(dataReaderConfiguration.TimeZone));
return utcTime;
}
but C# does not have timezones defined without DST (except for UTC).
So we need to expand on the method to allow for a timezone conversion without DST.
You can create this function yourself, by leveraging the TimeZoneInfo.BaseUtcOffset property and a DateTimeOffset.
public static DateTime ConvertTimeToUtc(DateTime dt, TimeZoneInfo tz, bool useDST)
{
if (useDST)
{
// the normal way (converts using the time in effect - standard or daylight)
return TimeZoneInfo.ConvertTimeToUtc(dt, tz);
}
// the way to convert with just the standard time (even when DST is in effect)
var dto = new DateTimeOffset(dt, tz.BaseUtcOffset);
return dto.UtcDateTime;
}
Then just pass whatever property from your DataReaderConfiguration object that indicates whether you want to use DST (or negate it if necessary).
Also note that this gives the standard time based on the current set of rules. If you are dealing with historical dates where the time zone's standard time has changed, things get a bit more complex. You'd have to figure out which adjustment rules were in place at the time, etc. You might even find edge cases where the Windows time zone data is insufficient.

What would be the simplest string value to set DateTime

I am trying to figure out the best way of letting the users set the internal DateTime value of the Portable Class Library based on some string parameter they provide. The string parameter has to be a simple format.
So, now I have some considerations.
Is specifying UTC Offset enough for getting the right DateTime
public static DateTime FromUtcOffset(string value)
{
var utcDateTime = DateTime.UtcNow;
var offSet = TimeSpan.Parse(value);
return utcDateTime + offSet;
}
Or is specifying the TimeZone has some advantage over UTC Offset
TimeZoneInfo someTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
DateTime convertTimeFromUtc = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, someTimeZone);
My question is: What would be the right string parameter that can be taken from the user to let him decide what the value of DateTime would be?
Utc Offset
TimeZone
Or any other alternative that's less verbose.
Actually, it depends:
Do you work with network hosts, located in different time zones
Do you store time values for using them in future
Does your library work locally (hence, knows user's timezone)
1+2 basically mean if your time offset might change. If it not (the library is intended for local use only), get local time and don't care about the time offset. However, if the offset might change, usually storing "absolute" time in UTC format should be enough. To do this, you can:
Ask user for UTC time, not their local time
or
Ask for local time + offset (or get the offset from the local time zone, if possible)
Convert it to UTC time and store/process in UTC time
Provide output using local time (using the offset from 1. if it didn't change)
In 1 and 3 you will need a timezone to figure out the time offset. You don't need to know timezone if you already know the offset. Moreover, DateTime itself can store time offset information. It also can tell you if it stores local or UTC time (see DateTime.Kind Property).

How to combine date time and Timezone offset in an ASP.net application?

My web service call to a third party applications returns the date,time zone and timezone_offset values. I need to add this to a calendar in Asp.net application. What is the best way to combine this together so that my date object understands that its from Eastern time zone?
<start_date>2014-11-17 19:00:00</start_date>
<timezone>America/New_York</timezone>
<timezone_offset>GMT-0500</timezone_offset>
Since you have the offset too, you can use DateTimeOffset.Parse() to get the DateTimeOffset. From there, you can read the DateTime property. The output dt variable will have 2014-11-17 7:00:00 PM with DateTimeKind property set to "Unspecified"
var dtOffset = DateTimeOffset.Parse("2014-11-17 19:00:00-0500", CultureInfo.InvariantCulture);
var dt = dtOffset.DateTime;
A DateTimeOffset represents a point in time. Usually, its relative to UTC. So, it is a natural structure to initially parse the fields that you have.
If you want a reference to the same datetime in UTC, you can use this. Here the output dt variable will have 2014-11-18 12:00:00 AM with DateTimeKind property set to "Utc"
var dt = DateTime.Parse("2014-11-17 19:00:00-0500", CultureInfo.InvariantCulture).ToUniversalTime();
If you don't have the offset but just have the timeZoneId, you can still do it but you need NodaTime for that.
I'll focus on this part of the question:
What is the best way to combine this together so that my date object understands that its from Eastern time zone?
There is no data type built in to .NET that can sufficiently do that. The DateTimeOffset type associates with a particular offset, such as the -05:00 or -04:00 that might be in use by the Eastern time zone (depending on the date). But those same offsets might also be sourced from some other time zone entirely. A time zone has one or more offsets, but an offset isn't a time zone itself.
Fortunately there are solutions. There are two options to consider:
You could pair a DateTimeOffset with a TimeZoneInfo object. When storing or transmitting these, you would only send the full DateTimeOffset along with the Id of the time zone.
The Noda Time library is a much more effective way to work with date and time, especially when it comes to time zone concerns. It contains a type called ZonedDateTime that already combines a date, time, offset, and time zone. It can also be used to work with IANA time zone identifiers, such as the "America/New_York" time zone you specified in the question.

Correct approach to getting the universal time zone

In my project I want to get the universal time zone. I used two different kinds of approaches but I don't know which one is the best practice.
First approach is
public static DateTime GetUniversalTime(DateTime localDateTime)
{
TimeZone zone = TimeZone.CurrentTimeZone;
DateTime universal = zone.ToUniversalTime(localDateTime);
return universal;
}
then I want revert to local time I used the below method:
public static DateTime GetLocalTime(DateTime universalDateTime)
{
TimeZone zone = TimeZone.CurrentTimeZone;
DateTime local = zone.ToLocalTime(universalDateTime);
return local;
}
and second approach is get universal time zone DateTime.UtcNow;
then I want to revert to local time I used the above GetLocalTime method.
Can one explain what is the different between the above two approaches?
Which one is the best practice ?
Since you are asking about best practices:
Do not use the TimeZone class. If you need time zone conversions, use the TimeZoneInfo class instead. This is very clear in the MSDN documentation:
Whenever possible, avoid any use of "local" time. It is local to the system where the code is running. In the vast majority of real-world use cases, it is likely that it is not the local time zone of your user. This is especially true in a web application.
That means you should not be calling any of the following:
DateTime.Now
TimeZone.CurrentTimeZone
TimeZoneInfo.Local
DateTime.ToLocalTime()
DateTime.ToUniversalTime()
Any other method that involves the server's local time zone.
Instead, your application should allow the user to select a time zone, then you can convert to and from the local time in that zone using the TimeZoneInfo.Convert... methods.
If you need the current universal time, use DateTime.UtcNow or DateTimeOffset.UtcNow.
If you need the current local time zone of your server, ONLY use DateTimeOffset.Now.
If you need the current local time in a known time zone, such as US Eastern Time:
DateTime easternNow = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(
DateTime.UtcNow, "Eastern Standard Time");
If you want to convert between a known time zone and UTC, then use the TimeZoneInfo.ConvertTimeToUtc and TimeZoneInfo.ConvertTimeFromUtc methods, and be sure to pass in the time zone you are converting to/from:
// get the local time zone of your user, not of the server!
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
// use this to convert from UTC to local
DateTime local = TimeZoneInfo.ConvertTimeFromUtc(yourUtcDateTime, tzi);
// use this to convert from local to UTC
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(yourLocalDateTime, tzi);
Be aware that when you convert from local to UTC, you might encounter ambiguities during daylight saving time transitions. Read more in the DST tag wiki.
Additional reading: The Case Against DateTime.Now
For Universal Time.
DateTime.Now.ToUniversalTime()
For Local Time
DateTime.UtcNow.ToLocalTime()
Universal To Local
var nowUtc = DateTime.Now.ToUniversalTime();
var nowLocal = nowUtc.ToLocalTime();

Categories

Resources