Search code examples
f#type-providers

How to Parse Dates & Option Dates?


As I iterate over the rows returned by the CSVProvider there are instances where dates are either wrapped in options or unwrapped. Following is a sampling of the data:

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

I'd like to parse these dates and build records that have date strings (when a date is provided) and an empty string alternatively.

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

How can I achieve the above? I thought of and tried (see code below), building a custom type that aliased both wrapped and unwrapped DateTimes and then extracting/converting as needed.

Note: Code included below is non-functional:

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

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

Solution

  • The CSV provider attempts to infer the type of columns and infers them as dates or optional dates. In you case, it seems that you just want the string value as it is in the CSV file.

    You can get this easily by specifying the Schema in the CSV type provider and overriding the default behaviour for the date columns, so that it just gives you a string.

    Given the following CSV file saved as 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,
    

    You can get the data in the format you want using:

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