DateTime.Ticks property value - c#

Shouldn't the value of DateTime.Now.Ticks be the same as DateTime.UtcNow.Ticks? I checked their values and found that the difference represents my current time zone offset from UTC. What am I missing here?

This is part of how the objects were designed.
In other libraries and languages (for example, JavaScript's Date type), the value is bound to UTC, and usually uses an epoch of 1970-01-01.
But in .NET, the Ticks value is related to the same frame of reference that the Years, Months, Days, and other properties are based on. It uses an epoch of 0001-01-01.
In DateTime, there's a property called Kind:
If the kind is DateTimeKind.Utc, then you know the value is related to UTC.
If the kind is DateTimeKind.Local, then you know the value is related to the local time zone.
If the kind is DateTimeKind.Unspecified, then you have no idea what time zone reference you have. You simply have a date and time.
You see the difference between DateTime.UtcNow.Ticks and DateTime.Now.Ticks as your current time zone offset, because DateTime.Now has Local kind, while DateTime.UtcNow has Utc kind. So the ticks of DateTime.Now are based on your local time zone, while ticks from DateTime.UtcNow are based on UTC.
The DateTimeOffset type can be used to counteract this problem. The Ticks are still relative to the value shown, but the Offset can be used to always adjust these ticks back to a UTC frame of reference.
If you don't like this, as many do not, an alternative is to use types from the Noda Time library.
By the way, I cover this information in even greater detail, and compare it to other programming languages in my Pluralsight course, Date and Time Fundamentals.

It's different because the time zones are different.

Related

What timezone is the time part of the DateTime string along with an offset represents?

I have DateTime string as 2020-01-21T16:17:01.2202038-05:00, I would like to know 16:17:01.2202038 represents the local time or UTC time?
How can I preserve the local time in C#?
The offset is -05:00, which indicates that the date and time given (2020-01-21T16:17:01.2202038) are 5 hours behind UTC. In other words, it is the local time of some time zone that is UTC-5 at that point in time.
This is not necessarily the same as the local time of the computer where you are evaluating the code, nor is the offset guaranteed to be the same for other points in time for the same time zone.
In .NET, you're much better off representing such data with the DateTimeOffset type, rather than the DateTime type.
By the way, this format is defined as part of the ISO 8601 and RFC 3339 specifications.
A DateTime value does not have TZ offset data. It has a flag for “local” or “UTC” (or unspecified). See the DateTime.Kind property. Internally the actual value of the DateTime is an offset from UTC, stored independently of the Kind.
If a (non-0) TZ is displayed when a DateTime is converted to a string, the DateTime represents the local TZ offset and the TZ-local time.
This TZ offset is calculated on-the-fly depending on the actual DateTime value and current computer (really thread) settings. For example, it will change offsets “automatically” depending if the date is in Standard or Daylight time.* Since the calculation is done with limited data (ticks from UTC and a flag) the TZ is not necessarily “honest” across TZ shifts: the absolute time in UTC is correct, but the currently emitted TZ offset can change as it is computed on currently
active settings.
*Historical offsets can be inaccurate if these rules have changed multiple times, as implementations usually only store so much history.

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.

Converting datetime to time in C# / ASP.NET

I am trying to insert time on my asp.net project.
RequestUpdateEmployeeDTR requestUpdateEmployeeDTR = new RequestUpdateEmployeeDTR();
requestUpdateEmployeeDTR.AttendanceDeducID = int.Parse(txtAttendanceDeducID.Text);
requestUpdateEmployeeDTR.TimeInChange = txtTimeOutChange.Text;
requestUpdateEmployeeDTR.TimeOutChange = txtTimeOutChange.Text;
TimeInChange and TimeOutChange are DateTime data types. But I am inserting a time data type. How can I convert that into a time data type using C#? Thanks!
The .NET Framework does not have a native Time data type to represent a time of day. You will have to decide between one of the three following options:
Option 1
Use a DateTime type, and ignore the date portion. Pick a date that's outside of a normal range of values for your application. I typically use 0001-01-01, which is conveniently available as DateTime.MinValue.
If you are parsing a time from a string, the easiest way to do this is with the DateTimeStyles.NoCurrentDateDefault option. Without this option, it would use today's date instead of the min date.
DateTime myTime = DateTime.Parse("12:34", CultureInfo.InvariantCulture,
DateTimeStyles.NoCurrentDateDefault);
// Result: 0001-01-01 12:34:00
Of course, if you prefer to use today's date, you can do that. I just think it confuses the issue because you might be looking to apply this to some other date entirely.
Note that once you have a DateTime value, you can use the .TimeOfDay property to get at just the time portion, represented as a TimeSpan, which leads to option 2...
Option 2
Use a TimeSpan type, but be careful in how you interpret it. Understand that TimeSpan is first and foremost a type for representing an elapsed duration of time, not a time of day. That means it can store more than 24 hours, and it can also store negative values to represent moving backwards in time.
When you use it as a time of day, you might be inclined to think of it as "elapsed time since midnight". This, however, will get you into trouble because there are days where midnight does not exist in the local time zone.
For example, October 20th 2013 in Brazil started at 1:00 AM due to daylight saving time. So a TimeSpan of 8:00 on this day would actually have been only 7 hours elapsed since 1:00, not 8 hours elapsed since midnight.
Even in the United States, for locations that use daylight saving time, this value is misleading. For example, November 3rd 2013 in Los Angeles had a duplicated hour for when DST rolled back. So a TimeSpan of 8:00 on this day would actually had 9 hours elapsed since midnight.
So if you use this option, just be careful to treat it as the representative time value that matches a clock, and not as "time elapsed since midnight".
You can get it directly from a string with the following code:
TimeSpan myTime = TimeSpan.Parse("12:34", CultureInfo.InvariantCulture);
Option 3
Use a library that has a true "time of day" type. You'll find this in Noda Time, which offers a much better API for working with date and time in .NET.
The type that represents a "time of day" is called LocalTime, and you can get one from a string like this:
var pattern = LocalTimePattern.CreateWithInvariantCulture("HH:mm");
LocalTime myTime = pattern.Parse("12:34").Value;
Since it appears from your question that you are working with time and attendance data, I strongly suggest you use Noda Time for all your date and time needs. It will force you to put more thought into what you are doing. In the process, you will avoid the pitfalls that can come about with the built-in date/time types.
If you are storing a Time type in your database (such as SQL server), that gets translated as a TimeSpan in .Net. So if you go with this option, you'll need to convert the LocalTime to a TimeSpan as follows:
TimeSpan ts = new TimeSpan(myTime.TickOfDay);

How does DateTimeOffset deal with daylight saving time?

I am storing schedules in the database as a day of the week, hour and minute. When the data is read we create a DateTime object for the next occurrence of that day, hour and minute, but I need to modify this to be DST-aware. I am able to modify the database if necessary.
I know that DateTimeOffset stores a UTC date/time and an offset. I also know from this MSDN blog entry that DateTimeOffset should be used to "Work with daylight saving times".
What I'm struggling to understand is exactly how DateTimeOffset "work(s) with daylight saving times". My understanding, little that there is, is that daylight saving times are a political decision and cannot be inferred from purely an offset. How can it be that this structure is DST friendly if it only stores an offset and not a named timezone or country?
DateTimeOffset itself isn't really DST-aware, but TimeZoneInfo is. A DateTimeOffset represents a fixed instant in time - so you get to a DateTimeOffset via something that is time zone aware. In other words, if I asked for a DateTimeOffset now in the UK, I'd end up with something with an offset of +1 hour from UTC. If I asked for a DateTimeOffset for some time in December in the UK, I'd end up with something with an offset of 0 hours from UTC.
If you change your database to include the offset and you create the DateTimeOffset from the user's chosen DateTime (which should be of kind "unspecified") and their time zone, then that should give you the correct offset taking DST into account.
One thing to be aware of though: if I schedule something now for "2 years time" and you determine the offset now, that offset may not be correct in the future - for example, the government could change when DST applies, and obviously that's not going to change what's stored in your database.

DateTime.kind property

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.

Categories