如何解析日期和期权日期?

How to Parse Dates & Option Dates?

当我遍历 CSVProvider 返回的行时,有些情况下日期要么包含在选项中,要么未包含在选项中。以下是数据样本:

+======+==============+============+===============+
| Site | Order Number | Order Date | Delivery Date |
+======+==============+============+===============+
| xyz  |          100 | 12/14/2019 | 3/16/2020     |
+------+--------------+------------+---------------+
| xyz  |          101 | 12/14/2019 | 3/16/2020     |
+------+--------------+------------+---------------+
| xyz  |          102 | 12/14/2019 | 3/16/2020     |
+------+--------------+------------+---------------+
| xyz  |          103 | 3/25/2020  |               |
+------+--------------+------------+---------------+
| xyz  |          104 | 3/26/2020  |               |
+------+--------------+------------+---------------+
| xyz  |          105 | 3/31/2020  | 4/5/2020      |
+------+--------------+------------+---------------+
| xyz  |          106 | 4/4/2020   |               |
+------+--------------+------------+---------------+
| xyz  |          107 | 4/10/2020  |               |
+------+--------------+------------+---------------+
| xyz  |          108 | 4/12/2020  |               |
+------+--------------+------------+---------------+

我想解析这些日期并构建包含日期字符串(当提供日期时)和空字符串的记录。

type example = { orderNumber: int; orderDate: string; deliveryDate: string }

如何实现以上目标?我想到并尝试了(见下面的代码),构建了一个自定义类型,该类型为包装和未包装的 DateTimes 加上别名,然后根据需要 extracting/converting。

注意:下面包含的代码无效:

type DateTimeOption<DateTime> =
    | Some of DateTime
    | DateTime
    | None

let parseDate (date: DateTimeOption) =
    match date with
    | Some d -> d.ToString()
    | None -> ""
    | d: DateTime -> d.ToString()

通常,这采用解包的形式 - 从放大类型中提取内部值。

unwrap: (T | A<T>) -> T

我们没有任何多态约束可以让我们将类型表达为 DateTime | DateTime option,所以我们只需要使用对象。

let rec dateUnwrap (opt: obj) = 
    match opt with
    | :? DateTime as dt -> string dt
    | :? Option<DateTime> as opt -> 
        opt |> Option.map(dateUnwrap) |> Option.defaultValue ""
    | _ -> ""

测试

let now = DateTime.Now
assert ((dateUnwrap (Some now)) = string now)
assert ((dateUnwrap now) = string now)
assert ((dateUnwrap None) = "")

P.S.

如果您没有好的模式或示例,类型提供程序推断可能会很脆弱。

CsvProvider 有选项 - InferRows。这是提供程序为了构建模式而扫描的行数 - 它的默认值恰好是 1000。

如果您想使用样本的所有可用行:

type OrderProvider = CsvProvider<uri, InferRows = 0>

CSV 提供程序尝试推断列的类型并将它们推断为日期或可选日期。在您的情况下,您似乎只需要 CSV 文件中的字符串值。

您可以通过在 CSV 类型提供程序中指定 Schema 并覆盖日期列的默认行为来轻松实现这一点,这样它只会为您提供一个字符串。

鉴于以下 CSV 文件另存为 C:/temp/b.csv:

Site,OrderNumber,OrderDate,DeliveryDate
xyz,100,12/14/2019,3/16/2020
xyz,103,3/25/2020,
xyz,104,3/26/2020,
xyz,105,3/31/2020,4/5/2020
xyz,106,4/4/2020,

您可以使用您想要的格式获取数据:

type B = CsvProvider<"c:/temp/b.csv",Schema=",,string,string">

type example =
  { orderNumber: int; orderDate: string; deliveryDate: string }

[ for r in B.GetSample().Rows ->
    { orderNumber = r.OrderNumber; 
      orderDate = r.OrderDate; 
      deliveryDate = r.DeliveryDate } ]