Skip to main content

4.6 - Date and Time Manipulation

Working with dates and times is a common requirement in many applications. C# provides several types for representing and manipulating dates and times, including DateTime, DateTimeOffset, and TimeSpan. This chapter explores these types and their capabilities.

4.6.1 - DateTime and DateTimeOffset

The DateTime and DateTimeOffset structs are the primary types for working with dates and times in C#.

4.6.1.1 - Creating DateTime Objects

There are several ways to create DateTime objects:

Example:

using System;

class Program
{
static void Main()
{
// Create DateTime objects

// Current date and time
DateTime now = DateTime.Now;
Console.WriteLine($"Current date and time: {now}");

// Current UTC date and time
DateTime utcNow = DateTime.UtcNow;
Console.WriteLine($"Current UTC date and time: {utcNow}");

// Today's date (with time set to 00:00:00)
DateTime today = DateTime.Today;
Console.WriteLine($"Today's date: {today}");

// Specific date and time
DateTime specificDateTime = new DateTime(2023, 12, 31, 23, 59, 59);
Console.WriteLine($"Specific date and time: {specificDateTime}");

// Date only (time is set to 00:00:00)
DateTime dateOnly = new DateTime(2023, 12, 31);
Console.WriteLine($"Date only: {dateOnly}");

// Create from ticks (ticks are 100-nanosecond intervals since January 1, 0001)
DateTime fromTicks = new DateTime(636503616000000000);
Console.WriteLine($"From ticks: {fromTicks}");

// Create from string
DateTime fromString = DateTime.Parse("2023-12-31 23:59:59");
Console.WriteLine($"From string: {fromString}");
}
}

4.6.1.2 - DateTime Properties

The DateTime struct provides several properties for accessing different components of a date and time:

Example:

using System;

class Program
{
static void Main()
{
DateTime dt = new DateTime(2023, 12, 31, 23, 59, 59, 500);

// Date components
Console.WriteLine($"Year: {dt.Year}");
Console.WriteLine($"Month: {dt.Month}");
Console.WriteLine($"Day: {dt.Day}");
Console.WriteLine($"Day of week: {dt.DayOfWeek}");
Console.WriteLine($"Day of year: {dt.DayOfYear}");

// Time components
Console.WriteLine($"Hour: {dt.Hour}");
Console.WriteLine($"Minute: {dt.Minute}");
Console.WriteLine($"Second: {dt.Second}");
Console.WriteLine($"Millisecond: {dt.Millisecond}");

// Other properties
Console.WriteLine($"Ticks: {dt.Ticks}");
Console.WriteLine($"Kind: {dt.Kind}");

// Date and time parts
Console.WriteLine($"Date: {dt.Date}");
Console.WriteLine($"TimeOfDay: {dt.TimeOfDay}");
}
}

4.6.1.3 - DateTime Methods

The DateTime struct provides methods for manipulating dates and times:

Example:

using System;

class Program
{
static void Main()
{
DateTime dt = new DateTime(2023, 1, 1);

// Adding and subtracting time
DateTime tomorrow = dt.AddDays(1);
DateTime nextWeek = dt.AddDays(7);
DateTime nextMonth = dt.AddMonths(1);
DateTime nextYear = dt.AddYears(1);
DateTime threeHoursLater = dt.AddHours(3);
DateTime twoMinutesLater = dt.AddMinutes(2);

Console.WriteLine($"Original date: {dt}");
Console.WriteLine($"Tomorrow: {tomorrow}");
Console.WriteLine($"Next week: {nextWeek}");
Console.WriteLine($"Next month: {nextMonth}");
Console.WriteLine($"Next year: {nextYear}");
Console.WriteLine($"Three hours later: {threeHoursLater}");
Console.WriteLine($"Two minutes later: {twoMinutesLater}");

// Combining Add methods
DateTime combined = dt.AddYears(1).AddMonths(1).AddDays(1);
Console.WriteLine($"One year, one month, and one day later: {combined}");

// Subtracting dates
DateTime now = DateTime.Now;
DateTime pastDate = new DateTime(2020, 1, 1);

TimeSpan difference = now - pastDate;
Console.WriteLine($"Time since January 1, 2020: {difference.Days} days");

// Comparing dates
DateTime date1 = new DateTime(2023, 1, 1);
DateTime date2 = new DateTime(2023, 12, 31);

Console.WriteLine($"date1 < date2: {date1 < date2}");
Console.WriteLine($"date1 > date2: {date1 > date2}");
Console.WriteLine($"date1 == date2: {date1 == date2}");

// Compare method
int compareResult = date1.CompareTo(date2);
Console.WriteLine($"Compare result: {compareResult}");

// Checking if a year is a leap year
bool isLeapYear = DateTime.IsLeapYear(2024);
Console.WriteLine($"Is 2024 a leap year? {isLeapYear}");

// Getting the number of days in a month
int daysInMonth = DateTime.DaysInMonth(2023, 2);
Console.WriteLine($"Days in February 2023: {daysInMonth}");
}
}

4.6.1.4 - DateTimeOffset

The DateTimeOffset struct represents a date and time with an offset from UTC:

Example:

using System;

class Program
{
static void Main()
{
// Create DateTimeOffset objects

// Current date and time with local offset
DateTimeOffset now = DateTimeOffset.Now;
Console.WriteLine($"Current date and time with offset: {now}");

// Current UTC date and time
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
Console.WriteLine($"Current UTC date and time: {utcNow}");

// Specific date and time with offset
DateTimeOffset specificWithOffset = new DateTimeOffset(2023, 12, 31, 23, 59, 59, TimeSpan.FromHours(-5));
Console.WriteLine($"Specific date and time with offset: {specificWithOffset}");

// Create from DateTime
DateTime dt = new DateTime(2023, 12, 31, 23, 59, 59);
DateTimeOffset fromDateTime = new DateTimeOffset(dt);
Console.WriteLine($"From DateTime: {fromDateTime}");

// Properties specific to DateTimeOffset
Console.WriteLine($"Offset: {now.Offset}");
Console.WriteLine($"DateTime: {now.DateTime}");
Console.WriteLine($"LocalDateTime: {now.LocalDateTime}");
Console.WriteLine($"UtcDateTime: {now.UtcDateTime}");

// Converting between time zones
DateTimeOffset eastern = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.FromHours(-5));
DateTimeOffset pacific = eastern.ToOffset(TimeSpan.FromHours(-8));

Console.WriteLine($"Eastern time: {eastern}");
Console.WriteLine($"Pacific time: {pacific}");
}
}

4.6.1.5 - When to Use DateTime vs. DateTimeOffset

Guidelines for choosing between DateTime and DateTimeOffset:

Example:

using System;

class Program
{
static void Main()
{
// DateTime is suitable for:
// 1. Local date and time operations
// 2. When time zone is not important
// 3. When working with database systems that don't support offset

// Example: Local application that doesn't deal with different time zones
DateTime localAppointment = new DateTime(2023, 12, 31, 14, 30, 0, DateTimeKind.Local);
Console.WriteLine($"Local appointment: {localAppointment}");

// DateTimeOffset is suitable for:
// 1. Storing date and time with a specific offset
// 2. Working with different time zones
// 3. Preserving the original time zone information

// Example: Tracking events across different time zones
DateTimeOffset eventInNewYork = new DateTimeOffset(2023, 12, 31, 0, 0, 0, TimeSpan.FromHours(-5));
DateTimeOffset eventInLondon = new DateTimeOffset(2023, 12, 31, 0, 0, 0, TimeSpan.FromHours(0));
DateTimeOffset eventInTokyo = new DateTimeOffset(2023, 12, 31, 0, 0, 0, TimeSpan.FromHours(9));

Console.WriteLine($"Event in New York: {eventInNewYork}");
Console.WriteLine($"Event in London: {eventInLondon}");
Console.WriteLine($"Event in Tokyo: {eventInTokyo}");

// Converting all events to UTC for comparison
Console.WriteLine($"New York event in UTC: {eventInNewYork.UtcDateTime}");
Console.WriteLine($"London event in UTC: {eventInLondon.UtcDateTime}");
Console.WriteLine($"Tokyo event in UTC: {eventInTokyo.UtcDateTime}");

// Comparing events
Console.WriteLine($"New York event is before London event: {eventInNewYork < eventInLondon}");
Console.WriteLine($"London event is before Tokyo event: {eventInLondon < eventInTokyo}");
}
}

4.6.2 - TimeSpan

The TimeSpan struct represents a time interval (duration) that is the difference between two dates or times.

4.6.2.1 - Creating TimeSpan Objects

There are several ways to create TimeSpan objects:

Example:

using System;

class Program
{
static void Main()
{
// Create TimeSpan objects

// From hours, minutes, and seconds
TimeSpan ts1 = new TimeSpan(2, 30, 45); // 2 hours, 30 minutes, 45 seconds
Console.WriteLine($"TimeSpan from hours, minutes, seconds: {ts1}");

// From days, hours, minutes, seconds
TimeSpan ts2 = new TimeSpan(1, 2, 30, 45); // 1 day, 2 hours, 30 minutes, 45 seconds
Console.WriteLine($"TimeSpan from days, hours, minutes, seconds: {ts2}");

// From days, hours, minutes, seconds, milliseconds
TimeSpan ts3 = new TimeSpan(1, 2, 30, 45, 500); // 1 day, 2 hours, 30 minutes, 45 seconds, 500 milliseconds
Console.WriteLine($"TimeSpan from days, hours, minutes, seconds, milliseconds: {ts3}");

// From ticks
TimeSpan ts4 = new TimeSpan(10000000); // 1 second (10,000,000 ticks)
Console.WriteLine($"TimeSpan from ticks: {ts4}");

// Using static methods
TimeSpan fromDays = TimeSpan.FromDays(1.5);
TimeSpan fromHours = TimeSpan.FromHours(2.5);
TimeSpan fromMinutes = TimeSpan.FromMinutes(150);
TimeSpan fromSeconds = TimeSpan.FromSeconds(3600);
TimeSpan fromMilliseconds = TimeSpan.FromMilliseconds(5000);

Console.WriteLine($"From days: {fromDays}");
Console.WriteLine($"From hours: {fromHours}");
Console.WriteLine($"From minutes: {fromMinutes}");
Console.WriteLine($"From seconds: {fromSeconds}");
Console.WriteLine($"From milliseconds: {fromMilliseconds}");

// From string
TimeSpan fromString = TimeSpan.Parse("1:02:30:45");
Console.WriteLine($"From string: {fromString}");
}
}

4.6.2.2 - TimeSpan Properties

The TimeSpan struct provides properties for accessing different components of a time interval:

Example:

using System;

class Program
{
static void Main()
{
TimeSpan ts = new TimeSpan(1, 2, 30, 45, 500); // 1 day, 2 hours, 30 minutes, 45 seconds, 500 milliseconds

// Properties
Console.WriteLine($"Days: {ts.Days}");
Console.WriteLine($"Hours: {ts.Hours}");
Console.WriteLine($"Minutes: {ts.Minutes}");
Console.WriteLine($"Seconds: {ts.Seconds}");
Console.WriteLine($"Milliseconds: {ts.Milliseconds}");
Console.WriteLine($"Ticks: {ts.Ticks}");

// Total properties
Console.WriteLine($"Total days: {ts.TotalDays}");
Console.WriteLine($"Total hours: {ts.TotalHours}");
Console.WriteLine($"Total minutes: {ts.TotalMinutes}");
Console.WriteLine($"Total seconds: {ts.TotalSeconds}");
Console.WriteLine($"Total milliseconds: {ts.TotalMilliseconds}");
}
}

4.6.2.3 - TimeSpan Operations

The TimeSpan struct supports various operations:

Example:

using System;

class Program
{
static void Main()
{
TimeSpan ts1 = new TimeSpan(1, 0, 0); // 1 hour
TimeSpan ts2 = new TimeSpan(0, 30, 0); // 30 minutes

// Addition
TimeSpan sum = ts1 + ts2;
Console.WriteLine($"{ts1} + {ts2} = {sum}");

// Subtraction
TimeSpan difference = ts1 - ts2;
Console.WriteLine($"{ts1} - {ts2} = {difference}");

// Multiplication
TimeSpan doubled = ts1 * 2;
Console.WriteLine($"{ts1} * 2 = {doubled}");

// Division
TimeSpan halved = ts1 / 2;
Console.WriteLine($"{ts1} / 2 = {halved}");

// Negation
TimeSpan negated = -ts1;
Console.WriteLine($"-{ts1} = {negated}");

// Comparison
Console.WriteLine($"{ts1} < {ts2}: {ts1 < ts2}");
Console.WriteLine($"{ts1} > {ts2}: {ts1 > ts2}");
Console.WriteLine($"{ts1} == {ts2}: {ts1 == ts2}");

// Static properties
Console.WriteLine($"TimeSpan.Zero: {TimeSpan.Zero}");
Console.WriteLine($"TimeSpan.MinValue: {TimeSpan.MinValue}");
Console.WriteLine($"TimeSpan.MaxValue: {TimeSpan.MaxValue}");
}
}

4.6.2.4 - Using TimeSpan with DateTime

TimeSpan can be used with DateTime for date and time calculations:

Example:

using System;

class Program
{
static void Main()
{
DateTime now = DateTime.Now;

// Adding a TimeSpan to a DateTime
TimeSpan oneDay = TimeSpan.FromDays(1);
DateTime tomorrow = now + oneDay;

Console.WriteLine($"Now: {now}");
Console.WriteLine($"Tomorrow: {tomorrow}");

// Subtracting a TimeSpan from a DateTime
TimeSpan twoHours = TimeSpan.FromHours(2);
DateTime twoHoursAgo = now - twoHours;

Console.WriteLine($"Two hours ago: {twoHoursAgo}");

// Calculating the difference between two DateTimes
DateTime futureDate = new DateTime(2023, 12, 31);
TimeSpan timeUntil = futureDate - now;

Console.WriteLine($"Time until December 31, 2023: {timeUntil.Days} days, {timeUntil.Hours} hours, {timeUntil.Minutes} minutes");

// Using TimeSpan for scheduling
DateTime startTime = DateTime.Now;
TimeSpan duration = TimeSpan.FromHours(1.5);
DateTime endTime = startTime + duration;

Console.WriteLine($"Meeting starts at: {startTime:t}");
Console.WriteLine($"Meeting duration: {duration}");
Console.WriteLine($"Meeting ends at: {endTime:t}");
}
}

4.6.3 - Date Formatting and Parsing

C# provides various ways to format dates and times as strings and to parse strings into date and time values.

4.6.3.1 - Standard Date and Time Format Strings

C# supports standard format specifiers for formatting dates and times:

Example:

using System;

class Program
{
static void Main()
{
DateTime now = DateTime.Now;

// Standard date and time format strings
Console.WriteLine($"d (Short date): {now:d}");
Console.WriteLine($"D (Long date): {now:D}");
Console.WriteLine($"t (Short time): {now:t}");
Console.WriteLine($"T (Long time): {now:T}");
Console.WriteLine($"f (Full date/time, short time): {now:f}");
Console.WriteLine($"F (Full date/time, long time): {now:F}");
Console.WriteLine($"g (General date/time, short time): {now:g}");
Console.WriteLine($"G (General date/time, long time): {now:G}");
Console.WriteLine($"M (Month/day): {now:M}");
Console.WriteLine($"Y (Year/month): {now:Y}");
Console.WriteLine($"O (Round-trip): {now:O}");
Console.WriteLine($"R (RFC1123): {now:R}");
Console.WriteLine($"s (Sortable): {now:s}");
Console.WriteLine($"u (Universal sortable): {now:u}");
}
}

4.6.3.2 - Custom Date and Time Format Strings

Custom format strings provide more control over date and time formatting:

Example:

using System;

class Program
{
static void Main()
{
DateTime now = DateTime.Now;

// Custom date and time format strings
Console.WriteLine($"yyyy-MM-dd: {now:yyyy-MM-dd}");
Console.WriteLine($"MM/dd/yyyy: {now:MM/dd/yyyy}");
Console.WriteLine($"dd/MM/yyyy: {now:dd/MM/yyyy}");
Console.WriteLine($"HH:mm:ss: {now:HH:mm:ss}");
Console.WriteLine($"hh:mm:ss tt: {now:hh:mm:ss tt}");
Console.WriteLine($"yyyy-MM-dd HH:mm:ss: {now:yyyy-MM-dd HH:mm:ss}");
Console.WriteLine($"dddd, MMMM d, yyyy: {now:dddd, MMMM d, yyyy}");
Console.WriteLine($"MM/dd/yyyy h:mm tt: {now:MM/dd/yyyy h:mm tt}");

// Using ToString with custom format
string customFormat = "yyyy-MM-dd HH:mm:ss.fff";
Console.WriteLine($"Custom format: {now.ToString(customFormat)}");
}
}

4.6.3.3 - Parsing Dates and Times

C# provides methods for parsing strings into date and time values:

Example:

using System;
using System.Globalization;

class Program
{
static void Main()
{
// Basic parsing
string dateString1 = "2023-12-31";
DateTime date1 = DateTime.Parse(dateString1);
Console.WriteLine($"Parsed date: {date1}");

// Parsing with specific format
string dateString2 = "31/12/2023";
DateTime date2 = DateTime.ParseExact(dateString2, "dd/MM/yyyy", CultureInfo.InvariantCulture);
Console.WriteLine($"Parsed date with format: {date2}");

// Parsing with multiple formats
string dateString3 = "12/31/2023";
string[] formats = { "MM/dd/yyyy", "dd/MM/yyyy", "yyyy-MM-dd" };
DateTime date3 = DateTime.ParseExact(dateString3, formats, CultureInfo.InvariantCulture, DateTimeStyles.None);
Console.WriteLine($"Parsed date with multiple formats: {date3}");

// TryParse
string validDateString = "2023-12-31";
string invalidDateString = "not a date";

if (DateTime.TryParse(validDateString, out DateTime parsedDate))
{
Console.WriteLine($"Successfully parsed: {parsedDate}");
}
else
{
Console.WriteLine("Failed to parse");
}

if (DateTime.TryParse(invalidDateString, out DateTime parsedInvalidDate))
{
Console.WriteLine($"Successfully parsed: {parsedInvalidDate}");
}
else
{
Console.WriteLine("Failed to parse invalid date");
}

// TryParseExact
string dateWithFormat = "31-Dec-2023";
if (DateTime.TryParseExact(dateWithFormat, "dd-MMM-yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsedExactDate))
{
Console.WriteLine($"Successfully parsed with exact format: {parsedExactDate}");
}
else
{
Console.WriteLine("Failed to parse with exact format");
}
}
}

4.6.3.4 - Culture-Specific Formatting and Parsing

Date and time formatting and parsing can be affected by culture settings:

Example:

using System;
using System.Globalization;

class Program
{
static void Main()
{
DateTime now = DateTime.Now;

// Format using different cultures
CultureInfo[] cultures = {
CultureInfo.GetCultureInfo("en-US"),
CultureInfo.GetCultureInfo("fr-FR"),
CultureInfo.GetCultureInfo("de-DE"),
CultureInfo.GetCultureInfo("ja-JP")
};

Console.WriteLine("Formatting with different cultures:");
foreach (var culture in cultures)
{
Console.WriteLine($"Culture: {culture.DisplayName}");
Console.WriteLine($" Short date: {now.ToString("d", culture)}");
Console.WriteLine($" Long date: {now.ToString("D", culture)}");
Console.WriteLine($" Short time: {now.ToString("t", culture)}");
Console.WriteLine($" Long time: {now.ToString("T", culture)}");
}

// Parsing with culture
string usDateString = "12/31/2023";
string frDateString = "31/12/2023";

DateTime usDate = DateTime.Parse(usDateString, CultureInfo.GetCultureInfo("en-US"));
DateTime frDate = DateTime.Parse(frDateString, CultureInfo.GetCultureInfo("fr-FR"));

Console.WriteLine($"\nParsed US date: {usDate}");
Console.WriteLine($"Parsed French date: {frDate}");
}
}

4.6.4 - Time Zone Handling

Working with time zones is important for applications that deal with users or data from different parts of the world.

4.6.4.1 - TimeZoneInfo Class

The TimeZoneInfo class provides information about time zones and methods for converting between them:

Example:

using System;

class Program
{
static void Main()
{
// Get the local time zone
TimeZoneInfo localZone = TimeZoneInfo.Local;
Console.WriteLine($"Local time zone: {localZone.DisplayName}");
Console.WriteLine($"Standard name: {localZone.StandardName}");
Console.WriteLine($"Daylight name: {localZone.DaylightName}");
Console.WriteLine($"Base UTC offset: {localZone.BaseUtcOffset}");
Console.WriteLine($"Supports daylight saving time: {localZone.SupportsDaylightSavingTime}");

// Get the UTC time zone
TimeZoneInfo utcZone = TimeZoneInfo.Utc;
Console.WriteLine($"\nUTC time zone: {utcZone.DisplayName}");

// Get a specific time zone
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
Console.WriteLine($"\nEastern time zone: {easternZone.DisplayName}");

// List all available time zones
Console.WriteLine("\nAvailable time zones:");
foreach (TimeZoneInfo zone in TimeZoneInfo.GetSystemTimeZones())
{
Console.WriteLine($" {zone.Id}: {zone.DisplayName}");
}
}
}

4.6.4.2 - Converting Between Time Zones

The TimeZoneInfo class provides methods for converting times between different time zones:

Example:

using System;

class Program
{
static void Main()
{
// Get time zones
TimeZoneInfo localZone = TimeZoneInfo.Local;
TimeZoneInfo utcZone = TimeZoneInfo.Utc;
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
TimeZoneInfo pacificZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
TimeZoneInfo tokyoZone = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");

// Current time in local time zone
DateTime localTime = DateTime.Now;
Console.WriteLine($"Local time: {localTime} ({localZone.DisplayName})");

// Convert local time to UTC
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(localTime);
Console.WriteLine($"UTC time: {utcTime}");

// Convert UTC time to Eastern time
DateTime easternTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, easternZone);
Console.WriteLine($"Eastern time: {easternTime} ({easternZone.DisplayName})");

// Convert local time to Pacific time
DateTime pacificTime = TimeZoneInfo.ConvertTime(localTime, localZone, pacificZone);
Console.WriteLine($"Pacific time: {pacificTime} ({pacificZone.DisplayName})");

// Convert local time to Tokyo time
DateTime tokyoTime = TimeZoneInfo.ConvertTime(localTime, localZone, tokyoZone);
Console.WriteLine($"Tokyo time: {tokyoTime} ({tokyoZone.DisplayName})");

// Convert a specific date and time
DateTime newYearsEve = new DateTime(2023, 12, 31, 23, 59, 59);
Console.WriteLine($"\nNew Year's Eve in local time zone: {newYearsEve}");

DateTime newYearsEveUtc = TimeZoneInfo.ConvertTimeToUtc(newYearsEve, localZone);
Console.WriteLine($"New Year's Eve in UTC: {newYearsEveUtc}");

DateTime newYearsEveEastern = TimeZoneInfo.ConvertTime(newYearsEve, localZone, easternZone);
Console.WriteLine($"New Year's Eve in Eastern time: {newYearsEveEastern}");
}
}

4.6.4.3 - Daylight Saving Time

The TimeZoneInfo class provides methods for determining if a specific time is in daylight saving time:

Example:

using System;

class Program
{
static void Main()
{
// Get the Eastern time zone
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

// Check if a time is in daylight saving time
DateTime winterDate = new DateTime(2023, 1, 1);
DateTime summerDate = new DateTime(2023, 7, 1);

bool winterDst = easternZone.IsDaylightSavingTime(winterDate);
bool summerDst = easternZone.IsDaylightSavingTime(summerDate);

Console.WriteLine($"Eastern time zone: {easternZone.DisplayName}");
Console.WriteLine($"January 1, 2023 is in DST: {winterDst}");
Console.WriteLine($"July 1, 2023 is in DST: {summerDst}");

// Get DST information
TimeZoneInfo.AdjustmentRule[] rules = easternZone.GetAdjustmentRules();

Console.WriteLine("\nDST adjustment rules:");
foreach (TimeZoneInfo.AdjustmentRule rule in rules)
{
Console.WriteLine($" From {rule.DateStart.ToShortDateString()} to {rule.DateEnd.ToShortDateString()}");
Console.WriteLine($" Delta: {rule.DaylightDelta}");
Console.WriteLine($" DST start: {rule.DaylightTransitionStart}");
Console.WriteLine($" DST end: {rule.DaylightTransitionEnd}");
Console.WriteLine();
}

// Get the UTC offset for a specific date
TimeSpan winterOffset = easternZone.GetUtcOffset(winterDate);
TimeSpan summerOffset = easternZone.GetUtcOffset(summerDate);

Console.WriteLine($"UTC offset on January 1, 2023: {winterOffset}");
Console.WriteLine($"UTC offset on July 1, 2023: {summerOffset}");
}
}

4.6.4.4 - Working with DateTimeOffset and Time Zones

The DateTimeOffset struct is useful for working with times in different time zones:

Example:

using System;

class Program
{
static void Main()
{
// Create DateTimeOffset objects for different time zones
DateTimeOffset localTime = DateTimeOffset.Now;
DateTimeOffset utcTime = DateTimeOffset.UtcNow;

Console.WriteLine($"Local time: {localTime}");
Console.WriteLine($"UTC time: {utcTime}");

// Create DateTimeOffset with specific offset
DateTimeOffset easternTime = new DateTimeOffset(2023, 12, 31, 23, 59, 59, TimeSpan.FromHours(-5));
Console.WriteLine($"Eastern time: {easternTime}");

// Convert to different offset
DateTimeOffset pacificTime = easternTime.ToOffset(TimeSpan.FromHours(-8));
Console.WriteLine($"Pacific time: {pacificTime}");

// Convert to UTC
DateTimeOffset easternToUtc = easternTime.ToUniversalTime();
Console.WriteLine($"Eastern time in UTC: {easternToUtc}");

// Convert to local time
DateTimeOffset easternToLocal = easternTime.ToLocalTime();
Console.WriteLine($"Eastern time in local time zone: {easternToLocal}");

// Compare DateTimeOffset values
Console.WriteLine($"Eastern time == Pacific time: {easternTime == pacificTime}");
Console.WriteLine($"Eastern time.UtcDateTime == Pacific time.UtcDateTime: {easternTime.UtcDateTime == pacificTime.UtcDateTime}");
}
}

4.6.5 - DateOnly and TimeOnly (C# 10+)

C# 10 introduced the DateOnly and TimeOnly types, which represent just a date or just a time, without the overhead of a full DateTime.

Cross-Reference

For more information about C# 10 features, see Section 7.2.12 - Global Using Directives (C# 10+) and Section 7.2.13 - File-scoped Namespaces (C# 10+) in the Advanced C# Topics chapter.

4.6.5.1 - DateOnly

The DateOnly struct represents a date without a time component:

Example:

using System;

class Program
{
static void Main()
{
// Create DateOnly objects
DateOnly today = DateOnly.FromDateTime(DateTime.Today);
DateOnly specificDate = new DateOnly(2023, 12, 31);

Console.WriteLine($"Today: {today}");
Console.WriteLine($"Specific date: {specificDate}");

// Properties
Console.WriteLine($"Year: {specificDate.Year}");
Console.WriteLine($"Month: {specificDate.Month}");
Console.WriteLine($"Day: {specificDate.Day}");
Console.WriteLine($"Day of week: {specificDate.DayOfWeek}");
Console.WriteLine($"Day of year: {specificDate.DayOfYear}");

// Methods
DateOnly tomorrow = today.AddDays(1);
DateOnly nextMonth = today.AddMonths(1);
DateOnly nextYear = today.AddYears(1);

Console.WriteLine($"Tomorrow: {tomorrow}");
Console.WriteLine($"Next month: {nextMonth}");
Console.WriteLine($"Next year: {nextYear}");

// Comparison
Console.WriteLine($"today < tomorrow: {today < tomorrow}");
Console.WriteLine($"today > tomorrow: {today > tomorrow}");
Console.WriteLine($"today == tomorrow: {today == tomorrow}");

// Convert to DateTime
DateTime dateTime = specificDate.ToDateTime(TimeOnly.MinValue);
Console.WriteLine($"DateOnly to DateTime: {dateTime}");
}
}

4.6.5.2 - TimeOnly

The TimeOnly struct represents a time without a date component:

Example:

using System;

class Program
{
static void Main()
{
// Create TimeOnly objects
TimeOnly currentTime = TimeOnly.FromDateTime(DateTime.Now);
TimeOnly specificTime = new TimeOnly(14, 30, 0); // 2:30 PM

Console.WriteLine($"Current time: {currentTime}");
Console.WriteLine($"Specific time: {specificTime}");

// Properties
Console.WriteLine($"Hour: {specificTime.Hour}");
Console.WriteLine($"Minute: {specificTime.Minute}");
Console.WriteLine($"Second: {specificTime.Second}");
Console.WriteLine($"Millisecond: {specificTime.Millisecond}");
Console.WriteLine($"Ticks: {specificTime.Ticks}");

// Methods
TimeOnly later = specificTime.AddHours(2);
TimeOnly earlier = specificTime.AddMinutes(-30);

Console.WriteLine($"2 hours later: {later}");
Console.WriteLine($"30 minutes earlier: {earlier}");

// Comparison
Console.WriteLine($"specificTime < later: {specificTime < later}");
Console.WriteLine($"specificTime > earlier: {specificTime > earlier}");
Console.WriteLine($"specificTime == later: {specificTime == later}");

// Convert to TimeSpan
TimeSpan timeSpan = specificTime.ToTimeSpan();
Console.WriteLine($"TimeOnly to TimeSpan: {timeSpan}");

// IsBetween
bool isBetween = specificTime.IsBetween(earlier, later);
Console.WriteLine($"specificTime is between earlier and later: {isBetween}");
}
}

4.6.5.3 - Using DateOnly and TimeOnly Together

DateOnly and TimeOnly can be used together to represent a full date and time:

Example:

using System;

class Program
{
static void Main()
{
// Create DateOnly and TimeOnly objects
DateOnly date = new DateOnly(2023, 12, 31);
TimeOnly time = new TimeOnly(23, 59, 59);

Console.WriteLine($"Date: {date}");
Console.WriteLine($"Time: {time}");

// Combine into a DateTime
DateTime dateTime = date.ToDateTime(time);
Console.WriteLine($"Combined DateTime: {dateTime}");

// Extract DateOnly and TimeOnly from a DateTime
DateTime now = DateTime.Now;
DateOnly todayDate = DateOnly.FromDateTime(now);
TimeOnly currentTime = TimeOnly.FromDateTime(now);

Console.WriteLine($"Current DateTime: {now}");
Console.WriteLine($"Extracted DateOnly: {todayDate}");
Console.WriteLine($"Extracted TimeOnly: {currentTime}");

// Using DateOnly and TimeOnly for scheduling
DateOnly meetingDate = new DateOnly(2023, 12, 15);
TimeOnly meetingStartTime = new TimeOnly(9, 0);
TimeOnly meetingEndTime = new TimeOnly(10, 30);

Console.WriteLine($"Meeting on {meetingDate} from {meetingStartTime} to {meetingEndTime}");

// Check if a meeting is happening now
DateOnly currentDate = DateOnly.FromDateTime(DateTime.Now);
TimeOnly nowTime = TimeOnly.FromDateTime(DateTime.Now);

bool isMeetingToday = currentDate == meetingDate;
bool isMeetingNow = isMeetingToday && nowTime >= meetingStartTime && nowTime <= meetingEndTime;

Console.WriteLine($"Is the meeting today? {isMeetingToday}");
Console.WriteLine($"Is the meeting happening now? {isMeetingNow}");
}
}

4.6.5.4 - When to Use DateOnly and TimeOnly

Guidelines for choosing between DateTime, DateOnly, and TimeOnly:

Example:

using System;

class Program
{
static void Main()
{
// Use DateOnly for:
// 1. Birthdays
// 2. Anniversaries
// 3. Holidays
// 4. Any date without a time component

DateOnly birthday = new DateOnly(1990, 5, 15);
Console.WriteLine($"Birthday: {birthday}");

// Calculate age
DateOnly today = DateOnly.FromDateTime(DateTime.Today);
int age = today.Year - birthday.Year;
if (today.DayOfYear < birthday.DayOfYear)
{
age--;
}
Console.WriteLine($"Age: {age}");

// Use TimeOnly for:
// 1. Daily schedules
// 2. Opening hours
// 3. Any time without a date component

TimeOnly openingTime = new TimeOnly(9, 0);
TimeOnly closingTime = new TimeOnly(17, 0);
Console.WriteLine($"Store hours: {openingTime} - {closingTime}");

// Check if store is open
TimeOnly currentTime = TimeOnly.FromDateTime(DateTime.Now);
bool isStoreOpen = currentTime >= openingTime && currentTime < closingTime;
Console.WriteLine($"Is the store open now? {isStoreOpen}");

// Use DateTime for:
// 1. Specific events in time
// 2. Timestamps
// 3. When you need both date and time components

DateTime appointmentDateTime = new DateTime(2023, 12, 15, 14, 30, 0);
Console.WriteLine($"Appointment: {appointmentDateTime}");

// Use DateTimeOffset for:
// 1. Events across different time zones
// 2. When time zone information is important

DateTimeOffset flightDeparture = new DateTimeOffset(2023, 12, 15, 10, 30, 0, TimeSpan.FromHours(-5));
Console.WriteLine($"Flight departure: {flightDeparture}");
}
}

Working with dates and times in C# involves a rich set of types and methods for representing, manipulating, formatting, and parsing date and time values. By understanding these capabilities, you can effectively handle date and time operations in your applications, whether they involve simple date calculations or complex time zone conversions.