XMLProvider and issue with DateTime



我正在尝试使用XMLProvider处理一个使用AEOI XML格式交换税务信息的文件。

我正在从.xsd文件生成类型,相关位是:

<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>

然后在XML文件中写入:

<XMLTimeStamp>2022-04-28T10:09:17</XMLTimeStamp>

提供者被这样创建和使用:

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

然而,当我尝试访问有问题的元素时,我得到这个错误:

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_work1ssrcfsharpFSharp.Coreprintf.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@()

所以它看起来好像类型提供者期待一个DateTimeOffset而不是DateTime,如果我使用一个XML示例来生成提供者,它正确地将文件的元素标识为一个DateTime。

这是一个错误与提供程序或我错过了一些关于如何访问或指定这些元素?

花了一些时间阅读FSharp。数据代码看起来似乎是有意为xs:dateTime值使用DateTimeOffset的决定。给定的值应该解析为DateTime或DateTimeOffset,因此在转换过程中必须进行某些操作。

这看起来像是texttransforms .fs中的AsDateTimeOffset函数中的错误。

当前代码如下所示:

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

所以发生的是,当日期是2022-04-28T10:09:17时,d.Kind被设置为DateTimeKind。未指定,代码返回None。更改日期2022-04-28T10:09:17Z将导致设置d.Kind,并正确返回日期。(所以我有一个工作围绕现在)

我认为当前的代码可能是过于复杂的事情,它解析日期字符串两次,我不明白为什么它需要担心d.Kind是否被设置。我对这部分代码的建议是:

match ParseISO8601FormattedDateTime text cultureInfo with
| Some d -> new DateTimeOffset(d) |> Some
| _ -> None

我确实考虑过做一些类似xs:date转换所做的事情,即将Kind设置为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

对于asDateTimeOffset,这就是

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

这并没有在DateTimeOffset的DateTime内部设置Kind,但是DateTimeOffset被设计成:

定义了当前DateTimeOffset实例之间的差异日期、时间和协调世界时

偏移量对这些信息进行编码。

最新更新