What Does "Datetime" Mean in C#

What does DateTime? mean in C#?

Since DateTime is a struct, not a class, you get a DateTime object, not a reference, when you declare a field or variable of that type.

And, in the same way as an int cannot be null, so this DateTime object can never be null, because it's not a reference.

Adding the question mark turns it into a nullable type, which means that either it is a DateTime object, or it is null.

DateTime? is syntactic sugar for Nullable<DateTime>, where Nullable is itself a struct.

What is a DateTime? as opposed to just a DateTime in C#?

DateTime? can be null as opposed to DateTime

In C#, what is the `?` in the type `DateTime?`

The ? makes it a nullable type (it's shorthand for the Nullable<T> Structure and is applicable to all value types).

Nullable Types (C#)

Note:

The ?? you linked to is the null coalescing operator which is completely different.

What is a DateTime? as opposed to just a DateTime in C#?

DateTime? can be null as opposed to DateTime

What does DateTimeStyles.RoundtripKind enumeration mean?

So I was finally able to understand this and sharing the same information here if it can be helpful for others too:

First part is conversion of C# DateTime object into string. There are many format specifiers to do that but for us r and o format specifiers are of concern to us with regards to DateTimeStyles.RoundtripKind. You can see all date time format specifiers here. See what happens when we do the conversion in code using these format specifiers:

//r corresponds to RFC 1123 format (GMT date time format)
var gmtDateTimeString = DateTime.Now.ToString("r"); //gives Fri, 23 Sep 2016 15:39:21 GMT

//o corresponds to ISO 8601 (Local date time format)
var localDateTimeString = DateTime.Now.ToString("o"); //gives 2016-09-23T15:39:21.8899216+05:30

You can clearly see that string date time being output has the information embedded inside it which suggests:

  • Fri, 23 Sep 2016 15:39:21 GMT is of DateTimeKind.Utc (GMT text is present)
  • 2016-09-23T15:39:21.8899216+05:30 represents a date time of DateTimeKind.Local (T character is present as per ISO 8601 standard)

Now comes the second part. If I've to convert the date time strings stored in gmtDateTimeString and localDateTimeString back to a date time object then we need to parse them. So with the help of DateTimeStyles.RoundtripKind enumeration value passed to DateTime.Parse API you actually signify that time zone information is already baked in the string and API parses the date time appropriately using that information.

Normally, when date time data is transferred over the wire in XML format then ISO 8601 format is used which I saw in the post which I referred before posting the question in this thread. So while parsing such a date time string obtained from an XML document it was appropriate to use the DateTimeStyles.RoundtripKind to get the right date time value as per the time-zone information present in the string.

Difference between System.DateTime.Now and System.DateTime.Today

DateTime.Now returns a DateTime value that consists of the local date and time of the computer where the code is running. It has DateTimeKind.Local assigned to its Kind property. It is equivalent to calling any of the following:

  • DateTime.UtcNow.ToLocalTime()
  • DateTimeOffset.UtcNow.LocalDateTime
  • DateTimeOffset.Now.LocalDateTime
  • TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local)
  • TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.Local)

DateTime.Today returns a DateTime value that has the same year, month, and day components as any of the above expressions, but with the time components set to zero. It also has DateTimeKind.Local in its Kind property. It is equivalent to any of the following:

  • DateTime.Now.Date
  • DateTime.UtcNow.ToLocalTime().Date
  • DateTimeOffset.UtcNow.LocalDateTime.Date
  • DateTimeOffset.Now.LocalDateTime.Date
  • TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local).Date
  • TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.Local).Date

Note that internally, the system clock is in terms of UTC, so when you call DateTime.Now it first gets the UTC time (via the GetSystemTimeAsFileTime function in the Win32 API) and then it converts the value to the local time zone. (Therefore DateTime.Now.ToUniversalTime() is more expensive than DateTime.UtcNow.)

Also note that DateTimeOffset.Now.DateTime will have similar values to DateTime.Now, but it will have DateTimeKind.Unspecified rather than DateTimeKind.Local - which could lead to other errors depending on what you do with it.

So, the simple answer is that DateTime.Today is equivalent to DateTime.Now.Date.

But IMHO - You shouldn't use either one of these, or any of the above equivalents.

When you ask for DateTime.Now, you are asking for the value of the local calendar clock of the computer that the code is running on. But what you get back does not have any information about that clock! The best that you get is that DateTime.Now.Kind == DateTimeKind.Local. But whose local is it? That information gets lost as soon as you do anything with the value, such as store it in a database, display it on screen, or transmit it using a web service.

If your local time zone follows any daylight savings rules, you do not get that information back from DateTime.Now. In ambiguous times, such as during a "fall-back" transition, you won't know which of the two possible moments correspond to the value you retrieved with DateTime.Now. For example, say your system time zone is set to Mountain Time (US & Canada) and you ask for DateTime.Now in the early hours of November 3rd, 2013. What does the result 2013-11-03 01:00:00 mean? There are two moments of instantaneous time represented by this same calendar datetime. If I were to send this value to someone else, they would have no idea which one I meant. Especially if they are in a time zone where the rules are different.

The best thing you could do would be to use DateTimeOffset instead:

// This will always be unambiguous.
DateTimeOffset now = DateTimeOffset.Now;

Now for the same scenario I described above, I get the value 2013-11-03 01:00:00 -0600 before the transition, or 2013-11-03 01:00:00 -0700 after the transition. Anyone looking at these values can tell what I meant.

I wrote a blog post on this very subject. Please read - The Case Against DateTime.Now.

Also, there are some places in this world (such as Brazil) where the "spring-forward" transition happens exactly at Midnight. The clocks go from 23:59 to 01:00. This means that the value you get for DateTime.Today on that date, does not exist! Even if you use DateTimeOffset.Now.Date, you are getting the same result, and you still have this problem. It is because traditionally, there has been no such thing as a Date object in .Net. So regardless of how you obtain the value, once you strip off the time - you have to remember that it doesn't really represent "midnight", even though that's the value you're working with.

If you really want a fully correct solution to this problem, the best approach is to use NodaTime. The LocalDate class properly represents a date without a time. You can get the current date for any time zone, including the local system time zone:

using NodaTime;
...

Instant now = SystemClock.Instance.Now;

DateTimeZone zone1 = DateTimeZoneProviders.Tzdb.GetSystemDefault();
LocalDate todayInTheSystemZone = now.InZone(zone1).Date;

DateTimeZone zone2 = DateTimeZoneProviders.Tzdb["America/New_York"];
LocalDate todayInTheOtherZone = now.InZone(zone2).Date;

If you don't want to use Noda Time, there is now another option. I've contributed an implementation of a date-only object to the .Net CoreFX Lab project. You can find the System.Time package object in their MyGet feed. Once added to your project, you will find you can do any of the following:

using System;
...

Date localDate = Date.Today;

Date utcDate = Date.UtcToday;

Date tzSpecificDate = Date.TodayInTimeZone(anyTimeZoneInfoObject);

To get the date difference between a datetime and nullable datetime

TimeSpan? means Nullable<TimeSpan> which is a different structure from TimeSpan and it doesn't have a Days property.

Instead of that, you can use it's Value property and you can call it's Days after it like;

model.Diff = (model.Date1 - (model.Date2 != null ? model.Date2 : today)).Value.Days; 

Or as commented by juharr, you can use model.Date2 ?? today which returns model.Date2 if it's not null or returns today if model.Date2 is null like;

model.Diff = (model.Date1 - (model.Date2 ?? today)).Days;

What does %(percent symbol) mean in DateTime format

The related documentation can be found here: https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings

Note the description of the % symbol: "Defines the following character as a custom format specifier".[1]

Since you have a custom date time format string, the symbols M, d, H, ... are custom format specifiers. This means, here % essentially becomes a no-operation without any effect, because the symbols following it are already custom format specifiers.

So, what exactly is the purpose of % if the symbols in a custom date time format string are already custom format specifiers regardless of % being there or not? The reason for % becomes understandable when you consider that there are also standard date time format strings, which consist of a single character, a single format specifier. Pertinent documentation here: https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings

Basically, any date time format string made of only one character is treated as a standard date time format string. And any date time format string with two or more characters is treated as a custom date time format string.

What if you want to use a custom date time format string consisting of only one custom format specifier? That one-character string will be interpreted as a standard date time format string instead. And that is a problem.

If you compare the lists of specifiers for standard and custom date time format strings, you'll notice that many of the standard date time format specifiers use symbols that are also used by custom date time format specifiers. However, standard date time format specifiers represent different data and/or formatting patterns than the respective custom date time format specifier using the same symbol. For example, the standard date time format specifier y yields year+month, while the custom date time format specifier y yields the last two digits of the year.

Therefore, if you need a functionally single-specifier custom date time format string, you gotta fatten up that string and turn it from a one-character string into a two-characters string with the help of the "no-op" specifier %, so that it will be correctly treated as a custom date time format string.

As an example, imagine you want to get just the last two digits of the year and nothing more, and you decide to use the custom format specifier y which does exactly what you want. However, the format string "y" is a standard date time format string yielding year+month. So, how do you get what you want? You turn the standard date time format string "y" into a custom date time format string by using "%y".

[1]According to that documentation, it should theoretically be possible to use contiguous sequences of multiple % in custom date time format string like "%%%%%M/%%%%%%d". Each of those % sequences should functionally collapse into a single %, as by definition according to the quoted documentation, each % defines the following % as a custom format specifier that it already is. However -- and for the better, i might add -- the DateTime formatting functions will have none of such shenanigans and throw a FormatException for you being a bad boy having even tried this...



Related Topics



Leave a reply



Submit