2
\$\begingroup\$

I asked this question over at stackoverflow but was told it may be better suited here.

So I absolutely want to store DateTimeOffset objects in UTC format. To achieve the correct conversions, I've created my own methods to deal with the conversions.

/// <summary>String representation of the specified time zone.</summary>
        private const String LOCAL_TIME_ZONE_STRING_REPRESENTATION = "GMT Standard Time";
        /// <summary>TimeZoneInfo representation of the specified time zone.</summary>
        private static TimeZoneInfo LOCAL_TIME_ZONE = TimeZoneInfo.FindSystemTimeZoneById(LOCAL_TIME_ZONE_STRING_REPRESENTATION);

        /// <summary>With a given DateTime, passed DateTime is assumed it has been parsed and shares the same time zone as TimeZoneInfo LOCAL_TIME_ZONE.</summary>
        /// <param name="dateAndTime">DateTime in TimeZoneInfo LOCAL_TIME_ZONE.</param>
        /// <returns>UTC DateTime.</returns>
        public static DateTime ConvertToUtcDateTime(DateTime dateAndTime)
        {
            return TimeZoneInfo.ConvertTime(dateAndTime, LOCAL_TIME_ZONE).ToUniversalTime();
        }
        /// <summary>With a given DateTime, the DateTime is assumed to be a UTC time. It will then return a DateTime converted to TimeZoneInfo LOCAL_TIME_ZONE.</summary>
        /// <param name="dateAndTime">DateTime that is in UTC.</param>
        /// <returns>Converted to TimeZoneInfo LOCAL_TIME_ZONE DateTime.</returns>
        public static DateTime ConvertToLocalDateTime(DateTime dateAndTime)
        {
            return TimeZoneInfo.ConvertTimeFromUtc(dateAndTime, LOCAL_TIME_ZONE);
        }

Using the String constant LOCAL_TIME_ZONE_STRING_REPRESENTATION, any user who wishes to compile the code can specify which time zone they want the code to run in, rather than it try to use Window's local time zone.

Then the two above methods can be used to make a conversion between between the two:

private static void Main()
        {
            //Parse a date and time. It is to be assumed this parsed date and time is in the same time zone
            // as LOCAL_TIME_ZONE.
            DateTimeOffset dateTime = ConvertToUtcDateTime(new DateTime(2019,6,1,15,30,0));

            //Assuming we have retrieved a date and time that is in UTC time, we can now convert it
            // to the same time zone as LOCAL_TIME_ZONE.
            DateTime convertedFromUTC = ConvertToLocalDateTime(dateTime.DateTime);
}

The system would be able to parse DateTime's that have no time zone associated with them regardless where they would've came from, and convert them into UTC time assuming that DateTime came from the same TimeZone as LOCAL_TIME_ZONE. The only time where we would need to convert retrieved UTC DateTimes back into the same time zone as LOCAL_TIME_ZONE would be when we are visually displaying it to a user. All TimeSpan calculations etc, would use the UTC DateTimeOffset.

This seems to work as intended, and I can change LOCAL_TIME_ZONE_STRING_REPRESENTATION to any time zone I want, and using the methods I created, the system uses that time zone instead of Window's local time zone.

This would be particularly useful for me as the server hosting an application may be in a different time zone and have a different culture, but its intended users could be for a totally different time zone.

Am I making too much work for myself, or would this be a reasonable way to implement what I need?

\$\endgroup\$
  • \$\begingroup\$ Welcome to Code Review! I changed your title to follow the recommendations at How do I ask a good question? found in the Help Center. \$\endgroup\$ – AlexV Jun 11 at 10:32
  • \$\begingroup\$ Thanks, that title is definitely easier to read! \$\endgroup\$ – Izacch Jun 11 at 10:33
1
\$\begingroup\$

Using the String constant LOCAL_TIME_ZONE_STRING_REPRESENTATION, any user who wishes to compile the code can specify which time zone they want the code to run in, rather than it try to use Window's local time zone.

I think this is not the right way to provide flexibility. Lets say you sell your application to three different customers that want three different LOCAL_TIME_ZONE, then you'll have to compile the application three times. Do yourself the favor and place this as a setting in a configuration file or database. And what if the application is to be used world wide by a global customer? Do you plan to use the same time zone in all their offices?


    public static DateTime ConvertToUtcDateTime(DateTime dateAndTime)
    {
        return TimeZoneInfo.ConvertTime(dateAndTime, LOCAL_TIME_ZONE).ToUniversalTime();
    }

I don't think this is working correctly:

A DateTime object can either represent a local time which is always regarded as local according to the system settings or a UTC time if created with kind = DateTimeKind.Utc - seen from the DateTime api.

Let say LOCAL_TIME_ZONE_STRING_REPRESENTATION = "GMT Standard Time"; and the system time zone = "Romance Standard Time" (+01.00).

Because TimeZoneInfo.ConvertTime(dateAndTime, LOCAL_TIME_ZONE) converts from local time (Romance Standard Time), it converts

DateTime inputDate = new DateTime(2019, 3, 1, 15, 30, 0);

to

01-03-2019 14:30:00

and the call to ToUniversalTime() converts it further to:

01-03-2019 13:30:00

because this too anticipate the DateTime object to be in local time, which is "Romance Standard Time" and not "GMT Standard Time".

But if you - as you write in the explanation to the method - expect the input date time object to be in LOCAL_TIME_ZONE, no change should occur, because GMT = UTC.

To do it correctly I'll suggest this approach if the input DateTime object is still expected to be in LOCAL_TIME_ZONE:

public static DateTime ConvertToUtcDateTime(DateTime dateAndTime)
{
  return TimeZoneInfo.ConvertTimeToUtc(dateAndTime, LOCAL_TIME_ZONE);
}

That said, if I were you, I would reconsider the whole setup thoroughly before using it in a larger scale. Dates, Times and globalization in general is rather complicated, so do yourself the favor to read and test a lot before taking a concept into use that is not just relying on the system. A place to start reading could be here.

\$\endgroup\$
  • \$\begingroup\$ This is a good explanation to show that DateTime is not context-free. The consumer should always assert a timezone when the Kind is LocalTime. \$\endgroup\$ – dfhwze Jun 15 at 15:54
  • \$\begingroup\$ Thanks for the information. One thing I am having a real hard time understanding is how I would use DateTimeOffset.Parse() and specifically specify a TimeZoneInfo if I specifically know the time zone that the date and time has been parsed from. \$\endgroup\$ – Izacch Jul 2 at 13:01
  • \$\begingroup\$ @Izacch: If you parse the datetime string with DateTime.Parse(), you can use TimeSpan offset = TimeZoneInfo.GetUtcOffset(dateTime) to get the offset from UTC and then call the constructor: var utcOffset = DateTimeOffset(dateTime, offset); If I understand you right. \$\endgroup\$ – Henrik Hansen Jul 2 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.