C# Time Tutorial: The When, What, and How

Navigate to:

Time manipulation is a staple of programming. This is true no matter what programming language happens to be your favorite: Python, Java, Kotlin, Ruby, you name it. C# isn’t an exception, of course, and that’s why today we bring you a comprehensive yet approachable guide to C# time manipulation.

We’ll open the post by giving you the ten-thousand-foot view of time handling in C# programming. After that, we’ll descend a little bit to give you more actionable tips. You’ll learn about the main time-related functions in C# —— what they are and how to use them.

Before wrapping up, we’ll cover real-world applications of time handling in C#, so you know how to use all the information from this post in ways that generate the most value for your project.

Prerequisites

If you want to follow along with the post, testing the code samples as you go, you’ll need:

  • a version of the .NET SDK installed on your machine —— we recommend .NET 7
  • some IDE or text editor—Visual Studio Code is a great choice
  • at least basic C# knowledge

How Is Time Used in C# Programming?

In C# and .NET, time handling is a first-class citizen. To enable your program to work with times and dates, you don’t have to do anything special, such as adding using statements or installing NuGet packages. As you’ll see, the types you need to handle time concerns all live within the System namespace, so you already have access to them.

Considering that C# is a (mostly) object-oriented language, it shouldn’t come as a surprise that its time-related features are provided via the usage of objects. The main one you’ll work with is theDateTimetype. The DateTime type is a structure —— that is, a value type instead of a reference type —— and it’s immutable. Since its value never changes, it can be used in safer and more predictable ways, leading to more robust code.

DateTime represents, well, a date and a time. But its interface also offers plenty of useful time-related operations, such as:

  • performing time arithmetic, such as adding minutes, hours, days, or other time periods to a given date
  • comparing two dates
  • formatting the date according to a myriad of data and time formats

Despite DateTime being the most famous of C# time-related types, it’s far from being the only one. Other useful types include DateTimeOffset, TimeSpan, DateOnly, TimeOnly, and TimeZoneInfo.

Now let’s learn more about how to use some of these functions in practice.

It’s now the time to learn how to actually use the time-related functionality in C#. For this section, we’ll use a FAQ format. We’ll list common scenarios as questions, answering them right away.

How Do You Get the Current Time in C#?

The easiest way to obtain the current time and date in C# is using the Now property from the DateTime type. It returns a DateTime value, containing the current date and time according to the clock of the system on which the program is running. What follows is a simple program that greets the user according to the time of the day:

DateTime currentTime = DateTime.Now;
int hour = currentTime.Hour;

if (hour >= 8 && hour < 12)
{
    Console.WriteLine("Good morning!");
} 
else if (hour >= 12 && hour < 18)
{
    Console.WriteLine("Good afternoon!");
}
else
{
    Console.WriteLine("Good evening!");
}

As you can see, the code also uses the Hour property on the returned DateTime to obtain just the hour portion of the current value. There are also other properties for different portions of the value:

int minute = currentTime.Minute;
int second = currentTime.Second;
int day = currentTime.Day;
int month = currentTime.Month;
int year = currentTime.Year;
int microsecond = currentTime.Microsecond;
int milisecond = currentTime.Millisecond;
int dayOfYear = currentTime.DayOfYear;

Is There a Time Data Type in C#?

For most of its existence, C# didn’t provide one data type solely for times and one only for dates. You’d have to make do with DateTime –– that always has both components –– which often caused bugs, especially in comparison scenarios. (Another alternative would be to resort to a third-party library such as NodaTime.)

Starting with .NET 6, now there are types for storing only the date or time. They’re called DateOnly and TimeOnly, respectively.

That’s how you can retrieve the current time and store it in a TimeOnly variable:

TimeOnly now = TimeOnly.FromDateTime(DateTime.Now);
DateOnly today = DateOnly.FromDateTime(DateTime.Now);

How Do You Work With Durations?

If you have two DateTime values, you can easily calculate the delta (that is, the difference) between them. The result is a value of the TimeSpan type. Let’s see how to do it in practice:

var start  = new DateTime(2023, 10, 5, 10, 0, 0);
var end = new DateTime(2023, 10, 6, 7, 25, 0);
TimeSpan delta = end - start;

The code above declares two DateTime values, using the constructor to pass the year, month, day, hour, minute, and seconds. Then, using the minus operator, we calculate the difference between the two values and assign it to a new variable of type TimeSpan.

The TimeSpan object has several properties that enable you to retrieve portions of its value, such as TotalMinutes, TotalHours, TotalSeconds, and more.

You can also create TimeSpan values using its static factory methods. For instance, if you need to represent a duration of 50 minutes, that’s how you’d go about it:

var duration = TimeSpan.FromMinutes(50);

Real-World Applications of Time in C

Let’s continue by covering some real-world applications of C# time-related programming.

Displaying the Current Date and/or Time

Many programs might need to display the current date and/or time on their UIs. As you’ve seen, the DateTime.Now property comes in handy for retrieving the value. When it comes to formatting, you’d use one of the many variations of ToString() to format the values according to your needs. You also have at your disposal more specific methods such as ToLongTimeString(), ToLongDateString(), ToShortDateString(), ToShortTimeString().

Recording “Historical” Data

Whenever you need to store the time and date of an event, you shouldn’t just use DateTime.Now to retrieve the moment. That’s because this property returns a value with the Kind property set to Local. That means that value is local to the computer it was generated on, but has no concept whatsoever of time zones. The correct approach in these cases is to save the value as UTC, and only convert it to local times when displaying it.

To get the current date and time in UTC, you simply use the DateTime.UtcNow property:

var utcNow = DateTime.UtcNow;

Another alternative is using a different type: instead of DateTime, you’d leverage DateTimeOffset:

DateTimeOffset localWithOffset = DateTimeOffset.Now;

The DateTimeOffset type contains the regular, local date, but it also stores the offset from UTC. This approach has the benefit of preserving the time in local time, which facilitates visualization while enabling the conversion to universal time (UTC) when it’s needed.

Defining Expiration Dates

A common scenario in business is the need to define expiration dates: final dates for trial periods, end dates of contracts or other legal terms, expiration dates for personal access tokens, and so on.

It’s easy to come up with these dates by using the AddDays() method from DateTime and its companions:

var today = DateTime.Today;
DateTime tenDaysLater = today.AddDays(10);
DateTime twoMonthsLater = today.AddMonths(2);
DateTime nextYear = today.AddYears(1);

There are no Subtract methods. In order to subtract from a DateTime object, you’d simply supply negative values to the Addxxx methods.

Validating or Parsing DateTime Values From Files

Another common scenario is having to parse dates and times stored in text files —— e.g., .CSV files. Since there’s no guarantee that these values are actually valid, make sure to write your code in a robust manner. The following code extracts and parses the date on a line from a .CSV file. The code assumes that the date is in the second column:

void ParseLine(string line)
{
    string[] parts = line.Split(',');
    if (parts.Length < 3)
        throw new InvalidOperationException("File with wrong data!");

    string dateCandidate = parts[1];
    if (!DateTime.TryParse(dateCandidate, out DateTime date))
    {
        throw new InvalidOperationException("Invalid date!");
    }

    // do something useful with date
}

As you can see, no date format is supplied to the method. If you try this code on your own, make sure the date is in the ISO-8601 format and it will work. Other formats may or may not work depending on your system’s culture.

Wrapping up

Time handling is a gigantic topic in programming. It’s fascinating, complex, and full of opportunities for mistakes and bugs. This post was a gentle introduction to the topic. You’ve learned how time handling works in C#, what the main types you should use are, and even some real-world scenarios.

However, this is just the tip of the iceberg. There’s no way I could cover all there is to know about this topic within the scope of a single blog post. So, here are some items you should research on your own:

  • Learn more about the different kinds—meaning, the different possible values for its Kind property—a DateTime can assume, and the implications they bring for your code
  • Learn more about the TimeZoneInfo class and how to work with code that needs to handle time zones
  • Research how to schedule future events and how daylight savings time can bring a lot of complexity to the table

Thanks for reading, and until next time.

This post was written by Carlos Schults. Carlos is a consultant and software engineer with experience in desktop, web, and mobile development. Though his primary language is C#, he has experience with a number of languages and platforms. His main interests include automated testing, version control, and code quality.