Correct way to convert datetime timezone for display - c#

We are developing a website and currently, the timezone of the website and database is in German time zone (European standard time zone). But the application is being accessed from the US also. There is a screen in the application which contains a DateTime field called ValidFrom and the time we are storing is UTC time. currently, users are not selecting the time so we are using .NET built-in DateTime.UTCNow to store DateTime value in the database. But the problem is while displaying, we need to display it according to User timezone. So after googling for many hours, we found two solutions one using moment and another approach is using DateTime.SpecifyKind. We tried using moment.js but it converted the date time to local time once again. So we ended up using DateTime.SpecifyKind as below.
[DataMember]
private DateTime _validFrom;
public DateTime ValidFrom
{
get { return _validFrom; }
set { _validFrom = DateTime.SpecifyKind(value, DateTimeKind.Utc); }
}
And now the values are displayed according to timezone. But my doubt is, is it the correct approach to handle timezone display or any other better solution exist?

I'd use DateTimeOffset instead, something like:
var utc = DateTimeOffset.UtcNow;
var tz = TimeZoneInfo.FindSystemTimeZoneById("Your Specific Time Zone Id");
var zonedDateTime = TimeZoneInfo.ConvertTime(utc, tz);
Save the UTC and user's time zone in the database, and convert UTC to specific time zone any time you want to show it to your users. I also suggest you take a look at NodaTime if you want to do anything serious with date and time. The built-in DateTime in .Net is misleading.

I wrote an extension method for this:
public static DateTime ConvertFromUTC(this DateTime date, TimeZoneInfo destZone)
{
var utcZone = TimeZoneInfo.FindSystemTimeZoneById("UTC");
return TimeZoneInfo.ConvertTime(date, utcZone, destZone);
}
However, if you plan to use something like this you need to be aware of daylight saving time. The result may be off if the conversion crosses a DST change in either timezone. So it isn't really suitable if you need absolute precision, which depends on the website, e.g.: is it a blog or a stock trading app?

Related

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.

Convert some local time to UTC in C#

I am trying do to something like this:
On a client side I have datepicker for selecting date, drop down for selecting an hour, and drop down with time zones for selecting user time zone.
I am sending this info to server. On a server side, I want to accomplish this:
Take date and time values, and check what is the value of time zone.
If it is for example "UTC+1" (or any other +- value of UTC time), convert that into UTC, before saving.
What I am not sure how to do it is: What value should I send from client as time zone information so server can detect it is a for example UTC+1.
I saw examples like this:
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
On how to find out what is the time zone by its id, but I cannot do something like this:
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("UTC+1");
Because, I get an exception, of course:
Additional information: The time zone ID 'UTC+1' was not found on the
local computer.
Does someone know what is Id for all UTC+-someNumber, or there is a way to detect timezone from UTC string in some different way?
Did someone had experience whit this kind of a conversion?
As far as I remember the only way to work with the timezones is by the full name that is available in your OS.
You can find a similar question here.
A list from MSDN is here.
So there seems to be no easy way to convert strings like "UTC+1", unless you create a mapping to the ones that are supported by framework.
You could use TimeZoneInfo.CreateCustomTimeZone():
DateTime utcTime = DateTime.UtcNow;
TimeZoneInfo targetTimeZone = TimeZoneInfo.CreateCustomTimeZone("MyId", TimeSpan.FromHours(1), "Somewhere", "Somewhere");
DateTime targetTime = TimeZoneInfo.ConvertTime(utcTime, targetTimeZone);
or you can use DateTimeOffset, or DateTime.AddHours(1):
var datetimeOffset = new DateTimeOffset(yourDateTime, TimeSpan.FromHours(1));
var otherDatetime = yourDateTime.AddHours(1);

How can I get the DateTime based on the current timezone in ASP.NET, C#

I've been using DateTime.Now in my asp.net application. However, I think this is always using the time of the server which is in the US. How could I get the datetime based on the timezone? For example, if someone is using my software in Taiwan I would want to show the date based on their timezone not on US timezone.
I know that I can find the current timezone like this:
TimeZone localZone = TimeZone.CurrentTimeZone;
However, I need a DateTiem. Is there a way I could convert this to a DateTime?
Edit
To clarify, I want to just show the current date on my webpage. However, when I use DateTime.Now it uses the timezone of my server. I won't be storing this date in my DB so I don't think I'll need this date in UTC.
This will convert local time, to specific time zone:
var yourTime = TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.Local, TimeZoneInfo.FindSystemTimeZoneById("your time zone ID"));

.NET Save DateTime and completely ignore timezone

Maybe the answer is so obvious, I'm not seeing it, but I have a question that I'll risk asking anyway.
I want to allow users of a .NET Web application to enter a date/time, store it in an Oracle database, and no matter which timezone they are in, it always displays as the raw, original version as typed in by the user. So if one user in California enters 2PM and another in Maryland enters 2PM, they would both show as 2PM to a user in Japan. Two types of clients are possible, a web user and a windows client user (connected via web service).
Think of it like I want to completely break all timezone smarts that most applications worry about.
I don't want to save as a string though. I want a datetime that I can add/remove hours and minutes from.
Edit:
This was basically the exact problem I was having.
You should always store DateTime in UTC format (universal). When you display it you can choose which ever timezone you wish, in your case this can be fixed for all users, rather than based on location.
// when recording date time
DateTime utcDateTime = DateTime.UtcNow;
// parse DateTime back out from string
DateTime utcDateTime = DateTime.SpecifyKind(DateTime.Parse(dateStr),
DateTimeKind.Utc);
// localized DateTime
DateTime localDate = utcDateTime.ToLocalTime();
// fixed DateTime based on timezone
string timeZoneKey = "New Zealand Standard Time";
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneKey);
DateTime nzlocalDate = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, timeZone);
This takes into account things like day-light savings which can trip you up if start saving localized dates.
If you just store the DateTime as entered/picked by the user then it will be stored as just that. There will be time zone informations stored in it, but you are in control of what you do with it.
For example, when you want to output it to the screen/file etc. you will need to format it to a string. If you use this ToString overload with CultureInfo.InvariantCulture then this should ignore the current culture and output the date as is:
DateTime date = DateTime.Now;
string output = date.ToString("d", CultureInfo.InvariantCulture);
Other operations will require different handling, but you will need to specify what happens in each case.
I had a time sensitive fix and the SpecifyKind did not allow me to make proper TimeSpan comparisons. In my situation, the quickest solution was to simply remove the Hours, Minutes, and Seconds from the time, as the DateTime I was comparing with was at midnight (00:00:00),
DateTime eventDateTime = (DateTime)row["event_date"];
eventDateTime = eventDateTime.AddHours(-1 * eventDateTime.Hour).AddMinutes(-1 * eventDateTime.Minute).AddSeconds(-1 * eventDateTime.Second);
If you really want discard time zone:
public static DateTime WithoutTimeZone(this DateTime dateTime)
{
if (dateTime.Kind != DateTimeKind.Unspecified)
return new DateTime(dateTime.Ticks, DateTimeKind.Unspecified);
return dateTime;
}

Converting UK times (both BST and GMT) represented as strings to UTC (in C#)

I have to use some dates and times from a legacy database. They are represented as strings. Dates are dd/MM/yy. Times are HH:mm.
I'd like to convert these to UTC as soon as I pull them from the database. I'm working on US systems, so need a common time.
The problem I'm facing is how to convert them to UTC DateTime values. I can do the parsing, etc. The real problem I have concerns the timezone.
I'm trying to use the following approach:
DateTime ukTime = // Parse the strings in a DateTime value.
TimeZoneInfo timeZoneInformation = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTimeOffset utcTime = new DateTimeOffset(ukTime, timeZoneInformation.BaseUtcOffset);
However, this gives incorrect values if the date is in the British Summer Time period.
I can use "GMT Daylight Time" on those dates, but that requires me to know when the switchover is. I'm sure there must be a less laborious way.
As I'm not using a machine with UK time settings I can't rely on local time.
Basically, I need something like:
// Works for both GMT (UTC+0) and BST (UTC+1) regardless of the regional settings of the system it runs on.
DateTime ParseUkTimeAsUtcTime(string date, string time)
{
...
}
I've scoured the posts, but couldn't find anything that addressed this directly. Surely this is also an issue with EST, EDT, etc?
Try using the GetUtcOffset() method on your TimeZoneInfo instance, which takes "adjustment rules" into consideration.
Using this should work basically the same as your original example, but you'll use that method instead of the BaseUtcOffset property.
DateTime ukTime = // Parse the strings in a DateTime value.
TimeZoneInfo timeZoneInformation = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTimeOffset utcTime = new DateTimeOffset(ukTime, timeZoneInformation.GetUtcOffset(ukTime));
How about:
DateTime.Parse(dateTimeString).ToUniversalTime();
Assuming that the database server stores its datetimes in the same timezone as your application server.

Categories

Resources