← All posts

Programming 4 min read

Understanding UTC, Time Zones, and Time Stamps in .NET

Discover how missing UTC offsets can silently break your application logic, and learn the right way to handle dates and times.

Understanding UTC, Time Zones, and Time Stamps in .NET

Have you ever wondered why dates and times can be so tricky to work with in an application?

Imagine a user writes a journal entry at 12:30 AM on November 10, but your application thinks they wrote it on November 9. Suddenly, your streak calculation is incorrect, and you're left wondering what went wrong.

The problem might not be your business logic. It might be how you're handling time.

Let's take a step back and understand UTC, time zones, and how to work with dates and times correctly in an application.

What is UTC?

  • UTC is Coordinated Universal Time. It is the universal time standard and never changes for daylight saving time. Different time zones use UTC as their reference point to determine local time.

  • Each time zone tells you how many hours ahead of or behind UTC it is.

    • Eastern Daylight Time (New York, USA) is UTC-5. This tells us that New York is 5 hours behind UTC.

    • Central European Summer Time (Paris, France) is UTC+2. This tells us that Paris is 2 hours ahead of UTC.

  • If you provide your local time along with your offset from UTC, it can be reliably converted to any other time zone. If you only provide local time without a UTC offset or time zone, accurate conversion becomes impossible.

Think of UTC as the master clock. When you go to a different time zone, your local time shifts away from UTC by either a positive or negative number of hours.

Here is an example of how understanding UTC helps you convert time from one zone to another. Let's say the time in New York is 14:00. What time is it in Paris?

  1. Convert New York time to UTC: Since EST is UTC-5 (5 hours behind UTC), you do the opposite and add 5 hours to get back to the master clock.

    14:00 + 5 hours = 19:00 UTC

  2. Convert UTC to CEST: Since CEST is UTC+2 (2 hours ahead of UTC), you follow the offset directly and add 2 hours.

    19:00 + 2 hours = 21:00 CEST

So, when it is 14:00 in New York, it is 21:00 in Paris.

Time in an Application

When working with dates and times in an application, .NET provides a few different options:

  • DateTime.Now gives you the local date and time of the machine running the application. For example, it might tell you that it is 14:00, but the value itself does not tell you its UTC offset.

  • DateTime.UtcNow gives you the current date and time in UTC.

  • DateTimeOffset.Now gives you the local date and time along with its UTC offset.

For example, an event happens at: 11/07/2026 14:30:00 -05:00

This tells us that the event happened at 14:30 in a time zone that was 5 hours behind UTC.

The Problem with Storing the Wrong Time

Imagine a journal application that calculates a user's streak. Every day the user completes a journal entry, the date is saved, and that data is used to calculate the streak.

Now, let's say I store the local date and time when the user creates a journal entry:

  • 11/07/2026 14:30:00

  • 11/08/2026 16:30:00

  • 11/09/2026 22:30:00

This should yield a streak of 3 because an entry was added on three consecutive days.

How Can This Create a Bug When Viewed from Another Time Zone?

One bug I experienced happened when a user created a journal entry shortly after midnight, around 12:30 AM locally in Eastern Time.

The server read 11/10/2026 00:30:00 and assumed it was UTC because the database did not explicitly store an offset. The application then interpreted that value as UTC and converted it back to Eastern Time (UTC-5), resulting in 11/09/2026 19:30:00.

Now, instead of recognizing the journal entry as November 10, the application thinks it was created on November 9. This breaks the user's streak calculation because the application is operating on the wrong calendar date.

This is why storing a date and time without its UTC offset or time zone can cause subtle bugs. The server has no way of knowing what the original local time actually represented.

Which Type Should You Use in Your Application?

You generally want to use DateTimeOffset when storing timestamps that represent a specific moment in time.

It provides the local date and time along with its UTC offset, ensuring that any other application reading the value has enough information to identify the exact moment in time and convert it to another zone accurately.

Lesson Learned

Using a date and time without knowing its UTC offset or time zone can cause subtle, frustrating bugs in an application.

For timestamps, DateTimeOffset is generally a much safer and more reliable choice than an unspecified DateTime value!

Newsletter

Get new posts by email

Get new posts in your inbox whenever I publish. No spam, unsubscribe in one click.

I'll only email you new posts. Unsubscribe anytime.