A Peek Into .NET 6's DateOnly And TimeOnly Structure

If there was a poll to find that one little feature every C# developer would love to have in .Net, then it is most likely the ability to store Date and Time individually. For years now, we had to use DateTime to represent Date when the Time part of the object had to be ignored. The same thing happened when we wanted to save time and had to ignore the Date of the DateTime component.
And with .Net 6, that long agonizing wait has come to an end. .Net 6 has now introduced DateOnly and TimeOnly Structures which could store Date and Time components.


The DateOnly structure allows you to save a Date property with a more explicit structure rather than using the DateTime and ignoring the Time part.
  1. var dateOnlyFirst = new DateOnly(2020, 2, 16);  
  2. var dateOnlySecond = DateOnly.FromDateTime(DateTime.Now);  
  3. Console.WriteLine(dateOnlyFirst);  
  4. Console.WriteLine(dateOnlySecond);  
  5. // Output  
  6. 16-02-2020  
  7. 04-06-2021  
We could create the instance either using the Constructors or static helper methods like DateOnly.FromDateTime. It is also interesting to know what happens behinds the scenes. Internally, the DateOnly structure stores the value in an Int32 field that represents the number of days since 1/1/0001. The field is designed to store values from 1 Jan,0001 to 31st Dec 9999. If you take a glimpse of code in the .Net Github source code for DateOnly, you could find some of the following,
  1. private readonly int _dayNumber;  
  2. // Maps to Jan 1st year 1  
  3. private const int MinDayNumber = 0;  
  4. // Maps to December 31 year 9999. The value calculated from "new DateTime(9999, 12, 31).Ticks / TimeSpan.TicksPerDay"  
  5. private const int MaxDayNumber = 3_652_058;  
  6. public DateOnly(int year, int month, int day) => _dayNumber = DayNumberFromDateTime(new DateTime(year, month, day));  
  7. public static DateOnly FromDateTime(DateTime dateTime) => new DateOnly(DayNumberFromDateTime(dateTime));  
  8. private static int DayNumberFromDateTime(DateTime dt) => (int)(dt.Ticks / TimeSpan.TicksPerDay);  
The DateOnly provides most of the (applicable) functionality that DateTime provides including AddDays(),AddMonths(),AddYears, ParseExact and many more.


TimeOnly Quite similar to DateOnly, the TimeOnly structure provides a way to represent the Time component effectively in .Net.
  1. var timeOnlyFirst = new TimeOnly(10,10,10);  
  2. var timeOnlySecond = TimeOnly.FromDateTime(DateTime.Now);  
  3. Console.WriteLine(timeOnlyFirst);  
  4. Console.WriteLine(timeOnlySecond);  
  5. //Output  
  6. 10:10  
  7. 05:35  
Internally, TimeOnly uses a long to represent the ticks elapsed since midnight. Let us know to take a glimpse of the internal code of TimeOnly.
  1.  // represent the number of ticks map to the time of the day. 1 ticks = 100-nanosecond in time measurements.  
  2. private readonly long _ticks;  
  3. // MinTimeTicks is the ticks for the midnight time 00:00:00.000 AM  
  4. private const long MinTimeTicks = 0;  
  5. // MaxTimeTicks is the max tick value for the time in the day. It is calculated using DateTime.Today.AddTicks(-1).TimeOfDay.Ticks.  
  6. private const long MaxTimeTicks = 863_999_999_999;  
  7. public TimeOnly(int hour, int minute, int second) : this(DateTime.TimeToTicks(hour, minute, second, 0)) {}  
  8. public TimeOnly(long ticks)  
  9.    {  
  10.       if ((ulong)ticks > MaxTimeTicks)  
  11.       {  
  12.          throw new ArgumentOutOfRangeException(nameof(ticks), SR.ArgumentOutOfRange_TimeOnlyBadTicks);  
  13.       }  
  14.    _ticks = ticks;  
  15. }  
As with the DateOnly structure, the TimeOnly too comes in with a lot of helper methods that would aid the developer.
It is quite safe to assume that a lot of developers would be quite happy with the introduction of these structures. These would definitely improve the code base a lot and make the representations more explicit, rather than using DateTime and ignoring a part of it.