.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.
C# DateOnly and TimeOnly Structure
Getting StartedDateOnly 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.
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# TimeOnly
- 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.
TimeOnly Examples
The following example demonstrates how to create instances of TimeOnly structure, add or parse or format and compare the type.
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