1

Hi i receice some random datetimeoffset utc my point is 1 - turn it into chicago time 2- Define the chicago startOfDay 3-finaly convert chicago startOfDay back to an utc datetimeOffset. (this process is needed to query an utc api)

i writed this that seem do what i want but realy not sure it will always do the job with day saving light etc.. someone can tell or improve the code?

var UTCDate = DateTimeOffset.UtcNow; //<----------Some random utc dateTimeOffset
            TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
            DateTimeOffset CSTDate = GetZoneDatetimeOffset(UTCDate, zone);
            Console.WriteLine("Utc : {0} Chicago: {1}  local : {2}", UTCDate, CSTDate, UTCDate.ToLocalTime());            
            Console.WriteLine(" Chicago StartOfDay: {0}  Chicago StartOfDay To UTC : {1}", CSTDate.Date, CSTDate.Date.ToUniversalTime());

    public  DateTimeOffset GetZoneDatetimeOffset(DateTimeOffset someUTCDate , TimeZoneInfo destZone)
            {
                
                DateTimeOffset ZoneDateTimeOffset = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(someUTCDate.DateTime , TimeZoneInfo.Utc.Id, destZone.Id);           
                return ZoneDateTimeOffset;
    
            }
Dams
  • 11
  • 2

1 Answers1

5

You have a few bugs in your code:

  • You call TimeZoneInfo.ConvertTimeBySystemTimeZoneId and pass a DateTime value. The result will thus also be a DateTime. The Kind of that result will be Unspecified. Assigning it to a DateTimeOffset thus will perform an implicit cast operation from DateTime to DateTimeOffset, which will use the computer's local time zone - not the time zone you are working with.

  • Both DateTimeOffset.Date and DateTimeOffset.DateTime also return a DateTime whose Kind is Unspecified. Thus when you call ToLocalTime or ToUniversalTime, you are again using your the computer's local time zone.

  • Determining the start of the day in a specific time zone can be tricky. Though it doesn't happen in Chicago (or anywhere in the USA), some time zones of the world have DST transitions that occur immediately at the start of the day. Thus 00:00 might not be the first moment of the day, or it might occur twice. Your code doesn't account for that.

    A good example is Cuba, where DST next starts on 2022-03-13 at midnight, and thus the start of that day in Cuba is 2022-03-13T01:00.

    You can use the GetStartOfDay method I already provided in this answer to handle these edge cases.

Putting it all together:

// Input values
DateTimeOffset utc = DateTimeOffset.UtcNow;
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");

// Convert with full fidelity using only DateTimeOffset values
DateTimeOffset converted = TimeZoneInfo.ConvertTime(utc, zone);

// Get the start of day using the method from https://stackoverflow.com/a/49988688
DateTimeOffset startOfDay = GetStartOfDay(converted.DateTime, zone);

// Output the results
Console.WriteLine("Original values:");
Console.WriteLine("Chicago: {0:o}   UTC: {1:o}   Local: {2:o}", converted, utc, utc.ToLocalTime());
Console.WriteLine();
Console.WriteLine("At start of day in Chicago:");
Console.WriteLine("Chicago: {0:o}   UTC: {1:o}   Local: {2:o}", startOfDay, startOfDay.ToUniversalTime(), startOfDay.ToLocalTime());

Example output (local time zone is US Pacific Time in this example):

Original values:
Chicago: 2022-03-10T10:58:47.8164830-06:00   UTC: 2022-03-10T16:58:47.8164830+00:00   Local: 2022-03-10T08:58:47.8164830-08:00

At start of day in Chicago:
Chicago: 2022-03-10T00:00:00.0000000-06:00   UTC: 2022-03-10T06:00:00.0000000+00:00   Local: 2022-03-09T22:00:00.0000000-08:00

See also the working .NET Fiddle here.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • will take me sometime to undestand all but look like an awesome clear answer thanks – Dams Mar 10 '22 at 19:02