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
How to Use Class Fields with System.Text.JSON.JSONserializer
Properly Draw Text Using Graphicspath
Console Application Closes Immediately After Opening in Visual Studio
How to Pass an Object from Form1 to Form2 and Back to Form1
Escape Special Character in Regex
Executing Ssis 2012 Package That Has Script Components from External Application
Logging Request/Response Messages When Using Httpclient
Local Function VS Lambda C# 7.0
How Enumerate All Classes with Custom Class Attribute
Does .Net Provide an Easy Way Convert Bytes to Kb, Mb, Gb, etc.
Readonlycollection or Ienumerable for Exposing Member Collections
Hyphenated HTML Attributes with ASP.NET MVC
Escape Special Character in Regex
How to Install a Windows Service Programmatically in C#
How to Wait for a Backgroundworker to Cancel
Generate and Sign Certificate Request Using Pure .Net Framework
A Property or Indexer May Not Be Passed as an Out or Ref Parameter