C# DateOnly and TimeOnly Structure

Kailash Chandra Behera | Saturday, September 09, 2023

Introduction

.Net Framework provides DateTime class to declare variables for storing date and time values. But developer suffered a bit problem when they want to store date part by diregarding the time and vice versa. To overcome this .Net 6 provides DateOnly and TimeOnly structure to store date and time value separately. Here in this blog post we will explore the C# DateOnly and TimeOnly structures.

Getting Started

DateOnly and TimeOnly DataTypes stores Date and time of the day separately, Both the datatypes are introduced in .Net 6. If you work on the SQL server, it is same as SQL server Date and Time Datatypes which are used to store Date and time value of the day separately.

In .Net Framework developers used the DateTime type to store a whole date with time or date with disregarding the time or time with disregarding the date. To separate or extract the date value or time value from datatype DateTime, developer is required to use string format as below.

DateTime Format (Dates and Times)

Format Result
DateTime.Now.ToString("MM/dd/yyyy") 05/09/2023
DateTime.Now.ToString("dddd, dd MMMM yyyy") Saturday, 09 September 2023
DateTime.Now.ToString("dddd, dd MMMM yyyy") Saturday, 09 September 2023 05:50
DateTime.Now.ToString("dddd, dd MMMM yyyy") Saturday, 09 September 2023 05:50 AM
DateTime.Now.ToString("dddd, dd MMMM yyyy") Saturday, 09 September 2023 5:50
DateTime.Now.ToString("dddd, dd MMMM yyyy") Saturday, 09 September 2023 5:50 AM
DateTime.Now.ToString("dddd, dd MMMM yyyy HH:mm:ss") Saturday, 09 September 2023 05:50:06
DateTime.Now.ToString("MM/dd/yyyy HH:mm") 05/09/2023 05:50
DateTime.Now.ToString("MM/dd/yyyy hh:mm tt") 05/09/2023 05:50 AM
DateTime.Now.ToString("MM/dd/yyyy H:mm") 05/09/2023 5:50
DateTime.Now.ToString("MM/dd/yyyy h:mm tt") 05/09/2023 5:50 AM
DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") 05/09/2023 05:50:06
DateTime.Now.ToString("MMMM dd") September 09
DateTime.Now.ToString("yyyy’-‘MM’-‘dd’T’HH’:’mm’:’ss.fffffffK") 2023-05-16T05:50:06.7199222-04:00
DateTime.Now.ToString("ddd, dd MMM yyy HH’:’mm’:’ss ‘GMT’") Sat, 09 September 2023 05:50:06 GMT
DateTime.Now.ToString("yyyy’-‘MM’-‘dd’T’HH’:’mm’:’ss") 2023-08-09T05:50:06
DateTime.Now.ToString("HH:mm") 05:50
DateTime.Now.ToString("hh:mm tt") 05:50 AM
DateTime.Now.ToString("H:mm") 5:50
DateTime.Now.ToString("h:mm tt") 5:50 AM
DateTime.Now.ToString("HH:mm:ss") 05:50:06
DateTime.Now.ToString("yyyy MMMM") 2023 September

The above examples describe that to store date value and time value from DateTime types, developers need to declare two more string variables. DateOnly and TimeOnly are types that represent those portions of a DateTime type.

C# DateOnly

The DateOnly type is introduced in .Net 6 which represents specific date, without time. It has a range from 0001-01-01 through 9999-12-31, just like DateTime. Since it has no time component, it represents a date from the start of the day to the end of the day. This structure is ideal for storing specific dates, such as a birth date, an anniversary date, or business-related dates.

Benefits of using C# DateOnly

  • The DateTime structure may roll into the previous or next day if it's offset by a time zone. DateOnly can't be offset by a time zone, and it always represents the date that was set.

  • Serializing a DateTime structure includes the time component, which may obscure the intent of the data. Also, DateOnly serializes less data.

  • When code interacts with a database, such as SQL Server, whole dates are generally stored as the date data type, which doesn't include a time. DateOnly matches the database type better.

DateOnly examples

The following example demonstrates how to create instances of DateOnly structure, add or subtract days, months or years, parse or format and compare the type.

Declaration

 //Creates a new instance of the DateOnly structure to the specified year, month, and day.  
 DateOnly dateOnly = new DateOnly(2023, 09, 05);  
 Console.WriteLine("Date is " + dateOnly);  
 //Creates a new instance of the DateOnly structure to the specified year, month, and day for the specified calendar.  
 var hebrewCalendar = new System.Globalization.HebrewCalendar();  
 var theDate = new DateOnly(5776, 2, 8, hebrewCalendar); // 8 Cheshvan 5776  
 Console.WriteLine("Date is " + theDate);  
 
 /* This example produces the following output:  
  * 09/05/2023  
  * 10/21/2015  
 */  

Convert DateTime to DateOnly

 var today = DateOnly.FromDateTime(DateTime.Now);  
 Console.WriteLine($"Today is {today}");  
 
 /* This example produces output similar to the following:  
  *   
  * Today is 09/09/2023  
 */  

Add or Subtract (Days, Months, Years)

 DateOnly dateOnly = new DateOnly(2023, 09, 07);  
 var nextDay = dateOnly.AddDays(1);  
 var previousDay = dateOnly.AddDays(-1);  
 var decadeLater = dateOnly.AddYears(10);  
 var lastMonth = dateOnly.AddMonths(-1);  
 Console.WriteLine($"Date: {dateOnly}");  
 Console.WriteLine($" Next day: {nextDay}");  
 Console.WriteLine($" Previous day: {previousDay}");  
 Console.WriteLine($" Decade later: {decadeLater}");  
 Console.WriteLine($" Last month: {lastMonth}");  
 
 /*This example produces the following output:  
  Date: 07-09-2023  
  Next day: 08-09-2023  
  Previous day: 06-09-2023  
  Decade later: 07-09-2033  
  Last month: 07-08-2023  
 */  

Parse and format DateOnly

 using System.Globalization;  
 var dateOnly = DateOnly.ParseExact("06 Sep 2023", "dd MMM yyyy", CultureInfo.InvariantCulture); // Custom format  
 var dateOnly2 = DateOnly.Parse("September 7, 2023", CultureInfo.InvariantCulture);  
 Console.WriteLine(dateOnly.ToString("m", CultureInfo.InvariantCulture));   // Month day pattern  
 Console.WriteLine(dateOnly2.ToString("o", CultureInfo.InvariantCulture));  // ISO 8601 format  
 Console.WriteLine(dateOnly2.ToLongDateString());  
 
 /* This example produces the following output:  
   September 06  
   2023-09-07  
   07 September 2023  
 */  

Compare DateOnly

 using System.Globalization;  
 var dateOnly = DateOnly.ParseExact("06 Sep 2023", "dd MMM yyyy", CultureInfo.InvariantCulture); // Custom format  
 var dateOnly2 = DateOnly.Parse("September 7, 2023", CultureInfo.InvariantCulture);  
 var dateLater = dateOnly.AddMonths(6);  
 var dateBefore = dateOnly.AddDays(-10);  
 Console.WriteLine($"Consider {dateOnly}...");  
 Console.WriteLine($" Is '{nameof(dateOnly2)}' equal? {dateOnly == dateOnly2}");  
 Console.WriteLine($" Is {dateLater} after? {dateLater > dateOnly} ");  
 Console.WriteLine($" Is {dateLater} before? {dateLater < dateOnly} ");  
 Console.WriteLine($" Is {dateBefore} after? {dateBefore > dateOnly} ");  
 Console.WriteLine($" Is {dateBefore} before? {dateBefore < dateOnly} ");  
 
 /*  This example produces the following output:
  Consider 06-09-2023...  
  Is 'dateOnly2' equal? False  
  Is 06-03-2024 after? True  
  Is 06-03-2024 before? False  
  Is 27-08-2023 after? False  
  Is 27-08-2023 before? True  
 */  

TimeOnly

The TimeOnly structure represents a time-of-day value, such as a daily alarm clock or what time you eat lunch each day. TimeOnly is limited to the range of 00:00:00.0000000 - 23:59:59.9999999, a specific time of day.

Benefits of using C# DateOnly

  • TimeSpan represents elapsed time, such as time measured with a stopwatch. The upper range is more than 29,000 years, and its value can be negative to indicate moving backwards in time. A negative TimeSpan doesn't indicate a specific time of the day.

  • If TimeSpan is used as a time of day, there's a risk that it could be manipulated to a value outside of the 24-hour day. TimeOnly doesn't have this risk. For example, if an employee's work shift starts at 18:00 and lasts for 8 hours, adding 8 hours to the TimeOnly structure rolls over to 2:00

  • Using DateTime for a time of day requires that an arbitrary date be associated with the time, and then later disregarded. It's common practice to choose DateTime.MinValue (0001-01-01) as the date, however, if hours are subtracted from the DateTime value, an OutOfRange exception might occur. TimeOnly doesn't have this problem as the time rolls forwards and backwards around the 24-hour timeframe.

  • Serializing a DateTime structure includes the date component, which may obscure the intent of the data. Also, TimeOnly serializes less data.

Declaration

 
  //Initializes a new instance of the TimeOnly structure using a specified number of ticks.  
 TimeOnly timeOnly = new TimeOnly(23,28);  
 Console.WriteLine($"Time: {timeOnly}");  
 //Initializes a new instance of the TimeOnly structure to the specified hour, minute, and second.  
 TimeOnly timeOnly = new TimeOnly(23,28,30);  
 Console.WriteLine($"Time: {timeOnly}");  
 //Initializes a new instance of the TimeOnly structure to the specified hour, minute, second, and millisecond.  
 TimeOnly timeOnly = new TimeOnly(23,28,30,100);  
 Console.WriteLine($"Time: {timeOnly}");  
 
 /* This example produces output similar to the following:  
   Time: 11.28 PM  
      Time: 11.28 30 PM  
 */  

Convert DateTime to DateOnly

 var now = TimeOnly.FromDateTime(DateTime.Now);  
 Console.WriteLine($"It is {now} right now");  
 
 /* This example produces output similar to the following:  
  *   
  * It is 2:01 PM right now  
 */  

Add or Subtract Time

 TimeOnly timeOnly = new TimeOnly(23,28);  
 var hourLater = timeOnly.AddHours(1);  
 var minutesBefore = timeOnly.AddMinutes(-12);  
 var secondsAfter = timeOnly.Add(TimeSpan.FromSeconds(10));  
 var daysLater = timeOnly.Add(new TimeSpan(hours: 21, minutes: 200, seconds: 83), out int wrappedDays);  
 var daysBehind = timeOnly.AddHours(-222, out int wrappedDaysFromHours);  
 Console.WriteLine($"Time: {timeOnly}");  
 Console.WriteLine($" Hours later: {hourLater}");  
 Console.WriteLine($" Minutes before: {minutesBefore}");  
 Console.WriteLine($" Seconds after: {secondsAfter}");  
 Console.WriteLine($" {daysLater} is the time, which is {wrappedDays} days later");  
 Console.WriteLine($" {daysBehind} is the time, which is {wrappedDaysFromHours} days prior");  
 /* This example produces the following output:  
   Time: 11.28 PM  
   Hours later: 12.28 AM  
   Minutes before: 11.16 PM  
   Seconds after: 11.28 PM  
   11.49 PM is the time, which is 1 days later  
   05.28 PM is the time, which is -9 days prior  
 */  

Parse and format DateOnly

 var timeOnly = TimeOnly.ParseExact("5:00 pm", "h:mm tt", CultureInfo.InvariantCulture); // Custom format  
 var timeOnly2 = TimeOnly.Parse("17:30:25", CultureInfo.InvariantCulture);  
 Console.WriteLine(timeOnly.ToString("o", CultureInfo.InvariantCulture));   // Round-trip pattern.  
 Console.WriteLine(timeOnly2.ToString("t", CultureInfo.InvariantCulture));  // Long time format  
 Console.WriteLine(timeOnly2.ToLongTimeString());  
 /* This example produces the following output:  
  *   
  * 17:00:00.0000000  
  * 17:30  
  * 5:30:25 PM  
 */  

Summary

I hope the information provided in this blog post C# DateOnly and TimeOnly Structure is helpful to you.

Thanks


No comments: