msgraph-sdk-dotnet
msgraph-sdk-dotnet copied to clipboard
[Client bug]: ToDateTime extension fails with Windows time zones on Linux
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
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)
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