在F#中将字符串转换为System.DateTime

Ram*_*amy 8 f# date

如果我从命令行获取一个字符串,它看起来像这样:

'1-1-2011'
Run Code Online (Sandbox Code Playgroud)

如何将该字符串转换为F#中的DateTime对象?

Ste*_*sen 22

根据您的具体需要,.NET的日期时间类有字符串转换为一些静态方法DateTime的情况下,这些都是DateTime.Parse,DateTime.ParseExactDateTime.TryParse他们几个重载.

@ 7sharp9演示了执行日期解析的最基本方法,直接调用方法DateTime.Parse.但是,F#中的事情变得有趣DateTime.TryParse.而DateTime.Parse如果解析失败会抛出异常,最简单的过载DateTime.TryParse有签名string * byref<DateTime> -> bool,这将返回解析是否成功设置byref,如果真参数解析日期,或将它的默认值(null在这种情况下),否则.但是,在F#中使用它的语法很麻烦(事实上它并不适合任何.NET语言),因此F#语言设计了一个特殊的功能,允许像@Thomas Petricek指出的那样更好的调用约定.出.

但即使是F#(bool,result)返回类型模式也不理想.大多数情况下,如果解析失败,则不需要默认值.一个更好的签名DateTime.TryParse将是string -> option<DateTime>.幸运的是,我们可以随意扩展DateTime:

type System.DateTime with 
    static member TryParseOption str =
        match DateTime.TryParse str with
        | true, r -> Some(r)
        | _ -> None
Run Code Online (Sandbox Code Playgroud)

我们使用上面的扩展名如下:

match System.DateTime.TryParseOption "11/11/11" with 
| Some r -> stdout.WriteLine r
| None -> stdout.WriteLine "none"
Run Code Online (Sandbox Code Playgroud)

这与F#约定更为一致(List.tryFind例如).但即使这样也可以"变得更好".注意我们如何匹配try解析的结果.使用部分活动模式(当然!),我们可以包装整个类的try parses并将匹配移动到匹配大小写以获得更大的灵活性.请采取以下措施

open System
let (|DateTime|_|) str =
    match DateTime.TryParse str with
    | true, dt -> Some(dt)
    | _ -> None

let (|Int|_|) str =
    match Int32.TryParse str with
    | true, num -> Some(num)
    | _ -> None

let (|Float|_|) str =
    match Double.TryParse str with
    | true, num -> Some(num)
    | _ -> None
Run Code Online (Sandbox Code Playgroud)

使用这些,我们可以编写一个简洁的小控制台应用程序:

let rec loop() =
    stdout.WriteLine "
Please select an option:
    1) Parse something
    2) Exit
"
    match stdin.ReadLine() with
    | Int 1 -> 
        stdout.WriteLine "Enter something to parse: "
        match stdin.ReadLine() with
        | Int num -> stdout.WriteLine("Successfully parsed int: {0}", num)
        | Float num -> stdout.WriteLine("Successfully parsed float: {0}", num)
        | DateTime dt -> stdout.WriteLine("Successfully parsed DateTime: {0}", dt)
        | _ -> stdout.WriteLine "Parse Failed!"
        loop()
    | Int 2 -> 
        stdout.WriteLine "Now exiting"
    | _ -> 
        stdout.WriteLine "Invalid option, please try again"
        loop()
Run Code Online (Sandbox Code Playgroud)

要注意的关键是嵌套的匹配项,其中Int,Float,DateTime执行同样的匹配表达式内的尝试解析.

这些活动模式还有其他简洁的应用,例如,我们可以简洁地同时过滤和映射日期字符串列表

> ["11/23/2003"; "not a date"; "1/1/23 23:23pm"] |> Seq.choose(|DateTime|_|);;
val it : seq<DateTime> =
  seq
    [11/23/2003 12:00:00 AM {Date = 11/23/2003 12:00:00 AM;
                             Day = 23;
                             DayOfWeek = Sunday;
                             DayOfYear = 327;
                             Hour = 0;
                             Kind = Unspecified;
                             Millisecond = 0;
                             Minute = 0;
                             Month = 11;
                             Second = 0;
                             Ticks = 632051424000000000L;
                             TimeOfDay = 00:00:00;
                             Year = 2003;};
     1/1/2023 11:23:00 PM {Date = 1/1/2023 12:00:00 AM;
                           Day = 1;
                           DayOfWeek = Sunday;
                           DayOfYear = 1;
                           Hour = 23;
                           Kind = Unspecified;
                           Millisecond = 0;
                           Minute = 23;
                           Month = 1;
                           Second = 0;
                           Ticks = 638082121800000000L;
                           TimeOfDay = 23:23:00;
                           Year = 2023;}]
Run Code Online (Sandbox Code Playgroud)


7sh*_*rp9 11

你可以像这样简单地做到:

let dateTime = System.DateTime.Parse "1-1-2011"
Run Code Online (Sandbox Code Playgroud)


Tom*_*cek 11

要为7sharp9写的内容添加一个好东西,如果你还想处理失败,你可以写:

match System.DateTime.TryParse "1-1-2011" with
| true, date -> printfn "Success: %A" date
| false, _ -> printfn "Failed!"
Run Code Online (Sandbox Code Playgroud)

这并不明显,因为该TryParse方法有一个byref<DateTime>作为最后一个参数(并且它out在C#中使用),但F#允许您像这样调用方法.