msgraph-sdk-dotnet icon indicating copy to clipboard operation
msgraph-sdk-dotnet copied to clipboard

[Client bug]: ToDateTime extension fails with Windows time zones on Linux

Open tjmoore opened this issue 3 years ago • 1 comments

Describe the bug On Linux if a DateTimeTimeZone object has a Windows time zone set for TimeZone property, and ToDateTime extension method is used to covert to a DateTime object, this can fail looking up the time zone.

A work around is to convert the TimeZone property to the platform time zone (IANA on Linux) before using ToDateTime, or roll my own version of this extension to be cross-platform.

To Reproduce

var dtTimeZone = new DateTimeTimeZone
{
    DateTime = "2021-07-07T16:00:00.0000000",
    TimeZone = "GMT Standard Time"
};

var dt = dtTimeZone.ToDateTime().ToUniversalTime();

Console.WriteLine($"{dt:yyyy-MM-ddTHH:mm:ssK}");

Expected behavior Returns output:

2021-07-07T15:00:00Z

This is the behaviour on Windows

Actual behaviour

Unhandled exception. System.TimeZoneNotFoundException: The time zone ID 'GMT Standard Time' was not found on the local computer.
 ---> System.IO.FileNotFoundException: Could not find file '/usr/share/zoneinfo/GMT Standard Time'.
File name: '/usr/share/zoneinfo/GMT Standard Time'
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
   at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
   at Internal.IO.File.ReadAllBytes(String path)
   at System.TimeZoneInfo.TryGetTimeZoneFromLocalMachine(String id, TimeZoneInfo& value, Exception& e)
   --- End of inner exception stack trace ---
   at System.TimeZoneInfo.FindSystemTimeZoneById(String id)
   at Microsoft.Graph.Extensions.DateTimeTimeZoneExtensions.ToDateTime(DateTimeTimeZone dateTimeTimeZone)
   at GraphToDateTimeBug.Program.Main(String[] args) in E:\dev\SamplesAndTests\GraphToDateTimeBug\Program.cs:line 17

Client version Microsoft.Graph 3.33.0

Desktop (please complete the following information):

  • OS: CentOS 7
  • .NET Core 3.1.10

Additional context Noting that on creating a calendar event on Linux I can supply 'GMT Standard Time' with no problem. In fact I convert to Windows time zone via TimeZoneConverter library as the documentation suggests the "additional time zones" in IANA format are only a subset of all those available, and assume 365 works in Windows time zones anyway. https://docs.microsoft.com/en-us/graph/api/resources/datetimetimezone?view=graph-rest-1.0

Arguably this may not be a bug in ToDateTime but a use issue in the Windows time zone ID being present in DateTimeTimeZone on Linux. However I get 'GMT Standard Time' returned in this object if I create a calendar event with this time zone set (which succeeds).

This could also be an issue with the create event request returning 'GMT Standard Time', despite asking for UTC in the headers.

e.g.

var newEvent = new Event
{
    Subject = "Test",
    Start = new DateTimeTimeZone
    {
        DateTime = "2021-07-07 16:00:00",
        TimeZone = "GMT Standard Time"
    },
    End = new DateTimeTimeZone
    {
        DateTime = "2021-07-07 16:15:00",
        TimeZone = "GMT Standard Time"
    }
};

var eventCreated = await _client
    .Users[mailbox]
    .Events
    .Request()
    .Header("Prefer", $"outlook.timezone=\"UTC\"")
    .AddAsync(newEvent);

here eventCreated.Start.ToDateTime() fails.

On querying events, I request UTC in the same way and get UTC returned.

Also noticed an inconsistency in that I can specify a variety of formats for DateTime property in DateTimeTImeZone on creating an event, but ToDateTime extension method uses ParseExact and requires a specific format. AB#10145

tjmoore avatar Jul 07 '21 15:07 tjmoore

Actually, ToDateTime just isn't working for me to convert to UTC which is ultimately what I want, even on Windows.

[Test]
public void TestToDateTimeTimeZone()
{
    var dttz = new DateTimeTimeZone { DateTime = "2021-07-01T10:00:00.0000000", TimeZone = "Pacific Standard Time" }; // PDT

    var dt = dttz.ToDateTime().ToUniversalTime();

    Assert.That(dt.ToString("yyyy-MM-ddTHH:mm:ssK"), Is.EqualTo("2021-07-01T17:00:00Z"));
}

result is 2021-07-01T09:00:00Z when I'm expecting 2021-07-01T17:00:00Z (PDT = UTC - 7)

I assume because looking at the code for ToDateTime, it just marks it as Unknown kind and ToUnivseralTime on my local PC in UK thinks it's local BST, so UTC + 1

I guess this is down to this: https://github.com/microsoftgraph/msgraph-sdk-dotnet/pull/483#issuecomment-504138459

However ToDateTimeOffset also seems broken without even getting to converting to UTC...

[Test]
public void TestToDateTimeOffset()
{
    var dttz = new DateTimeTimeZone { DateTime = "2021-07-01T10:00:00.0000000", TimeZone = "GMT Standard Time" }; // BST

    var dto = dttz.ToDateTimeOffset();
    var dt = dto.UtcDateTime;

    Assert.That(dt.ToString("yyyy-MM-ddTHH:mm:ssK"), Is.EqualTo("2021-07-01T09:00:00Z"));
}

Throws an exception:

System.ArgumentException : The UTC Offset for Utc DateTime instances must be 0. (Parameter 'offset')

Stack Trace: DateTimeOffset.ctor(DateTime dateTime, TimeSpan offset) DateTimeTimeZoneExtensions.ToDateTimeOffset(DateTime dateTime, TimeZoneInfo timeZoneInfo) DateTimeTimeZoneExtensions.ToDateTimeOffset(DateTimeTimeZone dateTimeTimeZone)

tjmoore avatar Jul 08 '21 13:07 tjmoore

Closing this one for now.

However ToDateTimeOffset also seems broken without even getting to converting to UTC...

This was resolved via https://github.com/microsoftgraph/msgraph-sdk-dotnet/pull/1467 and should be fixed in versions 4.38.0 and above.

The behaviour on linux is issue with out of support .NET runtime that is now resolved in later runtimes as outlined at the link below.

https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6/#time-zone-conversion-apis

andrueastman avatar Jan 25 '23 08:01 andrueastman