2
votes

We have an application related to aviation, and specifically flights.

Times have to be stored in local, so I chose to use UTC Time + an offset, but then now I realize it is a bad choice:

By storing the timezone as an offset, I lose track of the original timezone and this has implications when dealing with daylight savings.

For example I can store a time in Alpine, UT as UTC time and a -6 offset and also a time in Phoenix, AZ as UTC time and a -6 offset.

But when daylight saving comes, the time will change in Alpine, but not in Phoenix.

So, I need to store the proper timezone and I have seen that there are also different lists with a different syntax, so I am assuming there are different standards.

In C#, what would be the best option to store a local time with the local time zone to make it work with daylight saving changes?

2
As you have too mentioned that storing local time is a bad choice , and I also agree with it. I would suggest that if you can start working changing your current program to store the UTC time zone (to have backward compatibility) you can store both UTC and local time zone value. That would you don't require to work on all the edge cases for what country has day light saving and when. You can rely on system dlls to convert the UTC value to local value based on regional settings of user.user1672994
"Times have to be stored in local". I'm really sorry for you. This right there is the gate to madness. Having to deal with daylight savings only makes the trip to madness faster. Please, take the advice of someone that have walked this road before, and for your own sanity - reconsider that approach.Zohar Peled
The regional settings of the user are not relevant here because, in aviation, times displayed are always local to the location of the airport. The issue is that if the time is stored in UTC + Offset and the daylight saving kicks in, I can't do the correction since I don't know what zone that time belongs to if I only store an offset.Thomas
Store them in UTC, display them in local time. Convert when needed.Marvin
Not in aviation: if you are looking for a LA -> NY flight, the flight departure is LA time, the flight arrival is written as NY time, this is not related to the client.Thomas

2 Answers

5
votes

From the discussion in the question's comments, I understand that you are working with flight time schedules - that is, the time a future flight is intended to depart. This is indeed a case where the local time is more important than the UTC time.

Since you have the local time and location of departure (ex: 5:00 PM in Salt Lake City), then you should be storing in your database of scheduled departure times two values:

  • 17:00 - The relevant local time of the departure
  • SLC - The location where the time is relevant

If this is a specific occurrence of this flight, then you should store the date as well:

  • 2018-06-01T17:00 - The specific relevant local time of the departure
  • SLC - The location where the local time is relevent

These are the details that are contextually relevant to your business use case. Do not lose sight of them by converting them to UTC.

That said, you might consider storing them as a DateTimeOffset (2018-06-01T17:00-06:00), which makes converting to UTC trivial for a given instance. However there are two problems with this approach:

  • It cannot work with recurrences, because the offset may change.
  • Even for a single instance, the offset might change - if the government controlling the time zone decides to change their standard offset or daylight saving time rules before that occurrence takes effect. If you do take a DateTimeOffset approach, or a UTC-based approach, you must be prepared to recalculate future events in the face of such changes. (For more on this, see my blog articles: On the Timing of Time Zone Changes and Time Zone Chaos Inevitable in Egypt. There are countless other examples.)

With regards to the location - because you are working with data that is contextually applicable to the airline industry, I recommend using IATA airport codes like the SLC that I showed above. In other contexts, one might store an IANA time zones identifier like America/Denver, or a Windows time zone identifier like Mountain Standard Time.

You may find my "Airport Time Zones" gist (code and output table) useful for working with IATA airport codes. You'll have to decide how that data will flow through your system. If you are running on Windows and want to use the TimeZoneInfo class to convert times to different time zones, then use the Windows time zone IDs shown there. If you want to use the IANA time zone IDs instead, consider using Noda Time, or you can use my TimeZoneConverter library. There are several different options here, so explore them all carefully and pick ones that make sense to you.

Noda Time would be a great choice, IMHO. Not only would you get excellent time zone support, but you'd also be able to use types like LocalTime or LocalDateTime which align well with the scenarios described.

1
votes

As I wrote in my comment, do not store local dates. Instead, store datetime values as UTC, and convert to local datetime when you need to display it.
You can use the ConvertTimeFromUtc method of the TimeZoneInfo class for that.

This means you will have to also keep a list of locations and whatever TimeZoneInfo they are associated in - For example,
Jerusalem would be associated with Israel Standard Time,
Rome with W. Europe Standard Time,
Hawaii with Hawaiian Standard Time
and so on. (I'll bet you can find such a list online somewhere.)
Please note that the ConvertTimeFromUtc method handles the daylight savings problem for you as well.

Then you can do something like this to get the local time by location:

DateTime GetLocalDateByCityName(DateTime utc, string cityName)
{
    var timeZoneInfoId = GetTimeZoneInfoIdByCityName(string cityName);
    return TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZoneInfo.FindSystemTimeZoneById(timeZoneInfoId);
}

And of course, in GetTimeZoneInfoIdByCityName you get the TimeZoneInfoId for the specific city.