Reputation: 5657
I'm trying to use the XMLProvider to work with a file that uses the AEOI XML format for exchange of tax information.
I'm generating the type from the .xsd file and the relevant bit is:
<xs:element name="XMLTimeStamp" type="xs:dateTime" id="S1.2">
<xs:annotation>
<xs:documentation>Date and time that the XML was originally created.</xs:documentation>
</xs:annotation>
</xs:element>
And then in the XML file I have:
<XMLTimeStamp>2022-04-28T10:09:17</XMLTimeStamp>
The provider gets created and used like this:
type CrsReport = XmlProvider<Schema="X:\\x\\uk_aeoi_submission_v2.0.xsd",
ResolutionFolder="X:\\x">
let sample = CrsReport.Load("X:\\x\\9999999999SAMPLE_FILE.xml")
let ts = sample.MessageData.XmlTimeStamp
However when I try and access the element in question I get this error:
Installed Packages
Fsharp.Data, 4.2.8
Error: System.Exception: Expecting DateTimeOffset in Value, got 2022-04-28T10:09:17
at Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThenFail@1439.Invoke(String message) in D:\workspace\_work\1\s\src\fsharp\FSharp.Core\printf.fs:line 1439
at System.Runtime.CompilerServices.RuntimeHelpers.DispatchTailCalls(IntPtr callersRetAddrSlot, IntPtr callTarget, IntPtr retVal)
at FSharp.Data.Runtime.TextRuntime.GetNonOptionalValue[T](String name, FSharpOption`1 opt, FSharpOption`1 originalValue)
at <StartupCode$FSI_0029>.$FSI_0029.main@()
So it looks as if type provider is expecting a DateTimeOffset instead of a DateTime and if I use a sample of XML to generate the provider it correctly identifies the element of the file as a DateTime.
Is this a bug with the provider or am I missing something about how to access or specify these elements?
Having spent some time reading the FSharp.Data code it looks as if it is a deliberate decision to use DateTimeOffset for xs:dateTime values. The value given should parse to either a DateTime or a DateTimeOffset so something must be going on in the conversion process.
Upvotes: 0
Views: 144
Reputation: 5657
This looks like a bug in the AsDateTimeOffset
function in the TextConversions.fs.
The code is currently as shown below:
let ParseISO8601FormattedDateTime text cultureInfo =
match DateTime.TryParse(text, cultureInfo, dateTimeStyles) with
| true, d -> d |> Some
| false, _ -> None
match ParseISO8601FormattedDateTime text cultureInfo with
| Some d when d.Kind <> DateTimeKind.Unspecified ->
match DateTimeOffset.TryParse(text, cultureInfo, dateTimeStyles) with
| true, dto -> dto |> Some
| false, _ -> None
| _ -> None
So what is happening is that when the date is 2022-04-28T10:09:17
them d.Kind
is set to DateTimeKind.Unspecified and the code returns None
. Changing the date 2022-04-28T10:09:17Z
causes the d.Kind
to be set and the date gets returned correctly. (So I have a work around for now)
I think that the current code might be over complicating things, it parses the date string twice and I don't see why it needs to worry about d.Kind
being set or not. My suggestion for this part of the code would be:
match ParseISO8601FormattedDateTime text cultureInfo with
| Some d -> new DateTimeOffset(d) |> Some
| _ -> None
I did consider doing something like the xs:date conversion does which is to set the Kind to local.
// Parse ISO 8601 format, fixing time zone if needed
match ParseISO8601FormattedDateTime text cultureInfo with
| Some d when d.Kind = DateTimeKind.Unspecified -> new DateTime(d.Ticks, DateTimeKind.Local) |> Some
| x -> x
So for asDateTimeOffset
this would then be
match ParseISO8601FormattedDateTime text cultureInfo with
| Some d when d.Kind = DateTimeKind.Unspecified ->
let d1 = new DateTime(d.Ticks,DateTimeKind.Local)
new DateTimeOffset(d1) |> Some
| Some d -> new DateTimeOffset(d) |> Some
| _ -> None
This doesn't set the Kind
in the DateTime internals of the DateTimeOffset, but then DateTimeOffset is designed to:
defines the difference between the current DateTimeOffset instance's date and time and Coordinated Universal Time (UTC)
So the offset encodes this information.
Upvotes: 1