Working with Dates, Times, and Time Zones

We've worked with numbers and now text but we haven't worked with dates yet. This is a really important set of data types for folks that are working in accounting, or finance and other industries that need to be able to track when various business events occur. Let's talk about all the different types of date data types and how to work with them in C#

Download this lesson as a Polyglot Notebook to open in Visual Studio Code, or open directly in your web browser with Binder.

In the beginning... there was DateTime

The original date data type that was available for net is the DateTime data type. This data type allows you to store both a date and a time and interact with those values in the date and time. There's a minimum value and a maximum value property that you can work with and all kinds of formatting capabilities of a date time variable. We create a new DateTime variable by using the new keyword and specifying the year month, day, year, and optionally the time information including hour (in 24 hour format), minute, and second.

Let's take a look at some samples where we're going to schedule our next game night.

var gameNight = new DateTime(2024, 5, 1, 19, 0, 0);
display(gameNight);

display(gameNight.Hour);
display(gameNight.Minute);
display(gameNight.Second);

var dateOfNextGame = new DateTime(2024, 5, 8);
display(dateOfNextGame);

var firstDate = DateTime.MinValue;
display(firstDate);

var lastDate = DateTime.MaxValue;
display(lastDate);

Notice that the display of the date is returned in a standard format of year-2 digit month-2 digit day and 24 hour-based time with a Z at the end. Additionally the dateOfNextGame is returned with a time of midnight on the 8th of May because no time was specified. The firstDate value points to midnight on January 1st of the year 1 on the Gregorian Calendar that most of the world uses. There are other calendars available for use in C#, and you can specify which calendar to use as an optional argument when creating a DateTime

This type of structure is pretty good when working with dates and times in a single time zone or you need to do some date and time arithmetic but don't need to be concerned about things like daylight savings time.

Many people don't carry around date and time values in this very discrete format that we created a DateTime value with, but rather something more humanly readable like May 1, 2024 7:00pm In C#, we can Parse those values to create a DateTime that we can then work with.

var myTime = DateTime.Parse("May 1, 2024 7:00 PM");
display(myTime);

C# will do its best to parse the value passed in, and you can also specify the exact format of the string value using the ParseExact method as well:

var exactTime = DateTime.ParseExact("5/1/2024 7:00 PM", "M/d/yyyy h:mm tt", null);
display(exactTime);

Documentation for the custom format specified in this sample can be found on Microsoft Learn.

DateOnly and TimeOnly

However, many folks work with just a date or just a time. We can now work with just these parts that describe dates and times using the DateOnly and TimeOnly variable types.

var gameDay = new DateOnly(2024, 5, 1);
display(gameDay);

var startTime = new TimeOnly(19, 0, 0);
display(startTime);

Time zones, Daylight Savings Time and DateTimeOffset

For more complex operations that need to include and handle information across time zones and daylight savings time, its recommended that you use the DateTimeOffset date type. This type includes time zone information and can properly handle the transition of date information across daylight savings regulations. This type is significantly more accurate for specifying an exact point in time and reflecting that in different time zones.

The easiest way to work with DateTimeOffset is to create one from a DateTime and specify the time zone information or the type of DateTime that was intended using a DateTimeKind value. The DateTimeKind allows you to specify if the DateTime is in UTC time, Local time to a specific time zone, or doesn't reference a specific time zone.

// let's specify that our gameNight is a local time
DateTime.SpecifyKind(gameNight, DateTimeKind.Local);
var gameNightOffset = new DateTimeOffset(gameNight);
display(gameNight);
display(gameNightOffset);

You can see that the gameNight value points to 7pm as we originally specified, and in my local time zone (EST which is 4 hours behind UTC), the gameNightOffset is 23:00 UTC. We can also force the creation of a DateTimeOffset with a specific time zone offset by passing in a TimeSpan value that specifies the number of hours of the offset:

DateTime.SpecifyKind(gameNight, DateTimeKind.Local);

// -5 for Central Daylight Time, used in Chicago, St. Louis, and Austin, Texas
var gameNightOffset = new DateTimeOffset(gameNight, TimeSpan.FromHours(-5)); 

display(gameNight);
display(gameNightOffset);

Now everyone will see that the gameNightOffset is stored with the value of May 2nd at midnight UTC. We can convert that back to local time or any other time zone using the TimeZoneInfo object. For example, if I wanted to convert this to Eastern European Time for my friends in Sofia, Bulgaria to know when my game night is planned, I can reference the FLE Standard Time timezone on Windows like this:

var easternEuropeanTimeZone = TimeZoneInfo.FindSystemTimeZoneById("FLE Standard Time");
var eetGameNight = TimeZoneInfo.ConvertTime(gameNightOffset, easternEuropeanTimeZone);
display(eetGameNight);

Your system's time zone names might be different, and you can see a list of the time zones available with this command:

display(TimeZoneInfo.GetSystemTimeZones());

TimeSpans - Referencing a Duration of Time

We saw above the use of the time span object to create a block of five hours. A TimeSpan in C# allows you to define or reference a duration of time. We can use a TimeSpan to reference the time of day as a duration from midnight to that specific time of day and we can also use time spans to help with arithmetic around dates and times.


var timeOurGameStarts = gameNight.TimeOfDay;
display(timeOurGameStarts);

var gameDuration = new TimeSpan(2, 0, 0); // 2 hours for our game night
display(gameDuration);

var timeToNextGameNight = new TimeSpan(14, 0, 0, 0); // 14 days until our next game night
display(timeToNextGameNight);

You can use this syntax to define a TimeSpan from days, hours, minutes, and seconds. You can also use some shortcut methods to create a TimeSpan for a duration:

var fiveDays = TimeSpan.FromDays(5);
var threeHours = TimeSpan.FromHours(3);

Arithmetic and Dates

Importantly, there are times when developers want to perform calculations between two dates, determine the end time for a duration, and other operations. The DateTime and DateTimeOffset objects provide the ability to Add and Subtract durations and date values.

Notice in the following sample that we also use the value DateTime.Now to reference the current time in the computer's current timezone. We can also use the value DateTime.UtcNow to reference the current time in the UTC time zone

var gameEndingTime = gameNight.Add(TimeSpan.FromHours(3));
display(gameEndingTime);

var timeToGameNight = gameNight.Subtract(DateTime.Now);
display(timeToGameNight);
About Us

CSharp In the Cards is a free technical educational series produced by Jeffrey T. Fritz and available in video, text, and source code formats. In the future, we plan to have more formats available

Contact Us

An unhandled error has occurred. Reload 🗙