DateTime.kind property - c#

Have a small doubt with the DateTime.kind property. Documentation says that kind property have three fields Unspecified, Local, and Utc to show how the datetime object is represented.
DateTime dt1 = DateTime.Now;
Console.WriteLine(dt1.Kind);
Which shows "Local" but in some microsoft documentation I red that system date and time that Windows maintains is UTC rather than local time.
If that is the case then the above WriteLine should output it as UTC rather than Local?
Any idea?
--Rahul

DateTime.Now is meant to retrieve the current local time. DateTime.UtcNow retrieves the current UTC time.
Note that this is unrelated to how Windows itself stores the time. I believe it stores the current time in UTC, but also keeps track of the current time zone, so it can display the appropriate local time. I believe this is what DateTime.Now does as well.

Related

UTC date.ToLocalTime() still produces date in UTC time

I'm working with an ASP.Net backend. I'm saving all my dates from the client side to the database in UTC time.
I have a function in the backend that exports some records and I would like to convert the dates extracted, from UTC time to the user's local time before displaying them.
I have tried tons of solutions proposed here on StackOverflow, but none of them seem to convert the date to local time, even though this works when displaying some of these dates on the client.I suspect the server already thinks the date is in local time, but I'm not sure how else to solve it.
Below are the different solutions I have tried:
//1.
var alertTime = record.TimeRecorded.GetValueOrDefault().ToLocalTime().ToString("hh:mm tt");
// 2.
var alertTime = record.TimeRecorded;
if (alertTime.HasValue)
{
var timeInUtc = TimeZoneInfo.ConvertTimeToUtc(alertTime.Value);
string alertTimeToLocalTime = timeInUtc.ToLocalTime().ToString("hh:mm tt");
}
//alertTimeToLocalTime is still in UTC time here
// 3.
if (alertTime.HasValue)
{
var localTime = TimeZoneInfo.ConvertTimeFromUtc(timeInUtc, TimeZoneInfo.Local);
string alertTimeToLocalTime = localTime.ToString("hh:mm tt");
}
None of these have managed to convert the alertTime to local time.
Am I missing something?
EDIT
//4. Another approach I had already tried which didn't work as well
var alertTime = DateTime.SpecifyKind(record.TimeRecorded.GetValueOrDefault(), DateTimeKind.Utc);
alertTimeToLocalTime = alertTime.ToLocalTime().ToString("hh:mm tt");
You said:
... from UTC time to the user's local time ...
Nothing in ASP.Net will tell you the user's local time zone. Calling ToLocalTime will convert from UTC to the server's time zone (unless the .Kind is already DateTimeKind.Local).
In many cases, the best practice of setting the server's time zone to UTC will mean that you will see no change with ToLocalTime or ToUniversalTime, other than the kind. And since the server's time zone is irrelevant in most cases, this is not the correct approach.
Instead, you either need to know the user's time zone through some other mechanism (such as them selecting it in your application) so you can use the TimeZoneInfo.ConvertTime (or Noda Time) to convert server-side, or you need to send UTC time down to the client and do the utc-to-local in JavaScript (since the browser is running in the user's time zone).
In general, any use of "local time" in a server application (such as ASP.NET) should be avoided. This includes ToLocalTime, ToUniversalTime, DateTimeKind.Local, TimeZoneInfo.Local, DateTime.Now, and a few other miscellaneous things.
It's because your DateTime's Kind is either Local or Unspecified. See the documentation for ToLocalTime():
Starting with the .NET Framework version 2.0, the value returned by the ToLocalTime method is determined by the Kind property of the current DateTime object. The following table describes the possible results.
Utc - This instance of DateTime is converted to local time.
Local - No conversion is performed.
Unspecified - This instance of DateTime is assumed to be a UTC time, and the conversion is performed as if Kind were Utc.
You can use the SpecifyKind method to set the Kind prior to doing the conversion.

What happens when we convert UTC Date time ToUniversalTime?

What happens when we convert UTC Date time ToUniversalTime?
DateTime localDate = DateTime.Now.AddMinute(offsetTimeZone);
DateTime todayStart = localDate.Date.ToUniversalTime().AddHours(00).AddMinutes(00);
There is a -lot- going on when converting using ToUniversalTime. DST is addressed, local time, etc. etc.
Just go to the reference source and read through the code:
http://referencesource.microsoft.com/#mscorlib/system/datetime.cs,fddce8be2da82dfc
There is already the same question on stackoverflow.
here is no implicit timezone attached to a DateTime object. If you run ToUniversalTime() on it, it uses the timezone of the context that the code is running in.
For example, if I create a DateTime from the epoch of 1/1/1970, it gives me the same DateTime object no matter where in the world I am.
If I run ToUniversalTime() on it when I'm running the code in Greenwich, then I get the same time. If I do it while I live in Vancouver, then I get an offset DateTime object of -8 hours.
This is why it's important to store time related information in your database as UTC times when you need to do any kind of date conversion or localization. Consider if your codebase got moved to a server facility in another timezone ;)
You can find the question and the complete answer here.
DateTime objects by default are typed as DateTimeKind.Local. On parsing a date and set it as DateTimeKind.Utc, then ToUniversalTime() performs no conversion. If we run ToUniversalTime(), it uses the timezone of the context that the code is running in.

Why DateTime.Now and DateTime.UtcNow Isn't My Current Local DateTime?

We use DateTime.Now, but the time is not equal with our server time!
When I run my project, these are the DateTime property values:
DateTime.Now = {15/14/04 05:20:18 AM}
DateTime.UtcNow = {15/14/04 12:20:18 PM}
But my current local system time is:
15/14/04 04:50:18 AM
My time zone is Tehran (UTC+03:30).
This is the first time I've see this behavior! Why doesn't DateTime.Now equal my computer's time?
Make sure you are not manipulating the timezone somewhere in code, or playing with System.Globalization.CultureInfo
Try to search in all your source code for System.Globalization.CultureInfo may be it is somewhere, also may be the time zone is cached somewhere so try to call System.Globalization.CultureInfo.CurrentCulture.ClearCachedData() before DateTime.Now
.NET DateTime.Now returns incorrect time when time zone is changed
Your timezone is UTC +03:30, but because of daylight saving it's +4:30. This means that when DateTime.UtcNow = {15/14/04 12:20:18 PM}, it's 04:50:18 AM in your timezone, which your clock confirms.
So your DateTime.Now doesn't confirm to your machine's datetime settings, making it return a value that doesn't match your clock.
As of why the accepted answer works can be explained by DateTime.Now using the TimeZoneInfo class to calculate the local time from UTC (using timezone and daylight saving), but I don't know why that can run out of sync. Do you never recycle your application pools and never shutdown your machine? ;)
System.Globalization.CultureInfo.CurrentCulture.ClearCachedData() works because it calls TimeZone.ResetTimeZone() and TimeZoneInfo.ClearCachedData().

UTC to local time conversion for previously saved datetimes if rules for timezone change

I'm storing a product in db. All dates (sql server datetime) are UTC and along with the dates I store the time zone id for that product. User enters the dates when product is available "from" and "until" in the listing.
So I do something like:
// Convert user's datetime to UTC
var userEnteredDateTime = DateTime.Parse("11/11/2014 9:00:00");
// TimeZoneInfo id will be stored along with the UTC datetime
var tz = TimeZoneInfo.FindSystemTimeZoneById("FLE Standard Time");
// following produces: 9/11/2014 7:00:00 AM (winter time - 1h back)
var utcDateTime = TimeZoneInfo.ConvertTimeToUtc(userEnteredDateTime, tz);
and save the record. Let's assume user did this on the 1st of August, while his time zone offset to UTC is still +03:00, nevertheless the saved date for the future listing has the correct +02:00 value because conversion took into consideration the "winter" time for that period.
Question is what datetime value will I get if I will attempt to convert that product's "from" and "until" date to product's local time zone on 11/11/2014 if, for example, due to some new rules the transition to winter time was abandoned, thus the time zone is still +03:00 instead of +02:00?
// Convert back
var userLocalTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, tz);
will I get 10AM or correct 9AM because OS/.NET patch will handle this?
Thank you!
P.S.: TimeZoneInfo has ToSerializedString() method, if I rather store this value instead of timezone id, will this guarantee that via UTC datetime + serialized timezoneinfo I will always be able to convert to the user's original datetime input?
In the scenario you describe, you would get 10:00 AM. The time zone conversion function would not have any idea that the value was originally entered as 9:00 AM, because you only saved the UTC time of 7:00 AM.
This illustrates one of the cases where the advice "always store UTC" is flawed. When you're working with future events, it doesn't always work. The problem is that governments change their mind about time zones often. Sometimes they give reasonable notice (ex. United States, 2007) but sometimes they don't (ex. Egypt, 2014).
When you made the original conversion from local time to UTC, you intentionally decided to trust that the time zone rules would not change. In other words, you decided that you would assign the event to the universal timeline based solely on the time zone rules as you knew them at that time.
The way to avoid this is simple: Future events should be scheduled in local time. Now, I don't mean "local to your computer", but rather "local to the user", so you will need to know the user's time zone, and you should also store the ID of the time zone somewhere.
You'll also need to decide what you want to do if the event falls into the spring-forward or fall-back transition for daylight saving time. This is especially important for recurrence patterns.
Ultimately though, you'll need to figure out when to run the event. Or in your case, you'll need to decide if the event has passed or not. There are a few different ways you can accomplish this:
Option 1
You can calculate the corresponding UTC value for each local time and keep it in a separate field.
On some cycle (daily, weekly, etc) you can recalculate upcoming UTC values from their local values and your current understanding of the time zone rules. Or, if you apply time zone updates manually, you can choose to recalculate everything at that time.
Option 2
You can store the values as a DateTimeOffset type instead of a DateTime. It will contain the original local time, and the offset that you calculated based on the time zone rules as you knew them at time of entry.
DateTimeOffset values can easily be coerced back to UTC, so they tend to work very well for this. You can read more in DateTime vs DateTimeOffset.
Just like in option 1, you would revisit the values periodically or after time zone data updates, and adjust the offsets to align with the new time zone data.
This is what I usually recommend, especially if you're using a database that has support for DateTimeOffset types, such as SQL Server or RavenDB.
Option 3
You can store the values as a local DateTime.
When querying, you would calculate the current time in the target time zone and compare against that value.
DateTime now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, targetTZ);
bool passed = now >= eventTime;
The down side of this option is that you may have to make lots queries if you have events in lots of different time zones.
You may also have issues with values close to the fall-back DST transition, so be careful if you use this approach.
I recommend against the idea of serializing the time zone itself. If the time zone has changed, then it has changed. Pretending that it hasn't isn't a good workaround.

Convert UTC/GMT time to local time

We are developing a C# application for a web-service client. This will run on Windows XP PC's.
One of the fields returned by the web service is a DateTime field. The server returns a field in GMT format i.e. with a "Z" at the end.
However, we found that .NET seems to do some kind of implicit conversion and the time was always 12 hours out.
The following code sample resolves this to some extent in that the 12 hour difference has gone but it makes no allowance for NZ daylight saving.
CultureInfo ci = new CultureInfo("en-NZ");
string date = "Web service date".ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
As per this date site:
UTC/GMT Offset
Standard time zone: UTC/GMT +12 hours
Daylight saving time: +1 hour
Current time zone offset: UTC/GMT +13 hours
How do we adjust for the extra hour? Can this be done programmatically or is this some kind of setting on the PC's?
For strings such as 2012-09-19 01:27:30.000, DateTime.Parse cannot tell what time zone the date and time are from.
DateTime has a Kind property, which can have one of three time zone options:
Unspecified
Local
Utc
NOTE If you are wishing to represent a date/time other than UTC or your local time zone, then you should use DateTimeOffset.
So for the code in your question:
DateTime convertedDate = DateTime.Parse(dateStr);
var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified
You say you know what kind it is, so tell it.
DateTime convertedDate = DateTime.SpecifyKind(
DateTime.Parse(dateStr),
DateTimeKind.Utc);
var kind = convertedDate.Kind; // will equal DateTimeKind.Utc
Now, once the system knows its in UTC time, you can just call ToLocalTime:
DateTime dt = convertedDate.ToLocalTime();
This will give you the result you require.
I'd look into using the System.TimeZoneInfo class if you are in .NET 3.5. See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx. This should take into account the daylight savings changes correctly.
// Coordinated Universal Time string from
// DateTime.Now.ToUniversalTime().ToString("u");
string date = "2009-02-25 16:13:00Z";
// Local .NET timeZone.
DateTime localDateTime = DateTime.Parse(date);
DateTime utcDateTime = localDateTime.ToUniversalTime();
// ID from:
// "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone"
// See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx
string nzTimeZoneKey = "New Zealand Standard Time";
TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey);
DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone);
TimeZone.CurrentTimeZone.ToLocalTime(date);
DateTime objects have the Kind of Unspecified by default, which for the purposes of ToLocalTime is assumed to be UTC.
To get the local time of an Unspecified DateTime object, you therefore just need to do this:
convertedDate.ToLocalTime();
The step of changing the Kind of the DateTime from Unspecified to UTC is unnecessary. Unspecified is assumed to be UTC for the purposes of ToLocalTime: http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx
I know this is an older question, but I ran into a similar situation, and I wanted to share what I had found for future searchers, possibly including myself :).
DateTime.Parse() can be tricky -- see here for example.
If the DateTime is coming from a Web service or some other source with a known format, you might want to consider something like
DateTime.ParseExact(dateString,
"MM/dd/yyyy HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)
or, even better,
DateTime.TryParseExact(...)
The AssumeUniversal flag tells the parser that the date/time is already UTC; the combination of AssumeUniversal and AdjustToUniversal tells it not to convert the result to "local" time, which it will try to do by default. (I personally try to deal exclusively with UTC in the business / application / service layer(s) anyway. But bypassing the conversion to local time also speeds things up -- by 50% or more in my tests, see below.)
Here's what we were doing before:
DateTime.Parse(dateString, new CultureInfo("en-US"))
We had profiled the app and found that the DateTime.Parse represented a significant percentage of CPU usage. (Incidentally, the CultureInfo constructor was not a significant contributor to CPU usage.)
So I set up a console app to parse a date/time string 10000 times in a variety of ways. Bottom line:
Parse() 10 sec
ParseExact() (converting to local) 20-45 ms
ParseExact() (not converting to local) 10-15 ms
... and yes, the results for Parse() are in seconds, whereas the others are in milliseconds.
I'd just like to add a general note of caution.
If all you are doing is getting the current time from the computer's internal clock to put a date/time on the display or a report, then all is well. But if you are saving the date/time information for later reference or are computing date/times, beware!
Let's say you determine that a cruise ship arrived in Honolulu on 20 Dec 2007 at 15:00 UTC. And you want to know what local time that was.
1. There are probably at least three 'locals' involved. Local may mean Honolulu, or it may mean where your computer is located, or it may mean the location where your customer is located.
2. If you use the built-in functions to do the conversion, it will probably be wrong. This is because daylight savings time is (probably) currently in effect on your computer, but was NOT in effect in December. But Windows does not know this... all it has is one flag to determine if daylight savings time is currently in effect. And if it is currently in effect, then it will happily add an hour even to a date in December.
3. Daylight savings time is implemented differently (or not at all) in various political subdivisions. Don't think that just because your country changes on a specific date, that other countries will too.
#TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)
Don't forget if you already have a DateTime object and are not sure if it's UTC or Local, it's easy enough to use the methods on the object directly:
DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();
How do we adjust for the extra hour?
Unless specified .net will use the local pc settings. I'd have a read of: http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx
By the looks the code might look something like:
DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );
And as mentioned above double check what timezone setting your server is on. There are articles on the net for how to safely affect the changes in IIS.
In answer to Dana's suggestion:
The code sample now looks like:
string date = "Web service date"..ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate);
The original date was 20/08/08; the kind was UTC.
Both "convertedDate" and "dt" are the same:
21/08/08 10:00:26; the kind was local
I had the problem with it being in a data set being pushed across the wire (webservice to client) that it would automatically change because the DataColumn's DateType field was set to local. Make sure you check what the DateType is if your pushing DataSets across.
If you don't want it to change, set it to Unspecified
I came across this question as I was having a problem with the UTC dates you get back through the twitter API (created_at field on a status); I need to convert them to DateTime. None of the answers/ code samples in the answers on this page were sufficient to stop me getting a "String was not recognized as a valid DateTime" error (but it's the closest I have got to finding the correct answer on SO)
Posting this link here in case this helps someone else - the answer I needed was found on this blog post: http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ - basically use DateTime.ParseExact with a format string instead of DateTime.Parse
This code block uses universal time to convert current DateTime object then converts it back to local DateTime. Works perfect for me I hope it helps!
CreatedDate.ToUniversalTime().ToLocalTime();

Categories