Skip to content

DateTime.ParseExact breaks REPL #2003

Description

@forki
open System
open System.Globalization

let date = DateTime.ParseExact("21.10.2020", "dd.MM.yyyy", CultureInfo.InvariantCulture)

printfn "Date %O" date

Activity

  1. ncave commented on Mar 25, 2020

    @ncave
    Collaborator

    DateTime.ParseExact is not implemented at the moment.
    We should add a compiler error for it, or it should be implemented.

  2. travis-leith commented on Aug 27, 2020

    @travis-leith

    Typically my need for using DateTime.PaseExact is because I want to parse a string to a date using some specific date format, and I am guessing the same is true for most other people.
    Presently, I want to parse a string in "dd/MM/yyyy" format, on the client side.
    I am hoping this can be done using DateTime.TryParse and providing a custom implementation of IFormatProvider.

    However, the example I linked to is (to me anyway) a mess of OOP inheritance and stuff which I can't currently understand.
    The interface defines as single method called GetFormat(type) but I can't figure out if the type I need to cater for is DateTime or (as in the example) ICustomFormatter.

    Anyway, I think an example of how to do this (if indeed it is possible) would be a good thing for the documentation so that it becomes a widely known work around. Anyone know how to do this?

  3. Zaid-Ajaj commented on Aug 27, 2020

    @Zaid-Ajaj
    Member

    @travis-leith The Elmish Book has a section on Parsing Date Segments where if you ignore the parts related to the router, you can parse like this

    [<RequireQualifiesAccess>]
    module Date
    
    open System
    
    let (|Between|_|) (x: int) (y: int) (input: int) =
        if input >= x && input <= y
        then Some()
        else None
    
    let isLeapYear (year: int) = DateTime.IsLeapYear(year)
    
    type DateParts = { day: int; month: int; year: int }
    
    let buildDate (parts: DateParts) : Option<DateTime> =
      let day, month, year = parts.day, parts.month, parts.year
      if year <= 0 then
          None
      else
        match month, day with
        | 2, Between 1 29 when isLeapYear year -> Some (DateTime(year, month, day))
        | 2, Between 1 28 when not (isLeapYear year) -> Some (DateTime(year, month, day))
        | (1 | 3 | 5 | 7 | 8 | 10 | 12), Between 1 31 -> Some (DateTime(year, month, day))
        | (4 | 6 | 9 | 11), Between 1 30 -> Some (DateTime(year, month, day))
        | _ -> None
    
    let (|Int|_|) (number: string) = 
      match Int32.TryParse number with 
      | (true, value) -> Some value
      | _ -> None
    
    let parse (date: string) : Option<DateTime> = 
      match date.Split '/' with
      | [| Int day; Int month; Int year |] -> buildDate { day = day; month = month; year = year }
      | _ -> None

    Then you can the module like this

    match Date.parse inputDate with 
    | Some parsedDate -> (* do stuff *)
    | None -> (* invalid *)

    Notice the function parse will split the input date string on / but you can change that to whatever you like and in read the parts in the order you want

  4. travis-leith commented on Aug 28, 2020

    @travis-leith

    @Zaid-Ajaj this works well, thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions