21

One of the first things I learned about dates and times in c# (and various other languages) is that a date is stored as a DateTime with the time component set to midnight. There is no difference between "Jan 1, 2017" and "January 1, 2017 00:00:00.000". If you need to display just a date, you can use formatting functions like ToString to remove the time portion.

This seems to cause a lot of problems, a few of which I shall list here:

  1. DateTime takes up more storage space than needed: 8 bytes instead of the 3 required for a simple date.

  2. Use of 00:00:00 for "no date" conflates "a known value of 0" with "unknown value." This seems rather noobish, in the same way a new programmer might confuse a null string with an empty string. Null and empty are different, and "no time" and "midnight" are different ideas.

  3. You see idioms like this one poppping up, even in relatively simple comparisions:

    if (startDate >= myDateTime && myDateTime < endDate.AddDays(1))
    

    or

    if (startDateTime >= myDate && myDate <= endDateTime.Date)
    

    instead of a far simpler

    if (startDate >= myDate && myDate <= endDate)
    
  4. When system components located in different time zones call each other over web services, and the schema for those web services is generated from c# types, a time element can be introduced (so that the resulting date occurs early in the morning), or the date value actually may shift by a day (e.g. the final date is actually the prior day at a time late in the evening). This can make it painful to transmit values that are agnostic with respect to timezone, e.g. a date of birth, or a credit card expiration date.

SQL Server has a Date type that stores only month, day, and year.

XSD specifies different data types for Date, Time, and DateTime.

Why doesn't c# have such a type?

How do you work around it? For example, can c# properties be attributed so that they will serialize as a Date instead of a DateTime?

18
  • 3
    Because the BCL isn't exactly well designed. You could use NodaTime if you care about clean modeling of dates and times. Commented Mar 27, 2017 at 19:43
  • 23
    Pretty much everything involving dates, times, and timezones is always going to suck and you might as well just make peace with that fact. Commented Mar 27, 2017 at 20:00
  • 2
    Thanks Dan, but Eric's answer addresses the question of "why isn't there an alias for DateTime like there is for other fundamental data types (e.g. System.Int32 = int)?" It does not answer the question of why there is not a separate data type just for Date.
    – John Wu
    Commented Mar 27, 2017 at 20:02
  • 1
    @Snowman: Transitivity is hardly present between these two questions; if anything, there is a fallcious induction between your answers.
    – John Wu
    Commented Mar 27, 2017 at 20:32
  • 2
    To mangle a metaphor, this is the tip of the iceburg of a very deep rabbit hole. blog.nodatime.org/2011/08/what-wrong-with-datetime-anyway.html
    – user244218
    Commented Apr 6, 2017 at 16:10

5 Answers 5

17

What is a Date?

Let's say It's noon at your local region. You'll look at your clock and see something like 22/03/2017 12:00. You could say easily that this is the current date for everyone else in the world, right?

Well, not really. Chances are, if you are in London, or say, Russia, or the United States, your clock isn't really correct regarding those places. Your clock is marking the wrong time for the rest of the world, and for some places even the wrong date. When you talk about "the world", having a date without a time makes little to no sense once you start considering people outside your timezone. Just think how annoying it is to go to a foreigner website and seeing that, somehow, the user generated content there is coming from the future. That's what happens when you don't take into account timezones!

That's where C# DateTime goes in.

DateTime isn't the usual simple date you may need for local, just-my-company software. It is a somewhat powerful data structure that had the intent to be able to provide Universal Coordinated Time to any app. The magic part of the DateTime structure is that, with minor fiddling, you can make it display the correct DateTime for every single place in the world.

The idea behind DateTime was to provide not a simple Date object, but something you could use to represent dates all over the world, even with different Time Zones. It was made thinking in global applications, and thus it was designed with a bunch of extra functionalities that may not have apparent utility at first glance, but nevertheless can save a lot of time from people developing applications that will have to deal with variable time zones.

It is far from perfect, yes, but it does what it was meant for - representing Time in a universal, and somewhat portable, way.

So, in a sense, when using C# you are forced to consider times when developing your app, not only dates. And, really, that's a good thing - a DateTime is a reference point in time relative to something, and when you change your point of reference, the value for that DateTime must act accordingly.

To be totally fair, I think C# is one of the languages that got this thing right. You can have a Time interval without a date (TimeSpan is there for that), but you can't really have a meaningful date on a global scope without a reference frame and a time attached to it. I didn't like DateTime at all when I first met the language, but after having to develop an App with multiple timezones I understood why this design choice was actually a smart one.

28
  • 2
    @JohnWu Dates are not expressed in discrete parts - you don't have a "Day" component, a "Month" component and a "Year" component. You have just a "Ticks" component which derives the rest. Dates are represented in memory using a long, so you can't have a null time - you don't have a separate time component.
    – T. Sar
    Commented Mar 27, 2017 at 20:58
  • 12
    So, is a person born in Canberra, Australia on 2017-03-28 younger than a person born in Phoenix, AZ, USA on 2017-03-27? It depends on the time, and the timezone, because even plain-old-dates can be complicated. The use-case space for date-only data types is actually very very small, perhaps too small to warrant their own data type, when you can already do everything you need to with the DateTime class.
    – Eric King
    Commented Mar 27, 2017 at 21:50
  • 3
    @Eric: Seems to me the best solution is to store what the user entered. He entered a date. He didn't intend to imply a time as well. The only way to "fix" this with a DateTime is to accompany it with data about the user's browser's time zone; it is not possible with the DateTime alone. Or to pass the date as, say, an ISO-8601 date string, which makes me cringe.
    – John Wu
    Commented Mar 27, 2017 at 22:36
  • 4
    @Tsar: Then when he signs on again in London his date of birth will be off by a day. Nope.
    – John Wu
    Commented Mar 28, 2017 at 16:47
  • 3
    @CrouchingKitten You are mistaken. I do work right in the middle of data processing, and worked for almost five years in banking software. Date1 and Date2 are comparable between timezones because they are never stored as dates, but offsets of ticks. The "yyyy-mm-dd" format is just a human readable thing, not how they are stored down in the metal.
    – T. Sar
    Commented Jan 19, 2020 at 23:18
8

There isn't such a class in the CLR standard libraries, but there is often a need for such a thing, for the reasons you have identified and others.

You can import the "Noda" library for C# and use LocalDate to represent a date without a specific time.

This class is based on a similar class from the Java library "Joda", which was found to be so useful and well written that it has now been imported into the Java standard libraries: LocalDate

When converting from a LocalDate (without a time) to a standard DateTime (with a time component), the library forces you to make your assumptions explicit, so it avoids all kinds of edge cases and mistakes that you have identified in your question and in the discussion on T. Sar's answer

1
  • 2
    This is an constructive answer that provided useful alternative if you need to represent a "Date-only" information for some scenarios, even if it's clear from other answers that a Date only is completely ambiguous and is not a clear point or interval in time.
    – Pac0
    Commented Feb 1, 2019 at 13:58
7

Anthony Moore provides a blog entry with some historical notes specifically on DateTime, including a discussion of the sorts of problems that Microsoft was attempting to solve. It's a bit old, but still it provides some insight.

Most of the article is dedicated to dealing with time zone issues and backward compatibility issues. It appears that throughout the history of .NET versions, Microsoft realized that the problem space is very complex and everything they did seems to be a result of a desire for compromise between feature richness and simplicity. Here is an interesting bit which seems to speak to (very briefly) the problem of a date-only representation:

First, consider the landscape of date and time related scenarios:

A. Legacy DateTime Interop (databases, COM, Win32, etc).

B. Abstract DateTime scenarios (e.g. store starting time).

C. Date-only scenarios.

D. Time-only scenarios.

E. Absolute time scenarios. (e.g. file time).

F. Server scenarios with dates from multiple time zones where the original local time must be retained.

Scenarios C-D might be even better handled by dedicated Date and Time types. These options are still on the table, although they will not be in the .NET 3.5 release.

So it seems they did consider a Date data type and it was still on the table when this blog was written. A bit more explanation can be found elsewhere in the article:

There was a lot of desire to keep the type system simple, and while a time zone aware DateTime was better at representing absolute points in time such as a file time-stamp, it got awkward when doing certain things....Representing whole dates, e.g. the type for a calendar control to return. Obviously a “Date” type is an even better way of representing this, and many people have asked for separate Date and Time types, but in V1.0 there was a desire to keep the number of base types small to limit complexity of the platform. This feature request is definitely still on the table, although not planned for .NET 3.5

So I think the answer is... yes, they did think about it... no, they haven't done it yet, because it raises certain problems and there is a desire to keep the overall platform simple.

Meanwhile, they have released the newer DateTimeOffset structure, which addresses some of the time zone issues. But not any date-only issue. Hopefully the date-only issues will be next up for consideration.

UPDATE:

.NET 6 introduces the TimeOnly and DateOnly data types which directly address this problem. See How to use the DateOnly and TimeOnly structures.

3
  • Interesting historical question and answer especially given that ultimately, it appears that MS accepted that Dates without a time component are useful. The old conversations with much denial that dates can be meaningful without time are interesting as well. An associated concern is that you might actually want to avoid using universal times in some scenarios where time does matter. I read about a system which stored conference schedules using UTC. Between scheduling and the event, there was a change to the timezone where the conference was held, and the schedules were all off by an hour.
    – JimmyJames
    Commented May 17 at 18:44
  • @JimmyJames, I often find that months are useful without a day component! And in the payroll department, their years and months start 06-Apr. And my birthday is ultimately a yearday without the year. Different granularities, different phasing, and a difference between recording a single event and a pattern of recurrence. And as with the timezones, people don't realise that the phasing of the clock is highly conventional and under the local political control of states - in 100 years, British time (hardly a tin-pot place) has changed a number of times. There's a lot of complexity with time.
    – Steve
    Commented May 18 at 8:26
  • @Steve Right. And a lot of laws and contracts specify dates without regard to time. Trying to use datetimes as dates has been a recipe for bugs in my experience.
    – JimmyJames
    Commented May 19 at 16:13
0

Handling dates is tricky. Sometimes a day is the interval from midnight to midnight. Sometimes it is an abstract date. On the London bus time table, days are from 3am local time to 3am local time (so you don’t need two day tickets if you travel home after midnight).

If you have a date with no time then you could have another data type, or let dates be exactly at midnight POSIX time, it doesn’t make a difference. You just need to be aware what rules apply to a “date”.

-1

Yes C# properties can be attributed to just emit the date:

[XmlElement("EndDt", DataType = "date", IsNullable = true)]
public DateTime? EndDate { get; set; }


public bool ShouldSerializeEndDate()
{
    return EndDate.HasValue;
}

To avoid time zone issues use UTC dates.

If you want just the date in code use EndDate.Date.

1
  • 2
    This doesn't answer the question.
    – T. Sar
    Commented Mar 27, 2017 at 20:16

Not the answer you're looking for? Browse other questions tagged or ask your own question.